Files
EgtMachKernel/SurfFinishing.cpp
T
Dario Sassi b74f0d407d EgtMachKernel 2.7a3 :
- aggiunta a PostProc la chiamata a OnTableAxisData e a Estimator la chiamata a OnEstimTableAxisData per ogni asse di tavola su quella corrente
- modifiche varie a Machine per rendere possibile la modifica precedente
- piccolo aggiustamento a inizializzazione di dZConstOverlap.
2025-01-28 19:45:11 +01:00

4711 lines
196 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2019-2019
//----------------------------------------------------------------------------
// File : SurfFinishing.cpp Data : 28.05.19 Versione : 2.1e5
// Contenuto : Implementazione gestione finitura superfici.
//
//
//
// Modifiche : 28.05.19 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "MachMgr.h"
#include "DllMain.h"
#include "SurfFinishing.h"
#include "OperationConst.h"
#include "GeoConst.h"
#include "/EgtDev/Include/EXeCmdLogOff.h"
#include "/EgtDev/Include/EXeConst.h"
#include "/EgtDev/Include/EGkCurveLine.h"
#include "/EgtDev/Include/EGkCurveArc.h"
#include "/EgtDev/Include/EGkCurveComposite.h"
#include "/EgtDev/Include/EGkArcSpecial.h"
#include "/EgtDev/Include/EGkChainCurves.h"
#include "/EgtDev/Include/EGkOffsetCurve.h"
#include "/EgtDev/Include/EGkIntersCurves.h"
#include "/EgtDev/Include/EGkSfrCreate.h"
#include "/EgtDev/Include/EGkSurfLocal.h"
#include "/EgtDev/Include/EGkCAvToolSurfTm.h"
#include "/EgtDev/Include/EGkCAvSilhouetteSurfTm.h"
#include "/EgtDev/Include/EGkCalcPocketing.h"
#include "/EgtDev/Include/EGkIntervals.h"
#include "/EgtDev/Include/EGkStringUtils3d.h"
#include "/EgtDev/Include/EGkUserObjFactory.h"
#include "/EgtDev/Include/EGnStringKeyVal.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
#include "/EgtDev/Include/EGkCurveAux.h"
#include "/EgtDev/Include/EGkDistPointCurve.h"
#include "/EgtDev/Include/EGkDistPointSurfFr.h"
#include "/EgtDev/Include/EGkStmFromTriangleSoup.h"
#include <thread>
#include <future>
// per far dimenticare macro di WinUser.h
#undef GetClassName
using namespace std ;
//------------------------------ Errors --------------------------------------
// 3101 = "Error in SurfFinishing : UpdateToolData failed"
// 3102 = "Error in SurfFinishing : Tool loading failed"
// 3103 = "Error in SurfFinishing : Chaining failed"
// 3104 = "Error in SurfFinishing : Open Contour"
// 3105 = "Error in SurfFinishing : Contour Not Flat"
// 3106 = "Error in SurfFinishing : Tool Dir not perpendicular to Flat Area"
// 3107 = "Error in SurfFinishing : Empty RawBox"
// 3108 = "Error in SurfFinishing : Depth not computable"
// 3109 = "Error in SurfFinishing : Offset not computable"
// 3110 = "Error in SurfFinishing : Toolpath not computable"
// 3111 = "Error in SurfFinishing : Approach not computable"
// 3112 = "Error in SurfFinishing : Link not computable"
// 3113 = "Error in SurfFinishing : LeadIn not computable"
// 3114 = "Error in SurfFinishing : LeadOut not computable"
// 3115 = "Error in SurfFinishing : Retract not computable"
// 3116 = "Error in SurfFinishing : axes values not calculable"
// 3117 = "Error in SurfFinishing : outstroke xx"
// 3118 = "Error in SurfFinishing : link movements not calculable"
// 3119 = "Error in SurfFinishing : link outstroke"
// 3120 = "Error in SurfFinishing : post apply not calculable"
// 3121 = "Error in SurfFinishing : Linear Approx not computable"
// 3122 = "Error in SurfFinishing : aggregate from bottom not allowed"
// 3123 = "Error in SurfFinishing : missing surfaces"
// 3124 = "Error in SurfFinishing : region not computable"
// 3125 = "Error in SurfFinishing : CalcPocketing failed"
// 3126 = "Error in SurfFinishing : Computing ZConst Curves failed"
// 3127 = "Error in SurfFinishing : Computing ZConst Paths failed"
// 3128 = "Error in SurfFinishing : Curves with different extrusion"
// 3151 = "Warning in SurfFinishing : Skipped entity (xx)"
// 3152 = "Warning in SurfFinishing : No machinable path"
// 3153 = "Warning in SurfFinishing : Tool name changed (xx)"
// 3154 = "Warning in SurfFinishing : Tool data changed (xx)"
//----------------------------------------------------------------------------
static string KEY_THICK = "THICK" ;
const double SILH_SAMPLING = 1. ;
#define ENABLE_ZCONST_DEBUG 0
#define ENABLE_OPTIMAL_DEBUG 0
//----------------------------------------------------------------------------
USEROBJ_REGISTER( GetOperationClass( OPER_SURFFINISHING), SurfFinishing) ;
//----------------------------------------------------------------------------
const string&
SurfFinishing::GetClassName( void) const
{
return USEROBJ_GETNAME( SurfFinishing) ;
}
//----------------------------------------------------------------------------
SurfFinishing*
SurfFinishing::Clone( void) const
{
// alloco oggetto
SurfFinishing* pSrF = new(nothrow) SurfFinishing ;
// eseguo copia dei dati
if ( pSrF != nullptr) {
try {
pSrF->m_vId = m_vId ;
pSrF->m_pMchMgr = m_pMchMgr ;
pSrF->m_nPhase = m_nPhase ;
pSrF->m_Params = m_Params ;
pSrF->m_TParams = m_TParams ;
pSrF->m_dTHoldBase = m_dTHoldBase ;
pSrF->m_dTHoldLen = m_dTHoldLen ;
pSrF->m_dTHoldDiam = m_dTHoldDiam ;
pSrF->m_nStatus = m_nStatus ;
pSrF->m_nPaths = m_nPaths ;
}
catch( ...) {
delete pSrF ;
return nullptr ;
}
}
// ritorno l'oggetto
return pSrF ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::Dump( string& sOut, bool bMM, const char* szNewLine) const
{
sOut += GetClassName() + "[mm]" + szNewLine ;
sOut += KEY_PHASE + EQUAL + ToString( m_nPhase) + szNewLine ;
sOut += KEY_IDS + EQUAL + ToString( m_vId) + szNewLine ;
for ( int i = 0 ; i < m_Params.GetSize() ; ++ i)
sOut += m_Params.ToString( i) + szNewLine ;
for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i)
sOut += m_TParams.ToString( i) + szNewLine ;
sOut += KEY_NUM + EQUAL + ToString( m_nPaths) + szNewLine ;
sOut += KEY_STAT + EQUAL + ToString( m_nStatus) + szNewLine ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::Save( int nBaseId, STRVECTOR& vString) const
{
try {
int nSize = 1 + m_Params.GetSize() + m_TParams.GetSize() + 3 ;
vString.insert( vString.begin(), nSize, "") ;
int k = - 1 ;
if ( ! SetVal( KEY_IDS, m_vId, vString[++k]))
return false ;
for ( int i = 0 ; i < m_Params.GetSize() ; ++ i)
vString[++k] = m_Params.ToString( i) ;
for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i)
vString[++k] = m_TParams.ToString( i) ;
if ( ! SetVal( KEY_PHASE, m_nPhase, vString[++k]))
return false ;
if ( ! SetVal( KEY_NUM, m_nPaths, vString[++k]))
return false ;
if ( ! SetVal( KEY_STAT, m_nStatus, vString[++k]))
return false ;
}
catch( ...) {
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::Load( const STRVECTOR& vString, int nBaseGdbId)
{
int nSize = int( vString.size()) ;
// lista identificativi geometrie da lavorare
int k = - 1 ;
if ( k >= nSize - 1 || ! GetVal( vString[++k], KEY_IDS, m_vId))
return false ;
for ( auto& Sel : m_vId)
Sel.nId += nBaseGdbId ;
// parametri lavorazione
for ( int i = 0 ; i < m_Params.GetSize() ; ++ i) {
int nKey ;
if ( k >= nSize - 1 || ! m_Params.FromString( vString[++k], nKey) || nKey != i) {
if ( m_Params.IsOptional( i))
-- k ;
else
return false ;
}
}
// parametri utensile
for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i) {
int nKey ;
if ( k >= nSize - 1 || ! m_TParams.FromString( vString[++k], nKey) || nKey != i)
return false ;
}
// parametri di stato
while ( k < nSize - 1) {
// separo chiave da valore
string sKey, sVal ;
SplitFirst( vString[++k], "=", sKey, sVal) ;
// leggo
if ( sKey == KEY_PHASE) {
if ( ! FromString( sVal, m_nPhase))
return false ;
}
else if ( sKey == KEY_NUM) {
if ( ! FromString( sVal, m_nPaths))
return false ;
}
else if ( sKey == KEY_STAT) {
if ( ! FromString( sVal, m_nStatus))
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
SurfFinishing::SurfFinishing( void)
{
m_Params.m_sName = "*" ;
m_Params.m_sToolName = "*" ;
m_TParams.m_sName = "*" ;
m_TParams.m_sHead = "*" ;
m_dTHoldBase = 0 ;
m_dTHoldLen = 0 ;
m_dTHoldDiam = 0 ;
m_nStatus = MCH_ST_TO_VERIFY ;
m_nPaths = 0 ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::Prepare( const string& sSawName)
{
// verifico il gestore lavorazioni
if ( m_pMchMgr == nullptr)
return false ;
// recupero il gestore DB utensili della macchina corrente
ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ;
if ( pTMgr == nullptr)
return false ;
// recupero il gestore DB lavorazioni della macchina corrente
MachiningsMgr* pMMgr = m_pMchMgr->GetCurrMachiningsMgr() ;
if ( pMMgr == nullptr)
return false ;
// ricerca della lavorazione di libreria con il nome indicato
const SurfFinishingData* pDdata = GetSurfFinishingData( pMMgr->GetMachining( sSawName)) ;
if ( pDdata == nullptr)
return false ;
m_Params = *pDdata ;
// ricerca dell'utensile usato dalla lavorazione
const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ;
if ( pTdata == nullptr)
return false ;
m_TParams = *pTdata ;
m_Params.m_sToolName = m_TParams.m_sName ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::SetParam( int nType, bool bVal)
{
switch ( nType) {
case MPA_INVERT :
if ( bVal != m_Params.m_bInvert)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_bInvert = bVal ;
return true ;
}
return false ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::SetParam( int nType, int nVal)
{
switch ( nType) {
case MPA_SUBTYPE :
if ( ! m_Params.VerifySubType( nVal))
return false ;
if ( nVal != m_Params.m_nSubType)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_nSubType = nVal ;
return true ;
case MPA_LEADINTYPE :
if ( ! m_Params.VerifyLeadInType( nVal))
return false ;
if ( nVal != m_Params.m_nLeadInType)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_nLeadInType = nVal ;
return true ;
case MPA_LEADOUTTYPE :
if ( ! m_Params.VerifyLeadOutType( nVal))
return false ;
if ( nVal != m_Params.m_nLeadOutType)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_nLeadOutType = nVal ;
return true ;
case MPA_SCC :
if ( ! m_Params.VerifySolCh( nVal))
return false ;
if ( nVal != m_Params.m_nSolCh)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_nSolCh = nVal ;
return true ;
}
return false ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::SetParam( int nType, double dVal)
{
switch ( nType) {
case MPA_SPEED :
if ( ! m_TParams.VerifySpeed( dVal))
return false ;
if ( AreSameAngValue( dVal, m_TParams.m_dSpeed))
dVal = 0 ;
m_Params.m_dSpeed = dVal ;
return true ;
case MPA_FEED :
if ( AreSameLenValue( dVal, m_TParams.m_dFeed))
dVal = 0 ;
if ( ! AreSameLenValue( dVal, m_Params.m_dFeed))
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dFeed = dVal ;
return true ;
case MPA_STARTFEED :
if ( AreSameLenValue( dVal, m_TParams.m_dStartFeed))
dVal = 0 ;
if ( ! AreSameLenValue( dVal, m_Params.m_dStartFeed))
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dStartFeed = dVal ;
return true ;
case MPA_ENDFEED :
if ( AreSameLenValue( dVal, m_TParams.m_dEndFeed))
dVal = 0 ;
if ( ! AreSameLenValue( dVal, m_Params.m_dEndFeed))
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dEndFeed = dVal ;
return true ;
case MPA_TIPFEED :
if ( AreSameLenValue( dVal, m_TParams.m_dTipFeed))
dVal = 0 ;
if ( ! AreSameLenValue( dVal, m_Params.m_dTipFeed))
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dTipFeed = dVal ;
return true ;
case MPA_OFFSR :
if ( AreSameLenValue( dVal, m_TParams.m_dOffsR))
dVal = UNKNOWN_PAR ;
if ( ! AreSameLenValue( dVal, m_Params.m_dOffsR))
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dOffsR = dVal ;
return true ;
case MPA_DEPTH: {
string sVal = ToString( dVal) ;
if ( sVal != m_Params.m_sDepth)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_sDepth = sVal ;
} return true ;
case MPA_STARTPOS :
if ( ! AreSameLenValue( dVal, m_Params.m_dStartPos))
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dStartPos = dVal ;
return true ;
case MPA_OVERL :
if ( ! AreSameLenValue( dVal, m_Params.m_dOverlap))
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dOverlap = dVal ;
return true ;
case MPA_SIDESTEP :
if ( ! AreSameLenValue( dVal, m_Params.m_dSideStep))
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dSideStep = dVal ;
return true ;
case MPA_SIDEANGLE :
if ( abs( dVal - m_Params.m_dSideAngle) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dSideAngle = dVal ;
return true ;
case MPA_LITANG :
if ( abs( dVal - m_Params.m_dLiTang) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dLiTang = dVal ;
return true ;
case MPA_LIPERP :
if ( abs( dVal - m_Params.m_dLiPerp) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dLiPerp = dVal ;
return true ;
case MPA_LOTANG :
if ( abs( dVal - m_Params.m_dLoTang) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dLoTang = dVal ;
return true ;
case MPA_LOPERP :
if ( abs( dVal - m_Params.m_dLoPerp) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dLoPerp = dVal ;
return true ;
case MPA_APPROX :
if ( abs( dVal - m_Params.m_dApprox) > EPS_SMALL)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dApprox = dVal ;
return true ;
}
return false ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::SetParam( int nType, const string& sVal)
{
switch ( nType) {
case MPA_TOOL : {
const ToolData* pTdata ;
if ( ! m_Params.VerifyTool( m_pMchMgr->GetCurrToolsMgr(), sVal, pTdata))
return false ;
if ( ! SameTool( m_TParams, *pTdata))
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_sToolName = sVal ;
m_Params.m_ToolUuid = pTdata->m_Uuid ;
m_TParams = *pTdata ;
} return true ;
case MPA_DEPTH_STR :
if ( sVal != m_Params.m_sDepth)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_sDepth = sVal ;
return true ;
case MPA_SYSNOTES :
if ( sVal != m_Params.m_sSysNotes)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_sSysNotes = sVal ;
return true ;
case MPA_USERNOTES :
if ( sVal != m_Params.m_sUserNotes)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_sUserNotes = sVal ;
return true ;
case MPA_INITANGS :
if ( sVal != m_Params.m_sInitAngs)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_sInitAngs = sVal ;
return true ;
case MPA_BLOCKEDAXIS :
if ( sVal != m_Params.m_sBlockedAxis)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_sBlockedAxis = sVal ;
return true ;
}
return false ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::SetGeometry( const SELVECTOR& vIds)
{
// verifico validità gestore DB geometrico
if ( m_pGeomDB == nullptr)
return false ;
// reset della geometria corrente
m_vId.clear() ;
// verifico che gli identificativi rappresentino delle entità ammissibili
for ( const auto& Id : vIds) {
// test sull'entità
int nSubs ;
if ( ! VerifyGeometry( Id, nSubs)) {
string sInfo = "Warning in SurfFinishing : Skipped entity " + ToString( Id) ;
m_pMchMgr->SetWarning( 3151, sInfo) ;
continue ;
}
// posso aggiungere alla lista
m_vId.emplace_back( Id) ;
}
// aggiorno lo stato
m_nStatus |= MCH_ST_GEO_MODIF ;
// restituisco presenza geometria da lavorare
return ( ! m_vId.empty()) ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::Preview( bool bRecalc)
{
// non esiste preview, si fa apply
return Apply( bRecalc, false) ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::Apply( bool bRecalc, bool bPostApply)
{
// reset numero tagli nella lavorazione
int nCurrPaths = m_nPaths ;
m_nPaths = 0 ;
// verifico validità gestore DB geometrico e Id del gruppo
if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId))
return false ;
// aggiorno dati geometrici dell'utensile
bool bToolChanged = true ;
if ( ! UpdateToolData( &bToolChanged)) {
m_pMchMgr->SetLastError( 3101, "Error in SurfFinishing : UpdateToolData failed") ;
return false ;
}
// non è prevista finitura superficie con aggregato da sotto
if ( IsAggrBottom( m_TParams.m_sHead)) {
m_pMchMgr->SetLastError( 3122, "Error in SurfFinishing : aggregate from bottom not allowed") ;
return false ;
}
// verifico se necessario continuare nell'aggiornamento
if ( ! bRecalc && ! bToolChanged &&
( m_nStatus == MCH_ST_OK || m_nStatus == MCH_ST_NO_POSTAPPL)) {
// confermo i percorsi di lavorazione
m_nPaths = nCurrPaths ;
string sLog = string( "SurfFinishing apply skipped : status ") + ( m_nStatus == MCH_ST_OK ? "already ok" : "no postapply") ;
LOG_DBG_INFO( GetEMkLogger(), sLog.c_str()) ;
// eseguo aggiornamento assi macchina e collegamento con operazione precedente
if ( ! Update( bPostApply))
return false ;
m_nStatus = ( bPostApply ? MCH_ST_OK : MCH_ST_NO_POSTAPPL) ;
LOG_DBG_INFO( GetEMkLogger(), "Update done") ;
// esco con successo
return true ;
}
m_nStatus = MCH_ST_TO_VERIFY ;
// recupero gruppo per geometria ausiliaria
int nAuxId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_AUX) ;
bool bChain = false ;
// se non c'è, lo aggiungo
if ( nAuxId == GDB_ID_NULL) {
nAuxId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ;
if ( nAuxId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nAuxId, MCH_AUX) ;
m_pGeomDB->SetStatus( nAuxId, GDB_ST_OFF) ;
bChain = true ;
}
// altrimenti, se chiesto ricalcolo, lo svuoto
else if ( bRecalc) {
m_pGeomDB->EmptyGroup( nAuxId) ;
bChain = true ;
}
// rendo corrente l'utensile usato nella lavorazione
if ( ! m_pMchMgr->SetCalcTool( m_TParams.m_sName, m_TParams.m_sHead, m_TParams.m_nExit)) {
m_pMchMgr->SetLastError( 3102, "Error in SurfFinishing : Tool loading failed") ;
return false ;
}
// recupero i dati del portautensile
int nToolId = m_pMchMgr->GetCalcTool() ;
m_dTHoldBase = 0 ;
m_pGeomDB->GetInfo( nToolId, TTH_BASE, m_dTHoldBase) ;
m_dTHoldLen = 0 ;
m_pGeomDB->GetInfo( nToolId, TTH_LEN, m_dTHoldLen) ;
m_dTHoldDiam = 0 ;
m_pGeomDB->GetInfo( nToolId, TTH_DIAM, m_dTHoldDiam) ;
// se necessario, eseguo concatenamento ed inserisco i percorsi sotto la geometria ausiliaria
if ( bChain && ! Chain( nAuxId)) {
m_pMchMgr->SetLastError( 3103, "Error in SurfFinishing : Chaining failed") ;
return false ;
}
// recupero gruppo per geometria di lavorazione (Cutter Location)
int nClId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_CL) ;
// se non c'è, lo aggiungo
if ( nClId == GDB_ID_NULL) {
nClId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ;
if ( nClId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nClId, MCH_CL) ;
}
// altrimenti lo svuoto
else
m_pGeomDB->EmptyGroup( nClId) ;
// lavoro ogni singola regione piana
if ( m_Params.m_nSubType == SURFFIN_SUB_ZIGZAG || m_Params.m_nSubType == SURFFIN_SUB_ONEWAY ||
m_Params.m_nSubType == SURFFIN_SUB_SPIRALIN || m_Params.m_nSubType == SURFFIN_SUB_SPIRALOUT ||
m_Params.m_nSubType == SURFFIN_SUB_Z_CONST || m_Params.m_nSubType == SURFFIN_SUB_OPTIMAL) {
bool bOk = true ;
int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ;
while ( nPathId != GDB_ID_NULL) {
if ( ! ProcessSfr( nPathId, GDB_ID_NULL, nClId))
bOk = false ;
nPathId = m_pGeomDB->GetNextGroup( nPathId) ;
}
if ( ! bOk)
return false ;
}
// lavoro ogni singola curva composita
else if ( m_Params.m_nSubType == SURFFIN_SUB_PROJECT) {
bool bOk = true ;
int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ;
while ( nPathId != GDB_ID_NULL) {
if ( ! ProcessCrvCompo( nPathId, GDB_ID_NULL, nClId))
bOk = false ;
nPathId = m_pGeomDB->GetNextGroup( nPathId) ;
}
if ( ! bOk)
return false ;
}
else
return false ;
// assegno ingombri dei vari percorsi di lavorazione e della lavorazione nel suo complesso
CalcAndSetBBox( nClId) ;
// eseguo aggiornamento assi macchina e collegamento con operazione precedente
if ( ! Update( bPostApply))
return false ;
// aggiorno stato della lavorazione
m_nStatus = ( bPostApply ? MCH_ST_OK : MCH_ST_NO_POSTAPPL) ;
// dichiaro successiva da aggiornare
UpdateFollowingOperationsStatus( MCH_ST_OTH_MODIF) ;
LOG_DBG_INFO( GetEMkLogger(), "SurfFinishing apply done") ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::Update( bool bPostApply)
{
// verifico validità gestore DB geometrico e Id del gruppo
if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId))
return false ;
// se lavorazione vuota, esco
if ( m_nPaths == 0) {
m_pMchMgr->SetWarning( 3152, "Warning in SurfFinishing : No machinable path") ;
return true ;
}
// elimino le entità CLIMB, RISE e HOME della lavorazione, potrebbero falsare i calcoli degli assi (in ogni casi vengono riaggiunte dopo)
RemoveClimbRiseHome() ;
// imposto eventuale asse bloccato da lavorazione
SetBlockedRotAxis( m_Params.m_sBlockedAxis) ;
// calcolo gli assi macchina
string sHint = ExtractHint( m_Params.m_sUserNotes) ;
if ( ! m_Params.m_sInitAngs.empty())
sHint = m_Params.m_sInitAngs ;
if ( ! CalculateAxesValues( sHint)) {
string sInfo = m_pMchMgr->GetOutstrokeInfo() ;
if ( sInfo.empty())
m_pMchMgr->SetLastError( 3116, "Error in SurfFinishing : axes values not calculable") ;
else
m_pMchMgr->SetLastError( 3117, "Error in SurfFinishing : outstroke ") ;
return false ;
}
// gestione movimenti all'inizio di ogni singolo percorso di lavorazione e alla fine della lavorazione
if ( ! AdjustStartEndMovements()) {
string sInfo = m_pMchMgr->GetOutstrokeInfo() ;
if ( sInfo.empty())
m_pMchMgr->SetLastError( 3118, "Error in SurfFinishing : link movements not calculable") ;
else
m_pMchMgr->SetLastError( 3119, "Error in SurfFinishing : link outstroke ") ;
return false ;
}
// assegno estremi degli assi dei vari percorsi di lavorazione e della lavorazione nel suo complesso
CalcAndSetAxesBBox() ;
// esecuzione eventuali personalizzazioni
string sErr ;
if ( bPostApply && ! PostApply( sErr)) {
if ( ! IsEmptyOrSpaces( sErr))
m_pMchMgr->SetLastError( 3120, sErr) ;
else
m_pMchMgr->SetLastError( 3120, "Error in SurfFinishing : post apply not calculable") ;
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::GetParam( int nType, bool& bVal) const
{
switch ( nType) {
case MPA_INVERT :
bVal = m_Params.m_bInvert ;
return true ;
}
bVal = false ;
return false ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::GetParam( int nType, int& nVal) const
{
switch ( nType) {
case MPA_TYPE :
nVal = MT_SURFFINISHING ;
return true ;
case MPA_SUBTYPE :
nVal = m_Params.m_nSubType ;
return true ;
case MPA_LEADINTYPE :
nVal = m_Params.m_nLeadInType ;
return true ;
case MPA_LEADOUTTYPE :
nVal = m_Params.m_nLeadOutType ;
return true ;
case MPA_SCC :
nVal = m_Params.m_nSolCh ;
return true ;
}
nVal = 0 ;
return false ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::GetParam( int nType, double& dVal) const
{
switch ( nType) {
case MPA_SPEED :
dVal = GetSpeed() ;
return true ;
case MPA_FEED :
dVal = GetFeed() ;
return true ;
case MPA_STARTFEED :
dVal = GetStartFeed() ;
return true ;
case MPA_ENDFEED :
dVal = GetEndFeed() ;
return true ;
case MPA_TIPFEED :
dVal = GetTipFeed() ;
return true ;
case MPA_OFFSR :
dVal =GetOffsR() ;
return true ;
case MPA_STARTPOS :
dVal = m_Params.m_dStartPos ;
return true ;
case MPA_OVERL :
dVal = m_Params.m_dOverlap ;
return true ;
case MPA_SIDESTEP :
dVal = m_Params.m_dSideStep ;
return true ;
case MPA_SIDEANGLE :
dVal = m_Params.m_dSideAngle ;
return true ;
case MPA_LITANG :
dVal = m_Params.m_dLiTang ;
return true ;
case MPA_LIPERP :
dVal = m_Params.m_dLiPerp ;
return true ;
case MPA_LOTANG :
dVal = m_Params.m_dLoTang ;
return true ;
case MPA_LOPERP :
dVal = m_Params.m_dLoPerp ;
return true ;
case MPA_APPROX :
dVal = m_Params.m_dApprox ;
return true ;
}
dVal = 0 ;
return false ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::GetParam( int nType, string& sVal) const
{
switch ( nType) {
case MPA_NAME :
sVal = m_Params.m_sName ;
return true ;
case MPA_TOOL :
sVal = m_Params.m_sToolName ;
return true ;
case MPA_DEPTH_STR :
sVal = m_Params.m_sDepth ;
return true ;
case MPA_TUUID :
sVal = ToString( m_Params.m_ToolUuid) ;
return true ;
case MPA_UUID :
sVal = ToString( m_Params.m_Uuid) ;
return true ;
case MPA_SYSNOTES :
sVal = m_Params.m_sSysNotes ;
return true ;
case MPA_USERNOTES :
sVal = m_Params.m_sUserNotes ;
return true ;
case MPA_INITANGS :
sVal = m_Params.m_sInitAngs ;
return true ;
case MPA_BLOCKEDAXIS :
sVal = m_Params.m_sBlockedAxis ;
return true ;
}
sVal = "" ;
return false ;
}
//----------------------------------------------------------------------------
const ToolData&
SurfFinishing::GetToolData( void) const
{
return m_TParams ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::UpdateToolData( bool* pbChanged)
{
// recupero il gestore DB utensili della macchina corrente
ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ;
if ( pTMgr == nullptr)
return false ;
// recupero l'utensile nel DB utensili (se fallisce con UUID provo con il nome)
const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ;
if ( pTdata == nullptr) {
pTdata = pTMgr->GetTool( m_Params.m_sToolName) ;
if ( pTdata == nullptr)
return false ;
m_Params.m_ToolUuid = m_TParams.m_Uuid ;
}
// salvo posizione TC, testa e uscita originali
string sOrigTcPos = m_TParams.m_sTcPos ;
string sOrigHead = m_TParams.m_sHead ;
int nOrigExit = m_TParams.m_nExit ;
// verifico se sono diversi (ad esclusione di nome, posizione TC, testa e uscita)
bool bChanged = ( ! SameTool( m_TParams, *pTdata, false)) ;
// aggiorno comunque i parametri
m_TParams = *pTdata ;
// se definito attrezzaggio, aggiorno i parametri che ne possono derivare
string sTcPos ; string sHead ; int nExit ;
if ( m_pMchMgr->GetCurrSetupMgr().GetToolData( m_TParams.m_sName, sTcPos, sHead, nExit)) {
if ( sOrigTcPos != sTcPos ||
sOrigHead != sHead ||
nOrigExit != nExit)
bChanged = true ;
m_TParams.m_sTcPos = sTcPos ;
m_TParams.m_sHead = sHead ;
m_TParams.m_nExit = nExit ;
}
else {
if ( sOrigTcPos != pTdata->m_sTcPos ||
sOrigHead != pTdata->m_sHead ||
nOrigExit != pTdata->m_nExit)
bChanged = true ;
}
// eventuali segnalazioni
if ( ! EqualNoCase( m_Params.m_sToolName, m_TParams.m_sName)) {
string sInfo = "Warning in SurfFinishing : tool name changed (" +
m_Params.m_sToolName + "->" + m_TParams.m_sName + ")" ;
m_pMchMgr->SetWarning( 3153, sInfo) ;
m_Params.m_sToolName = m_TParams.m_sName ;
}
if ( bChanged) {
string sInfo = "Warning in SurfFinishing : tool data changed (" +
m_Params.m_sToolName + ")" ;
m_pMchMgr->SetWarning( 3154, sInfo) ;
}
// se definito parametro di ritorno, lo assegno
if ( pbChanged != nullptr)
*pbChanged = bChanged ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::GetGeometry( SELVECTOR& vIds) const
{
// restituisco l'elenco delle entità
vIds = m_vId ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::AdjustEndPointForAxesCalc( const CamData* pCamData, Point3d& ptP) const
{
// compenso il raggio dell'utensile
ptP += pCamData->GetCorrDir() * ( m_TParams.m_dDiam / 2) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::VerifyGeometry( SelData Id, int& nSubs)
{
// ammessi : curve o superfici
const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ;
if ( pGObj == nullptr)
return false ;
// se curva
if ( ( pGObj->GetType() & GEO_CURVE) != 0) {
const ICurve* pCurve = nullptr ;
// se direttamente la curva
if ( Id.nSub == SEL_SUB_ALL) {
pCurve = ::GetCurve( pGObj) ;
if ( pCurve != nullptr) {
if ( pCurve->GetType() == CRV_COMPO)
nSubs = ::GetCurveComposite( pCurve)->GetCurveCount() ;
else
nSubs = 0 ;
}
}
// altrimenti sottocurva di composita
else {
const ICurveComposite* pCompo = GetCurveComposite( pGObj) ;
if ( pCompo != nullptr)
pCurve = pCompo->GetCurve( Id.nSub) ;
nSubs = 0 ;
}
return ( pCurve != nullptr) ;
}
// se altrimenti è superficie trimesh
else if ( pGObj->GetType() == SRF_TRIMESH) {
const ISurfTriMesh* pSurf = ::GetSurfTriMesh( pGObj) ;
return ( pSurf != nullptr && pSurf->GetFacetCount() >= 1) ;
}
// altrimenti errore
else
return false ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::GetCurves( SelData Id, ICURVEPLIST& lstPC)
{
// ammessi : curve
const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ;
if ( pGObj == nullptr)
return false ;
// ne recupero il riferimento globale
Frame3d frGlob ;
if ( ! m_pGeomDB->GetGlobFrame( Id.nId, frGlob))
return false ;
// se curva
if ( ( pGObj->GetType() & GEO_CURVE) != 0) {
PtrOwner<ICurve> pCurve ;
// se direttamente curva
if ( Id.nSub == SEL_SUB_ALL) {
// recupero la curva
const ICurve* pOriCurve = ::GetCurve( pGObj) ;
if ( pOriCurve == nullptr)
return false ;
// la duplico
pCurve.Set( pOriCurve->Clone()) ;
// se estrusione mancante, imposto default
Vector3d vtExtr ;
if ( ! pCurve->GetExtrusion( vtExtr) || vtExtr.IsSmall())
pCurve->SetExtrusion( Z_AX) ;
}
// altrimenti sottocurva di composita
else {
// recupero la composita
const ICurveComposite* pCompo = GetCurveComposite( pGObj) ;
if ( pCompo == nullptr)
return false ;
// recupero la curva semplice
const ICurve* pOriCurve = ::GetCurve( pCompo->GetCurve( Id.nSub)) ;
if ( pOriCurve == nullptr)
return false ;
// la duplico
pCurve.Set( pOriCurve->Clone()) ;
// recupero estrusione e spessore
Vector3d vtExtr ;
if ( ! pCompo->GetExtrusion( vtExtr) || vtExtr.IsSmall())
vtExtr = Z_AX ;
pCurve->SetExtrusion( vtExtr) ;
double dThick ;
if ( pCompo->GetThickness( dThick))
pCurve->SetThickness( dThick) ;
}
if ( IsNull( pCurve))
return false ;
// la porto in globale
pCurve->ToGlob( frGlob) ;
// la restituisco
lstPC.emplace_back( Release( pCurve)) ;
return true ;
}
// se altrimenti superficie
else if ( pGObj->GetType() == SRF_TRIMESH)
return true ;
// altrimenti errore
else
return false ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::Chain( int nGrpDestId)
{
// vettore puntatori alle curve
ICURVEPOVECTOR vpCrvs ;
vpCrvs.reserve( m_vId.size()) ;
// vettore selettori delle curve originali
SELVECTOR vInds ;
// recupero tutte le curve e le porto in globale
for ( const auto& Id : m_vId) {
// prendo le curve
ICURVEPLIST lstPC ;
if ( ! GetCurves( Id, lstPC)) {
string sInfo = "Warning in SurfFinishing : Skipped entity " + ToString( Id) ;
m_pMchMgr->SetWarning( 3151, sInfo) ;
}
for ( auto pCrv : lstPC) {
vpCrvs.emplace_back( pCrv) ;
vInds.emplace_back( Id) ;
}
}
// se finitura a proiezione di curve
if ( m_Params.m_nSubType == SURFFIN_SUB_PROJECT) {
int nGroupName = -1 ;
for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) {
// creo nuovo gruppo
int nPathId = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrpDestId, Frame3d()) ;
if ( nPathId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nPathId, MCH_PATH + ToString( ++ nGroupName)) ;
m_pGeomDB->SetInfo( nPathId, KEY_IDS, ToString( nGroupName)) ;
// definisco la curva composita associata
PtrOwner<ICurveComposite> pCrvCompo( ConvertCurveToComposite( Release( vpCrvs[i]))) ;
if ( IsNull( pCrvCompo) || ! pCrvCompo->IsValid())
return false ;
int nNewId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, ::CloneCurveComposite( pCrvCompo)) ;
if ( nNewId == GDB_ID_NULL)
return false ;
// memorizzo la Thickness e l'Estrusione nelle Info del gruppo
double dThick ; pCrvCompo->GetThickness( dThick) ;
Vector3d vtExtr ; pCrvCompo->GetExtrusion( vtExtr) ;
m_pGeomDB->SetInfo( nNewId, KEY_THICK, dThick) ;
m_pGeomDB->SetInfo( nNewId, KEY_EXTR, vtExtr) ;
}
return true ;
}
// preparo i dati per il concatenamento
Vector3d vtExtr = Z_AX ;
bool bFirst = true ;
Point3d ptNear = ORIG ;
double dToler = 10 * EPS_SMALL ;
ChainCurves chainC ;
chainC.Init( true, dToler, int( vpCrvs.size())) ;
for ( size_t i = 0 ; i < vpCrvs.size() ; ++ i) {
// recupero la curva e il suo riferimento
ICurve* pCrv = vpCrvs[i] ;
if ( pCrv == nullptr)
continue ;
// recupero i dati della curva necessari al concatenamento e li assegno
Point3d ptStart, ptEnd ;
Vector3d vtStart, vtEnd ;
if ( ! pCrv->GetStartPoint( ptStart) || ! pCrv->GetStartDir( vtStart) ||
! pCrv->GetEndPoint( ptEnd) || ! pCrv->GetEndDir( vtEnd))
return false ;
if ( ! chainC.AddCurve( int( i + 1), ptStart, vtStart, ptEnd, vtEnd))
return false ;
// se prima curva, assegno inizio della ricerca
if ( bFirst) {
pCrv->GetExtrusion( vtExtr) ;
ptNear = ptStart + 10 * EPS_SMALL * vtStart ;
bFirst = false ;
}
// altrimenti
else {
Vector3d vtTmpExtr ; pCrv->GetExtrusion( vtTmpExtr) ;
if ( ! AreSameVectorApprox( vtTmpExtr, vtExtr)) {
m_pMchMgr->SetLastError( 3128, "Error in SurfFinishing : Curves with different extrusion") ;
return false ;
}
}
}
// recupero i percorsi concatenati e definisco la regione piana di svuotatura
SurfFlatRegionByContours SfrByC ;
INTVECTOR vnId2 ;
while ( chainC.GetChainFromNear( ptNear, false, vnId2)) {
// creo una curva composita
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
if ( IsNull( pCrvCompo))
return false ;
// estrusione e spessore
Vector3d vtExtr = Z_AX ;
double dThick = 0 ;
// vettore Id originali
SELVECTOR vId2 ;
vId2.reserve( vnId2.size()) ;
// recupero le curve semplici e le inserisco nella curva composita
for ( size_t i = 0 ; i < vnId2.size() ; ++ i) {
int nId = abs( vnId2[i]) - 1 ;
bool bInvert = ( vnId2[i] < 0) ;
vId2.emplace_back( vInds[nId]) ;
// recupero la curva
ICurve* pCrv = vpCrvs[nId] ;
// se necessario, la inverto
if ( bInvert)
pCrv->Invert() ;
// recupero eventuali estrusione e spessore
Vector3d vtTemp ;
if ( pCrv->GetExtrusion( vtTemp)) {
vtExtr = vtTemp ;
double dTemp ;
if ( pCrv->GetThickness( dTemp) && abs( dTemp) > abs( dThick))
dThick = dTemp ;
}
// la aggiungo alla curva composta
if ( ! pCrvCompo->AddCurve( ::Release( vpCrvs[nId]), true, dToler))
return false ;
}
// se non sono state inserite curve, vado oltre
if ( pCrvCompo->GetCurveCount() == 0)
continue ;
// imposto estrusione e spessore
pCrvCompo->SetExtrusion( vtExtr) ;
pCrvCompo->SetThickness( dThick) ;
// verifico sia piana e se necessario la appiattisco
PtrOwner<ICurve> pFlatCrv( FlattenCurve( *pCrvCompo, 50 * EPS_SMALL, 50 * EPS_ANG_SMALL, FLTCRV_USE_EXTR)) ;
if ( IsNull( pFlatCrv)) {
Plane3d plPlane ;
if ( ! pCrvCompo->IsFlat( plPlane, true, 50 * EPS_SMALL))
m_pMchMgr->SetLastError( 2403, "Error in SurfFinishing : Contour Not Flat") ;
else
m_pMchMgr->SetLastError( 2404, "Error in SurfFinishing : Tool Not Perpendicular to Flat Area") ;
return false ;
}
pFlatCrv->GetExtrusion( vtExtr) ;
pCrvCompo->Clear() ;
pCrvCompo->AddCurve( Release( pFlatCrv)) ;
// salvo vettore estrusione
pCrvCompo->SetExtrusion( vtExtr) ;
// salvo la thickness come seconda temp prop ( la Sfr rimuove la thick delle curve)
pCrvCompo->SetTempParam( dThick, 1) ;
// aggiorno il nuovo punto vicino
pCrvCompo->GetEndPoint( ptNear) ;
// se utile, approssimo con archi
if ( ! ApproxWithArcsIfUseful( pCrvCompo))
return false ;
// inserisco la curva nella regione piana
SfrByC.AddCurve( Release( pCrvCompo)) ;
}
// scorro le regioni piane ricavate dalle curve
int nGroupName = -1 ;
PtrOwner<ISurfFlatRegion> pSfrCurr( SfrByC.GetSurf()) ;
while ( ! IsNull( pSfrCurr) && pSfrCurr->IsValid()) {
// la normale del Chunk deve essere coerente con l'estrusione ricavata
if ( AreOppositeVectorApprox( pSfrCurr->GetNormVersor(), vtExtr))
pSfrCurr->Invert() ;
// per ogni Chunk
for ( int nC = 0 ; nC < pSfrCurr->GetChunkCount() ; ++ nC) {
// creo nuovo gruppo
int nPathId = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrpDestId, Frame3d()) ;
if ( nPathId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nPathId, MCH_PATH + ToString( ++ nGroupName)) ;
m_pGeomDB->SetInfo( nPathId, KEY_IDS, ToString( nGroupName)) ;
// recupero il Chunk corrente
PtrOwner<ISurfFlatRegion> pSfrChunk( pSfrCurr->CloneChunk( nC)) ;
if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid())
return false ;
int nNewId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, ::CloneSurfFlatRegion( pSfrChunk)) ;
if ( nNewId == GDB_ID_NULL)
return false ;
// salvo eventuali lati aperti per il Chunk corrente
for ( int nL = 0 ; nL < pSfrChunk->GetLoopCount( 0) ; ++ nL) {
// recupero il Loop
PtrOwner<ICurveComposite> pCrvLoop( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, nL))) ;
if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid())
return false ;
// memorizzo le proprietà di lato aperto nelle Info del gruppo
INTVECTOR vIndOpen ;
for ( int nU = 0 ; nU < pCrvLoop->GetCurveCount() ; ++ nU) {
int nTmpProp0 = TEMP_PROP_INVALID ;
if ( pCrvLoop->GetCurveTempProp( nU, nTmpProp0, 0) && nTmpProp0 == TEMP_PROP_OPEN_EDGE)
vIndOpen.emplace_back( nU) ;
}
// memorizzo la Thickness e l'Estrusione nelle Info del gruppo
if ( nL == 0) {
double dThick = pCrvLoop->GetTempParam( 1) ;
m_pGeomDB->SetInfo( nNewId, KEY_THICK, dThick) ;
m_pGeomDB->SetInfo( nNewId, KEY_EXTR, vtExtr) ;
}
}
}
// aggiorno la regione piana con la successiva calcolata
pSfrCurr.Set( SfrByC.GetSurf()) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::ProcessCrvCompo( int nPathId, int nPvId, int nClId)
{
// recupero gruppo per geometria temporanea
const string GRP_TEMP = "Temp" ;
int nTempId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, GRP_TEMP) ;
// se non c'è, lo aggiungo
if ( nTempId == GDB_ID_NULL) {
nTempId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ;
if ( nTempId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nTempId, GRP_TEMP) ;
}
// altrimenti lo svuoto
else
m_pGeomDB->EmptyGroup( nTempId) ;
// in ogni caso lo dichiaro temporaneo e non visibile
m_pGeomDB->SetLevel( nTempId, GDB_LV_TEMP) ;
m_pGeomDB->SetStatus( nTempId, GDB_ST_OFF) ;
// recupero la curva composita dal database geometrico
int nCrvCompoId = m_pGeomDB->GetFirstInGroup( nPathId) ;
if ( m_pGeomDB->GetGeoType( nCrvCompoId) != CRV_COMPO)
return false ;
// copio la curva composits da elaborare
int nCopyId = m_pGeomDB->CopyGlob( nCrvCompoId, GDB_ID_NULL, nTempId) ;
if ( nCopyId == GDB_ID_NULL)
return false ;
const ICurveComposite* pCrvCompoGDB( GetCurveComposite( m_pGeomDB->GetGeoObj( nCopyId))) ;
if ( ! pCrvCompoGDB->IsValid())
return false ;
// recupero estrusione e spessore
Vector3d vtExtr = Z_AX ;
if ( m_pGeomDB->ExistsInfo( nCrvCompoId, KEY_EXTR))
m_pGeomDB->GetInfo( nCrvCompoId, KEY_EXTR, vtExtr) ;
double dThick = 0. ;
if ( m_pGeomDB->ExistsInfo( nCrvCompoId, KEY_THICK))
m_pGeomDB->GetInfo( nCrvCompoId, KEY_THICK, dThick) ;
// valuto l'espressione dell'affondamento
ExeLuaSetGlobNumVar( "TH", abs( dThick)) ;
double dDepth ;
string sMyDepth = m_Params.m_sDepth ;
if ( ! ExeLuaEvalNumExpr( ToUpper( sMyDepth), &dDepth)) {
m_pMchMgr->SetLastError( 3108, "Error in SurfFinishing : Depth not computable") ;
return false ;
}
// recupero il box del grezzo in globale
BBox3d b3Raw ;
if ( ! GetRawGlobBox( m_nPhase, nPathId, 0.5 * m_TParams.m_dTDiam, b3Raw) || b3Raw.IsEmpty()) {
m_pMchMgr->SetLastError( 3107, "Error in SurfFinishing : Empty RawBox") ;
return false ;
}
// verifico che la curva sia piana
Plane3d plPlane ;
if ( ! pCrvCompoGDB->IsFlat( plPlane)) {
m_pMchMgr->SetLastError( 3005, "Error in SurfFinishing : Contour Not Flat") ;
return false ;
}
// recupero nome del path
string sPathName ;
m_pGeomDB->GetName( nPathId, sPathName) ;
// assegno il versore fresa
Vector3d vtTool = vtExtr ;
// se richiesta lavorazione
if ( nClId != GDB_ID_NULL) {
// creo gruppo per geometria di lavorazione del percorso
int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ;
if ( nPxId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nPxId, sPathName) ;
m_pGeomDB->SetMaterial( nPxId, BLUE) ;
// verifico se archi vanno approssimati con segmenti di retta
bool bSplitArcs = GetSplitArcs( vtTool) ;
// porto tutte le superfici nel riferimento della prima
Frame3d frSurf ;
SURFLOCALVECTOR vSrfLoc ;
INTVECTOR vSurfId ;
GetActiveSurfaces( vSurfId) ;
for ( auto nSurfId : vSurfId) {
if ( vSrfLoc.empty()) {
if ( ! m_pGeomDB->GetGlobFrame( nSurfId, frSurf))
return false ;
}
vSrfLoc.emplace_back( m_pGeomDB, nSurfId, frSurf) ;
}
if ( ! frSurf.IsValid()) {
m_pMchMgr->SetLastError( 3123, "Error in SurfFinishing : missing surfaces") ;
return false ;
}
// predispongo l'ambiente di correzione dei percorsi utensili con le superfici attive dei pezzi
PtrOwner<ICAvToolSurfTm> pCAvTlStm( CreateCAvToolSurfTm()) ;
if ( IsNull( pCAvTlStm))
return false ;
if ( abs( m_TParams.m_dSideAng) < EPS_ANG_SMALL) {
pCAvTlStm->SetStdTool( m_TParams.m_dLen + GetOffsR(),
m_TParams.m_dDiam / 2 + GetOffsR(),
m_TParams.m_dCornRad + GetOffsR()) ;
}
else {
double dDeltaRad ;
double dSideAngRad = m_TParams.m_dSideAng * DEGTORAD ;
if ( m_TParams.m_dSideAng > 0) {
if ( m_TParams.m_dCornRad < EPS_SMALL)
dDeltaRad = m_TParams.m_dMaxMat * tan( dSideAngRad) ;
else
dDeltaRad = m_TParams.m_dCornRad * cos( dSideAngRad) +
( m_TParams.m_dMaxMat + m_TParams.m_dCornRad * ( sin( dSideAngRad) - 1)) * tan( dSideAngRad) ;
}
else {
dDeltaRad = tan( dSideAngRad) * m_TParams.m_dMaxMat ;
}
double dStemRad = m_TParams.m_dDiam / 2 + dDeltaRad ;
double dTipRad = m_TParams.m_dDiam / 2 ;
pCAvTlStm->SetAdvTool( m_TParams.m_dLen + GetOffsR(),
dStemRad + GetOffsR(),
m_TParams.m_dMaxMat,
dTipRad + GetOffsR(),
m_TParams.m_dCornRad + GetOffsR()) ;
}
pCAvTlStm->SetSurfTm( *GetSurfTriMesh( vSrfLoc[0].Get())) ;
for ( int i = 1 ; i < int( vSrfLoc.size()) ; ++ i)
pCAvTlStm->AddSurfTm( *GetSurfTriMesh( vSrfLoc[i].Get())) ;
// assegno il vettore estrazione al gruppo del percorso
m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ;
// Imposto dati comuni
SetPathId( nPxId) ;
SetToolDir( vtTool) ;
// recupero la curva da lavorare
PtrOwner<ICurveComposite> pCrvCompo( pCrvCompoGDB->Clone()) ;
if ( IsNull( pCrvCompo) || ! pCrvCompo->IsValid())
return false ;
// Eseguo la lavorazione a seconda del tipo
double dElev = dDepth ;
switch ( m_Params.m_nSubType) {
case SURFFIN_SUB_PROJECT :
if ( ! AddProjection( pCAvTlStm, vSrfLoc, frSurf, pCrvCompoGDB, vtTool, dDepth, dElev, bSplitArcs))
return false ;
break ;
}
}
// incremento numero di percorsi
++ m_nPaths ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::ProcessSfr( int nPathId, int nPvId, int nClId)
{
// recupero gruppo per geometria temporanea
const string GRP_TEMP = "Temp" ;
int nTempId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, GRP_TEMP) ;
// se non c'è, lo aggiungo
if ( nTempId == GDB_ID_NULL) {
nTempId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ;
if ( nTempId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nTempId, GRP_TEMP) ;
}
// altrimenti lo svuoto
else
m_pGeomDB->EmptyGroup( nTempId) ;
// in ogni caso lo dichiaro temporaneo e non visibile
m_pGeomDB->SetLevel( nTempId, GDB_LV_TEMP) ;
m_pGeomDB->SetStatus( nTempId, GDB_ST_OFF) ;
// recupero la regione piana dal database geometrico
int nSfrId = m_pGeomDB->GetFirstInGroup( nPathId) ;
if ( m_pGeomDB->GetGeoType( nSfrId) != SRF_FLATRGN)
return false ;
// copio la regione piana da elaborare
int nCopyId = m_pGeomDB->CopyGlob( nSfrId, GDB_ID_NULL, nTempId) ;
if ( nCopyId == GDB_ID_NULL)
return false ;
const ISurfFlatRegion* pSfrGDB( GetSurfFlatRegion( m_pGeomDB->GetGeoObj( nCopyId))) ;
if ( ! pSfrGDB->IsValid())
return false ;
// recupero estrusione e spessore
Vector3d vtExtr = Z_AX ;
if ( m_pGeomDB->ExistsInfo( nSfrId, KEY_EXTR))
m_pGeomDB->GetInfo( nSfrId, KEY_EXTR, vtExtr) ;
double dThick = 0. ;
if ( m_pGeomDB->ExistsInfo( nSfrId, KEY_THICK))
m_pGeomDB->GetInfo( nSfrId, KEY_THICK, dThick) ;
// valuto l'espressione dell'affondamento
ExeLuaSetGlobNumVar( "TH", abs( dThick)) ;
double dDepth ;
string sMyDepth = m_Params.m_sDepth ;
if ( ! ExeLuaEvalNumExpr( ToUpper( sMyDepth), &dDepth)) {
m_pMchMgr->SetLastError( 3108, "Error in SurfFinishing : Depth not computable") ;
return false ;
}
// se spessore positivo, lo sottraggo al risultato
if ( dThick > 0)
dDepth -= dThick ;
// recupero il box del grezzo in globale
BBox3d b3Raw ;
if ( ! GetRawGlobBox( m_nPhase, nPathId, 0.5 * m_TParams.m_dTDiam, b3Raw) || b3Raw.IsEmpty()) {
m_pMchMgr->SetLastError( 3107, "Error in SurfFinishing : Empty RawBox") ;
return false ;
}
// recupero il Loop esterno della regione da svuotatare
PtrOwner<ICurve> pCrvExt( pSfrGDB->GetLoop( 0, 0)) ;
if ( IsNull( pCrvExt) || ! pCrvExt->IsValid())
return false ;
// verifico sia piana e sistemo senso antiorario visto dalla direzione di estrusione
Plane3d plPlane ; double dArea ;
if ( ! pCrvExt->GetArea( plPlane, dArea)) {
m_pMchMgr->SetLastError( 3005, "Error in SurfFinishing : Contour Not Flat") ;
return false ;
}
if ( abs( plPlane.GetVersN() * vtExtr) < cos( 10 * EPS_ANG_SMALL)) {
m_pMchMgr->SetLastError( 3006, "Error in SurfFinishing : Tool Dir not perpendicular to Flat Area") ;
return false ;
}
if ( plPlane.GetVersN() * vtExtr * dArea < 0)
pCrvExt->Invert() ;
if ( plPlane.GetVersN() * vtExtr < 0)
plPlane.Invert() ;
// recupero flag per saltare parti a massimo affondamento
bool bSkipMaxDown = true ;
GetValInNotes( m_Params.m_sUserNotes, "SkipMaxDown", bSkipMaxDown) ;
// recupero nome del path
string sPathName ;
m_pGeomDB->GetName( nPathId, sPathName) ;
// assegno il versore fresa
Vector3d vtTool = vtExtr ;
// se richiesta lavorazione
if ( nClId != GDB_ID_NULL) {
// creo gruppo per geometria di lavorazione del percorso
int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ;
if ( nPxId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nPxId, sPathName) ;
m_pGeomDB->SetMaterial( nPxId, BLUE) ;
// verifico se archi vanno approssimati con segmenti di retta
bool bSplitArcs = GetSplitArcs( vtTool) ;
// porto tutte le superfici nel riferimento della prima
Frame3d frSurf ;
SURFLOCALVECTOR vSrfLoc ;
INTVECTOR vSurfId ;
GetActiveSurfaces( vSurfId) ;
for ( auto nSurfId : vSurfId) {
if ( vSrfLoc.empty()) {
if ( ! m_pGeomDB->GetGlobFrame( nSurfId, frSurf))
return false ;
}
vSrfLoc.emplace_back( m_pGeomDB, nSurfId, frSurf) ;
}
if ( ! frSurf.IsValid()) {
m_pMchMgr->SetLastError( 3123, "Error in SurfFinishing : missing surfaces") ;
return false ;
}
// predispongo l'ambiente di correzione dei percorsi utensili con le superfici attive dei pezzi
PtrOwner<ICAvToolSurfTm> pCAvTlStm( CreateCAvToolSurfTm()) ;
if ( IsNull( pCAvTlStm))
return false ;
if ( abs( m_TParams.m_dSideAng) < EPS_ANG_SMALL) {
pCAvTlStm->SetStdTool( m_TParams.m_dLen + GetOffsR(),
m_TParams.m_dDiam / 2 + GetOffsR(),
m_TParams.m_dCornRad + GetOffsR()) ;
}
else {
double dDeltaRad ;
double dSideAngRad = m_TParams.m_dSideAng * DEGTORAD ;
if ( m_TParams.m_dSideAng > 0) {
if ( m_TParams.m_dCornRad < EPS_SMALL)
dDeltaRad = m_TParams.m_dMaxMat * tan( dSideAngRad) ;
else
dDeltaRad = m_TParams.m_dCornRad * cos( dSideAngRad) +
( m_TParams.m_dMaxMat + m_TParams.m_dCornRad * ( sin( dSideAngRad) - 1)) * tan( dSideAngRad) ;
}
else {
dDeltaRad = tan( dSideAngRad) * m_TParams.m_dMaxMat ;
}
double dStemRad = m_TParams.m_dDiam / 2 + dDeltaRad ;
double dTipRad = m_TParams.m_dDiam / 2 ;
pCAvTlStm->SetAdvTool( m_TParams.m_dLen + GetOffsR(),
dStemRad + GetOffsR(),
m_TParams.m_dMaxMat,
dTipRad + GetOffsR(),
m_TParams.m_dCornRad + GetOffsR()) ;
}
pCAvTlStm->SetSurfTm( *GetSurfTriMesh( vSrfLoc[0].Get())) ;
for ( int i = 1 ; i < int( vSrfLoc.size()) ; ++ i)
pCAvTlStm->AddSurfTm( *GetSurfTriMesh( vSrfLoc[i].Get())) ;
// determino la regione da lavorare
PtrOwner<ISurfFlatRegion> pSfrCnt( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrCnt) || ! pSfrCnt->AddExtLoop( *pCrvExt)) {
m_pMchMgr->SetLastError( 3124, "Error in SurfFinishing : region not computable") ;
return false ;
}
for ( int nL = 1 ; nL < pSfrGDB->GetLoopCount( 0) ; ++ nL) {
// recupero l'isola
PtrOwner<ICurve> pCrvIsl( pSfrGDB->GetLoop( 0, nL)) ;
if ( IsNull( pCrvIsl) || ! pCrvIsl->IsValid() ||
! pSfrCnt->AddIntLoop( Release( pCrvIsl)))
return false ;
}
// se richiesto, elimino le parti al massimo affondamento
if ( bSkipMaxDown &&
m_Params.m_nSubType != SURFFIN_SUB_Z_CONST) {
// calcolo silhouette dell'insieme di superfici
CISURFTMPVECTOR vpStm ; vpStm.reserve( vSurfId.size()) ;
for ( int i = 0 ; i < int( vSrfLoc.size()) ; ++ i)
vpStm.emplace_back( GetSurfTriMesh( vSrfLoc[i].Get())) ;
Frame3d frPocket ;
Point3d ptCen ; pCrvExt->GetCentroid( ptCen) ;
frPocket.Set( ptCen, vtTool) ;
frPocket.ToLoc( frSurf) ;
const double SILH_TOL = 1.0 ;
PtrOwner<ICAvParSilhouettesSurfTm> pCavParSilh( CreateCAvParSilhouettesSurfTm()) ;
if ( IsNull( pCavParSilh) || ! pCavParSilh->SetData( vpStm, frPocket, SILH_TOL))
return false ;
POLYLINEVECTOR vPL ;
if ( ! pCavParSilh->GetSilhouette( -dDepth, vPL)) {
m_pMchMgr->SetLastError( 3124, "Error in SurfFinishing : region not computable") ;
return false ;
}
// creo la regione piana dalle PolyLine ricavate dalla Silhouette
SurfFlatRegionByContours SfrMaker ;
for ( auto& PL : vPL) {
// recupero la curva dalla silhouette
PtrOwner<ICurveComposite> pSilCrv( CreateCurveComposite()) ;
if ( IsNull( pSilCrv))
return false ;
pSilCrv->FromPolyLine( PL) ;
// approssimo con archi
const double SILH_ARC_TOL = 0.1 * SILH_TOL ;
const double SILH_ARC_FEA_MAX = 100. ;
PolyArc PA ;
if ( pSilCrv->ApproxWithArcsEx( SILH_ARC_TOL, ANG_TOL_STD_DEG, SILH_ARC_FEA_MAX, PA)) {
PtrOwner<ICurveComposite> pTempCrv( CreateCurveComposite()) ;
if ( ! IsNull( pTempCrv) &&
pTempCrv->FromPolyArc( PA) &&
pTempCrv->RemoveSmallDefects( SILH_ARC_TOL / 2, ANG_TOL_STD_DEG) &&
pTempCrv->MergeCurves( SILH_ARC_TOL / 2, ANG_TOL_STD_DEG))
pSilCrv.Set( pTempCrv) ;
}
// aggiungo per regione
if ( ! SfrMaker.AddCurve( Release( pSilCrv))) {
m_pMchMgr->SetLastError( 3124, "Error in SurfFinishing : region not computable") ;
return false ;
}
}
PtrOwner<ISurfFlatRegion> pSfrSil( SfrMaker.GetSurf()) ;
if ( ! IsNull( pSfrSil)) {
pSfrSil->ToGlob( frSurf) ;
double dPockRadOffs = m_TParams.m_dDiam - m_Params.m_dSideStep - m_Params.m_dOverlap ;
pSfrSil->Offset( dPockRadOffs, ICurve::OFF_CHAMFER) ;
// intersezione tra contorno e regione
if ( ! pSfrCnt->Intersect( *pSfrSil)) {
// ricreo la regione originale
pSfrCnt->Clear() ;
pSfrCnt->AddExtLoop( *pCrvExt) ;
}
// azzero le proprietà delle curve semplici dei contorni delle regioni ( se 1 lato aperto)
for ( int nC = 0 ; nC < pSfrCnt->GetChunkCount() ; ++ nC) {
for ( int nL = 0 ; nL < pSfrCnt->GetLoopCount( nC) ; ++ nL) {
for ( int nCrv = 0 ; ; ++ nCrv) {
if ( ! pSfrCnt->SetCurveTempProp( nC, nL, nCrv, 0, 0) ||
! pSfrCnt->SetCurveTempProp( nC, nL, nCrv, 0, 1))
break ;
}
}
}
}
}
// se regione risultante vuota, non devo fare altro
if ( ! pSfrCnt->IsValid())
return true ;
// assegno il vettore estrazione al gruppo del percorso
m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ;
// Imposto dati comuni
SetPathId( nPxId) ;
SetToolDir( vtTool) ;
// Eseguo la lavorazione a seconda del tipo
double dElev = dDepth ;
switch ( m_Params.m_nSubType) {
case SURFFIN_SUB_ZIGZAG :
if ( ! AddZigZag( pCAvTlStm, frSurf, pSfrCnt, vtTool, dDepth, dElev, bSplitArcs))
return false ;
break ;
case SURFFIN_SUB_ONEWAY :
if ( ! AddOneWay( pCAvTlStm, frSurf, pSfrCnt, vtTool, dDepth, dElev, bSplitArcs))
return false ;
break ;
case SURFFIN_SUB_SPIRALIN :
if ( ! AddSpiral( pCAvTlStm, frSurf, pSfrCnt, vtTool, dDepth, dElev, bSplitArcs, true))
return false ;
break ;
case SURFFIN_SUB_SPIRALOUT :
if ( ! AddSpiral( pCAvTlStm, frSurf, pSfrCnt, vtTool, dDepth, dElev, bSplitArcs, false))
return false ;
break ;
case SURFFIN_SUB_Z_CONST :
if ( ! AddZConst( pCAvTlStm, vSrfLoc, frSurf, pSfrCnt, vtTool, dDepth, dElev, bSplitArcs))
return false ;
break ;
case SURFFIN_SUB_OPTIMAL :
if ( ! AddOptimal( pCAvTlStm, vSrfLoc, frSurf, pSfrCnt, vtTool, dDepth, dElev, bSplitArcs))
return false ;
break ;
}
}
// incremento numero di percorsi
++ m_nPaths ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::SimplifyCurve( ICurveComposite* pCompo) const
{
// controllo dei parametri
if ( pCompo == nullptr || ! pCompo->IsValid())
return false ;
// ricavo il punto iniziale e finale
Point3d ptStart ; pCompo->GetStartPoint( ptStart) ;
Point3d ptEnd ; pCompo->GetEndPoint( ptEnd) ;
// eseguo le modifiche su una copia della curva originale
PtrOwner<ICurveComposite> pCompoCL( CloneCurveComposite( pCompo)) ;
if ( IsNull( pCompoCL))
return false ;
// merge per uniformità
bool bOk = pCompoCL->MergeCurves( 200 * EPS_SMALL, 200 * EPS_ANG_SMALL, false) ;
// rimozione Spikes o Curve Z
bOk = bOk && pCompoCL->RemoveSmallDefects( 150 * EPS_SMALL, 2 * ANG_TOL_STD_DEG, true) ;
// interpolazione mediante linee ed archi
PolyArc PA ;
bOk = bOk && pCompoCL->ApproxWithArcsEx( 50 * EPS_SMALL, ANG_TOL_STD_DEG, LIN_FEA_STD, PA) &&
pCompoCL->Clear() && pCompoCL->FromPolyArc( PA) ;
// controllo aggiuntivo sui punti iniziali e finali che siano gli stessi
Point3d ptNewStart, ptNewEnd ;
bOk = bOk && pCompoCL->GetStartPoint( ptNewStart) && pCompoCL->GetEndPoint( ptNewEnd) &&
AreSamePointApprox( ptNewStart, ptStart) && AreSamePointApprox( ptNewEnd, ptEnd) ;
// controllo che non si siano create auto-intersezioni
SelfIntersCurve SIC( *pCompoCL) ;
bOk = bOk && ( SIC.GetCrossIntersCount() == 0) ;
// se tutto bene, sostiuisco la curva originale con la modificata
if ( bOk)
pCompo->CopyFrom( pCompoCL) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::GetActiveSurfaces( INTVECTOR& vSurfId) const
{
// pulisco vettore superfici
vSurfId.clear() ;
// verifiche
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// cerco tra gli oggetti selezionati
for ( const auto& Id : m_vId) {
int nEntId = Id.nId ;
if ( m_pGeomDB->GetGeoType( nEntId) == SRF_TRIMESH)
vSurfId.emplace_back( nEntId) ;
}
// se trovate superfici, considero solo queste ed esco
if ( ! vSurfId.empty())
return true ;
// altrimenti considero tutte le superfici dei pezzi nei grezzi attivi della fase
int nRawId = m_pMchMgr->GetFirstRawPart() ;
while ( nRawId != GDB_ID_NULL) {
if ( m_pMchMgr->VerifyRawPartPhase(nRawId, m_nPhase)) {
// ciclo sui pezzi del grezzo
int nPartId = m_pMchMgr->GetFirstPartInRawPart( nRawId) ;
while ( nPartId != GDB_ID_NULL) {
// ciclo sui layer dei pezzi
int nLayId = m_pGeomDB->GetFirstGroupInGroup( nPartId) ;
while ( nLayId != GDB_ID_NULL) {
// ciclo sulle entità del layer
int nEntId = m_pGeomDB->GetFirstInGroup( nLayId) ;
while ( nEntId != GDB_ID_NULL) {
// se entità superficie e visibile, la aggiungo
int nStat ;
if ( m_pGeomDB->GetGeoType( nEntId) == SRF_TRIMESH &&
m_pGeomDB->GetCalcStatus( nEntId, nStat) && nStat != GDB_ST_OFF)
vSurfId.emplace_back( nEntId) ;
// passo alla entità successiva
nEntId = m_pGeomDB->GetNext( nEntId) ;
}
nLayId =m_pGeomDB->GetNextGroup( nLayId) ;
}
nPartId = m_pMchMgr->GetNextPartInRawPart( nPartId) ;
}
}
nRawId = m_pMchMgr->GetNextRawPart( nRawId) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::AddZigZag( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, const ISurfFlatRegion* pSfrPock,
const Vector3d& vtTool, double dDepth, double dElev, bool bSplitArcs)
{
// recupero distanze di sicurezza
double dSafeZ = GetSafeZ() ;
// lunghezza di approccio/retrazione
double dAppr = m_Params.m_dStartPos ;
// calcolo lo zig-zag
double dPockRad = m_Params.m_dSideStep ;
double dPockRadOffs = m_TParams.m_dDiam / 2 - m_Params.m_dSideStep - m_Params.m_dOverlap ;
ICRVCOMPOPOVECTOR vpCrvs ;
if ( ! CalcPocketing( pSfrPock, dPockRad, dPockRadOffs, m_Params.m_dSideStep, m_Params.m_dSideAngle,
POCKET_ZIGZAG, false, false, true, false, P_INVALID, nullptr, vpCrvs)) {
m_pMchMgr->SetLastError( 3125, "Error in SurfFinishing : CalcPocketing failed") ;
return false ;
}
// determino il riferimento di base della svuotatura
Frame3d frPocket ;
Point3d ptCen ; pSfrPock->GetCentroid( ptCen) ;
frPocket.Set( ptCen, vtTool) ;
// ciclo sulle curve risultanti
bool bStart = true ;
double dProgCoeff = 1. / max( int( vpCrvs.size()), 1) ;
for ( int k = 0 ; k < int( vpCrvs.size()) ; ++ k) {
PtrOwner<ICurveComposite> pMCrv( Release( vpCrvs[k])) ;
pMCrv->ToLoc( frPocket) ;
// li correggo per non interferire con le superfici
if ( pCAvTlStm != nullptr) {
// approssimo la curva con una polilinea
PolyLine PL ;
if ( ! pMCrv->ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL))
return false ;
// eventuale aggiunta di punti per garantire max distanza
const double MIN_DIST = 1. ;
const double MAX_DIST = 50. ;
double dDist = Clamp( m_TParams.m_dDiam / 2, MIN_DIST, MAX_DIST) ;
if ( ! PL.AdjustForMaxSegmentLen( dDist))
return false ;
// porto nel riferimento delle superfici
PL.LocToLoc( frPocket, frSurf) ;
// porto i dati geometrici in locale alle superfici
Vector3d vtAxL = vtTool ;
vtAxL.ToLoc( frSurf) ;
Vector3d vtMoveL = vtAxL ;
// traslo della lunghezza utensile diminuita dell'affondamento
PL.Translate( vtAxL * ( m_TParams.m_dLen - dDepth)) ;
// eseguo CAv
if ( ! pCAvTlStm->TestPath( PL.GetUPointList(), vtAxL, vtMoveL, m_Params.m_dApprox, ( k + 1) * dProgCoeff))
return false ;
// contro-traslo della lunghezza utensile
PL.Translate( - vtAxL * m_TParams.m_dLen) ;
// riporto la polilinea nel riferimento della curva
PL.LocToLoc( frSurf, frPocket) ;
// elimino i punti allineati
PL.RemoveAlignedPoints( 0.8 * m_Params.m_dApprox) ;
// creo una curva composita a partire dalla polilinea
PtrOwner< ICurveComposite> pCompo( CreateCurveComposite()) ;
if ( IsNull( pCompo) || ! pCompo->FromPolyLine( PL))
return false ;
// sostituisco la vecchia curva con la nuova
pMCrv.Set( pCompo) ;
}
// ciclo sulle curve elementari
int nMaxInd = pMCrv->GetCurveCount() - 1 ;
for ( int i = 0 ; i <= nMaxInd ; ++ i) {
// curva corrente
const ICurve* pCrvC = pMCrv->GetCurve( i) ;
// copio la curva
PtrOwner<ICurve> pCurve( pCrvC->Clone()) ;
if ( IsNull( pCurve))
return false ;
pCurve->ToGlob( frPocket) ;
// se prima entità
if ( i == 0 ) {
// dati inizio entità
Point3d ptStart ;
pCurve->GetStartPoint( ptStart) ;
Vector3d vtStart ;
pCurve->GetStartDir( vtStart) ;
// vettore tangente iniziale non deve salire rispetto a estrusione (poi si prende opposto)
double dStartOnExtr = vtStart * vtTool ;
if ( dStartOnExtr > 0) {
vtStart -= dStartOnExtr * vtTool ;
vtStart.Normalize() ;
}
// determino normale della superficie sul punto iniziale
Vector3d vtNorm ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptStart, vtTool, vtNorm)) {
Point3d ptEnd ;
pCurve->GetEndPoint( ptEnd) ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptEnd, vtTool, vtNorm))
vtNorm = V_NULL ;
}
// determino inizio attacco
Point3d ptP1 ;
if ( ! CalcLeadInStart( ptStart, vtStart, vtTool, vtNorm, ptP1))
return false ;
// eventuale correzione inizio attacco per evitare interferenze
if ( ! GetLastGoodPoint( pCAvTlStm, frSurf, ptStart, ptP1, vtTool, ptP1))
return false ;
// determino elevazione su inizio attacco
double dStElev ;
if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev))
dStElev = dElev ;
dStElev -= ( ptP1 - ptStart) * vtTool ;
// se inizio, approccio globale al punto iniziale
if ( bStart) {
if ( ! AddApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) {
m_pMchMgr->SetLastError( 3111, "Error in SurfFinishing : Approach not computable") ;
return false ;
}
bStart = false ;
}
// altrimenti, approccio di collegamento
else {
if ( ! AddLinkApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) {
m_pMchMgr->SetLastError( 3112, "Error in SurfFinishing : Link not computable") ;
return false ;
}
}
// aggiungo attacco
SetFeed( GetStartFeed()) ;
if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtTool, bSplitArcs)) {
m_pMchMgr->SetLastError( 3113, "Error in SurfFinishing : LeadIn not computable") ;
return false ;
}
}
// elaborazioni sulla curva corrente (sempre un segmento di retta)
ICurveLine* pLine = GetCurveLine( pCurve) ;
if ( pLine == nullptr)
return false ;
Point3d ptP3 = pLine->GetEnd() ;
Vector3d vtMove ; pLine->GetStartDir( vtMove) ;
SetFeed( GetRightFeed( vtMove, vtTool)) ;
if ( AddLinearMove( ptP3) == GDB_ID_NULL)
return false ;
// se ultima entità
if ( i == nMaxInd) {
// dati fine entità
Point3d ptEnd ;
pCurve->GetEndPoint( ptEnd) ;
Vector3d vtEnd ;
pCurve->GetEndDir( vtEnd) ;
// vettore tangente finale non deve scendere rispetto a estrusione
double dEndOnExtr = vtEnd * vtTool ;
if ( dEndOnExtr < 0) {
vtEnd -= dEndOnExtr * vtTool ;
vtEnd.Normalize() ;
}
// determino normale della superficie sul punto finale
Vector3d vtNorm ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptEnd, vtTool, vtNorm)) {
Point3d ptStart ;
pCurve->GetStartPoint( ptStart) ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptStart, vtTool, vtNorm))
vtNorm = V_NULL ;
}
// determino fine uscita
Point3d ptP1 ;
if ( ! CalcLeadOutEnd( ptEnd, vtEnd, vtTool, vtNorm, ptP1))
return false ;
// eventuale correzione fine uscita per evitare interferenze
if ( ! GetLastGoodPoint( pCAvTlStm, frSurf, ptEnd, ptP1, vtTool, ptP1))
return false ;
// aggiungo uscita
SetFeed( GetEndFeed()) ;
if ( ! AddLeadOut( ptEnd, vtEnd, ptP1, vtTool, bSplitArcs)) {
m_pMchMgr->SetLastError( 3114, "Error in SurfFinishing : LeadOut not computable") ;
return false ;
}
// determino elevazione su fine uscita
double dEndElev ;
if ( ! GetElevation( m_nPhase, ptEnd - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dEndElev))
dEndElev = dElev ;
dEndElev -= ( ptP1 - ptEnd) * vtTool ;
// se non è ultimo tratto, aggiungo retrazione di collegamento
if ( k < int( vpCrvs.size()) - 1) {
if ( ! AddLinkRetract( ptP1, vtTool, dSafeZ, dEndElev, dAppr)) {
m_pMchMgr->SetLastError( 3112, "Error in SurfFinishing : Link not computable") ;
return false ;
}
}
// altrimenti aggiungo retrazione finale
else {
if ( ! AddRetract( ptP1, vtTool, dSafeZ, dEndElev, dAppr)) {
m_pMchMgr->SetLastError( 3115, "Error in SurfFinishing : Retract not computable") ;
return false ;
}
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::AddOneWay( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, const ISurfFlatRegion* pSfrPock,
const Vector3d& vtTool, double dDepth, double dElev, bool bSplitArcs)
{
// recupero distanze di sicurezza
double dSafeZ = GetSafeZ() ;
// lunghezza di approccio/retrazione
double dAppr = m_Params.m_dStartPos ;
// calcolo lo one-way
double dPockRad = m_Params.m_dSideStep ;
double dPockRadOffs = m_TParams.m_dDiam / 2 - m_Params.m_dSideStep - m_Params.m_dOverlap ;
ICRVCOMPOPOVECTOR vpCrvs ;
if ( ! CalcPocketing( pSfrPock, dPockRad, dPockRadOffs, m_Params.m_dSideStep, m_Params.m_dSideAngle,
POCKET_ONEWAY, false, false, true, false, P_INVALID, nullptr, vpCrvs)) {
m_pMchMgr->SetLastError( 3125, "Error in SurfFinishing : CalcPocketing failed") ;
return false ;
}
// determino il riferimento di base della svuotatura
Frame3d frPocket ;
Point3d ptCen ; pSfrPock->GetCentroid( ptCen) ;
frPocket.Set( ptCen, vtTool) ;
// ciclo sulle curve risultanti
bool bStart = true ;
double dProgCoeff = 1. / max( int( vpCrvs.size()), 1) ;
for ( int k = 0 ; k < int( vpCrvs.size()) ; ++ k) {
PtrOwner<ICurveComposite> pMCrv( Release( vpCrvs[k])) ;
pMCrv->ToLoc( frPocket) ;
// li correggo per non interferire con le superfici
if ( pCAvTlStm != nullptr) {
// approssimo la curva con una polilinea
PolyLine PL ;
if ( ! pMCrv->ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL))
return false ;
// eventuale aggiunta di punti per garantire max distanza
const double MIN_DIST = 1. ;
const double MAX_DIST = 50. ;
double dDist = Clamp( m_TParams.m_dDiam / 2, MIN_DIST, MAX_DIST) ;
if ( ! PL.AdjustForMaxSegmentLen( dDist))
return false ;
// porto nel riferimento delle superfici
PL.LocToLoc( frPocket, frSurf) ;
// porto i dati geometrici in locale alle superfici
Vector3d vtAxL = vtTool ;
vtAxL.ToLoc( frSurf) ;
Vector3d vtMoveL = vtAxL ;
// traslo della lunghezza utensile diminuita dell'affondamento
PL.Translate( vtAxL * ( m_TParams.m_dLen - dDepth)) ;
// eseguo CAv
if ( ! pCAvTlStm->TestPath( PL.GetUPointList(), vtAxL, vtMoveL, m_Params.m_dApprox, ( k + 1) * dProgCoeff))
return false ;
// contro-traslo della lunghezza utensile
PL.Translate( - vtAxL * m_TParams.m_dLen) ;
// riporto la polilinea nel riferimento della curva
PL.LocToLoc( frSurf, frPocket) ;
// elimino i punti allineati
PL.RemoveAlignedPoints( 0.8 * m_Params.m_dApprox) ;
// creo una curva composita a partire dalla polilinea
PtrOwner< ICurveComposite> pCompo( CreateCurveComposite()) ;
if ( IsNull( pCompo) || ! pCompo->FromPolyLine( PL))
return false ;
// sostituisco la vecchia curva con la nuova
pMCrv.Set( pCompo) ;
}
// ciclo sulle curve elementari
int nMaxInd = pMCrv->GetCurveCount() - 1 ;
for ( int i = 0 ; i <= nMaxInd ; ++ i) {
// curva corrente
const ICurve* pCrvC = pMCrv->GetCurve( i) ;
// copio la curva
PtrOwner<ICurve> pCurve( pCrvC->Clone()) ;
if ( IsNull( pCurve))
return false ;
pCurve->ToGlob( frPocket) ;
// se prima entità
if ( i == 0 ) {
// dati inizio entità
Point3d ptStart ;
pCurve->GetStartPoint( ptStart) ;
Vector3d vtStart ;
pCurve->GetStartDir( vtStart) ;
// vettore tangente iniziale non deve salire rispetto a estrusione (poi si prende opposto)
double dStartOnExtr = vtStart * vtTool ;
if ( dStartOnExtr > 0) {
vtStart -= dStartOnExtr * vtTool ;
vtStart.Normalize() ;
}
// determino normale della superficie sul punto iniziale
Vector3d vtNorm ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptStart, vtTool, vtNorm)) {
Point3d ptEnd ;
pCurve->GetEndPoint( ptEnd) ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptEnd, vtTool, vtNorm))
vtNorm = V_NULL ;
}
// determino inizio attacco
Point3d ptP1 ;
if ( ! CalcLeadInStart( ptStart, vtStart, vtTool, vtNorm, ptP1))
return false ;
// eventuale correzione inizio attacco per evitare interferenze
if ( ! GetLastGoodPoint( pCAvTlStm, frSurf, ptStart, ptP1, vtTool, ptP1))
return false ;
// determino elevazione su inizio attacco
double dStElev ;
if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev))
dStElev = dElev ;
dStElev -= ( ptP1 - ptStart) * vtTool ;
// se inizio, approccio globale al punto iniziale
if ( bStart) {
if ( ! AddApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) {
m_pMchMgr->SetLastError( 3111, "Error in SurfFinishing : Approach not computable") ;
return false ;
}
bStart = false ;
}
// altrimenti, approccio di collegamento
else {
if ( ! AddLinkApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) {
m_pMchMgr->SetLastError( 3112, "Error in SurfFinishing : Link not computable") ;
return false ;
}
}
// aggiungo attacco
SetFeed( GetStartFeed()) ;
if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtTool, bSplitArcs)) {
m_pMchMgr->SetLastError( 3113, "Error in SurfFinishing : LeadIn not computable") ;
return false ;
}
}
// elaborazioni sulla curva corrente (sempre un segmento di retta)
ICurveLine* pLine = GetCurveLine( pCurve) ;
if ( pLine == nullptr)
return false ;
Point3d ptP3 = pLine->GetEnd() ;
Vector3d vtMove ; pLine->GetStartDir( vtMove) ;
SetFeed( GetRightFeed( vtMove, vtTool)) ;
if ( AddLinearMove( ptP3) == GDB_ID_NULL)
return false ;
// se ultima entità
if ( i == nMaxInd) {
// dati fine entità
Point3d ptEnd ;
pCurve->GetEndPoint( ptEnd) ;
Vector3d vtEnd ;
pCurve->GetEndDir( vtEnd) ;
// vettore tangente finale non deve scendere rispetto a estrusione
double dEndOnExtr = vtEnd * vtTool ;
if ( dEndOnExtr < 0) {
vtEnd -= dEndOnExtr * vtTool ;
vtEnd.Normalize() ;
}
// determino normale della superficie sul punto finale
Vector3d vtNorm ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptEnd, vtTool, vtNorm)) {
Point3d ptStart ;
pCurve->GetStartPoint( ptStart) ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptStart, vtTool, vtNorm))
vtNorm = V_NULL ;
}
// determino fine uscita
Point3d ptP1 ;
if ( ! CalcLeadOutEnd( ptEnd, vtEnd, vtTool, vtNorm, ptP1))
return false ;
// eventuale correzione fine uscita per evitare interferenze
if ( ! GetLastGoodPoint( pCAvTlStm, frSurf, ptEnd, ptP1, vtTool, ptP1))
return false ;
// aggiungo uscita
SetFeed( GetEndFeed()) ;
if ( ! AddLeadOut( ptEnd, vtEnd, ptP1, vtTool, bSplitArcs)) {
m_pMchMgr->SetLastError( 3114, "Error in SurfFinishing : LeadOut not computable") ;
return false ;
}
// determino elevazione su fine uscita
double dEndElev ;
if ( ! GetElevation( m_nPhase, ptEnd - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dEndElev))
dEndElev = dElev ;
dEndElev -= ( ptP1 - ptEnd) * vtTool ;
// se non è ultimo tratto, aggiungo retrazione di collegamento
if ( k < int( vpCrvs.size()) - 1) {
if ( ! AddLinkRetract( ptP1, vtTool, dSafeZ, dEndElev, dAppr)) {
m_pMchMgr->SetLastError( 3112, "Error in SurfFinishing : Link not computable") ;
return false ;
}
}
// altrimenti aggiungo retrazione finale
else {
if ( ! AddRetract( ptP1, vtTool, dSafeZ, dEndElev, dAppr)) {
m_pMchMgr->SetLastError( 3115, "Error in SurfFinishing : Retract not computable") ;
return false ;
}
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::AddSpiral( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, const ISurfFlatRegion* pSfrPock,
const Vector3d& vtTool, double dDepth, double dElev, bool bSplitArcs, bool bInVsOut)
{
// recupero distanze di sicurezza
double dSafeZ = GetSafeZ() ;
// lunghezza di approccio/retrazione
double dAppr = m_Params.m_dStartPos ;
// calcolo la spirale
double dPockRad = m_Params.m_dSideStep ;
double dPockRadOffs = m_TParams.m_dDiam / 2 - m_Params.m_dSideStep - m_Params.m_dOverlap ;
int nType = ( bInVsOut ? POCKET_SPIRALIN : POCKET_SPIRALOUT) ;
ICRVCOMPOPOVECTOR vpCrvs ;
if ( ! CalcPocketing( pSfrPock, dPockRad, dPockRadOffs, m_Params.m_dSideStep, m_Params.m_dSideAngle,
nType, false, false, true, false, P_INVALID, nullptr, vpCrvs)) {
m_pMchMgr->SetLastError( 3125, "Error in SurfFinishing : CalcPocketing failed") ;
return false ;
}
// determino il riferimento di base della svuotatura
Frame3d frPocket ;
Point3d ptCen ; pSfrPock->GetCentroid( ptCen) ;
frPocket.Set( ptCen, vtTool) ;
// ciclo sulle curve risultanti
bool bStart = true ;
for ( int k = 0 ; k < int( vpCrvs.size()) ; ++ k) {
PtrOwner<ICurveComposite> pMCrv( Release( vpCrvs[k])) ;
pMCrv->ToLoc( frPocket) ;
// li correggo per non interferire con le superfici
if ( pCAvTlStm != nullptr) {
// approssimo la curva con una polilinea
PolyLine PL ;
if ( ! pMCrv->ApproxWithLines( m_Params.m_dApprox, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL))
return false ;
// eventuale aggiunta di punti per garantire max distanza
const double MIN_DIST = 1. ;
const double MAX_DIST = 50. ;
double dDist = Clamp( m_TParams.m_dDiam / 2, MIN_DIST, MAX_DIST) ;
if ( ! PL.AdjustForMaxSegmentLen( dDist))
return false ;
// porto nel riferimento delle superfici
PL.LocToLoc( frPocket, frSurf) ;
// porto i dati geometrici in locale alle superfici
Vector3d vtAxL = vtTool ;
vtAxL.ToLoc( frSurf) ;
Vector3d vtMoveL = vtAxL ;
// traslo della lunghezza utensile diminuita dell'affondamento
PL.Translate( vtAxL * ( m_TParams.m_dLen - dDepth)) ;
// eseguo CAv
if ( ! pCAvTlStm->TestPath( PL.GetUPointList(), vtAxL, vtMoveL, m_Params.m_dApprox))
return false ;
// contro-traslo della lunghezza utensile
PL.Translate( - vtAxL * m_TParams.m_dLen) ;
// riporto la polilinea nel riferimento della curva
PL.LocToLoc( frSurf, frPocket) ;
// elimino i punti allineati
PL.RemoveAlignedPoints( 0.8 * m_Params.m_dApprox) ;
// creo una curva composita a partire dalla polilinea
PtrOwner< ICurveComposite> pCompo( CreateCurveComposite()) ;
if ( IsNull( pCompo) || ! pCompo->FromPolyLine( PL))
return false ;
// sostituisco la vecchia curva con la nuova
pMCrv.Set( pCompo) ;
}
// ciclo sulle curve elementari
int nMaxInd = pMCrv->GetCurveCount() - 1 ;
for ( int i = 0 ; i <= nMaxInd ; ++ i) {
// curva corrente
const ICurve* pCrvC = pMCrv->GetCurve( i) ;
// copio la curva
PtrOwner<ICurve> pCurve( pCrvC->Clone()) ;
if ( IsNull( pCurve))
return false ;
pCurve->ToGlob( frPocket) ;
// se prima entità
if ( i == 0 ) {
// dati inizio entità
Point3d ptStart ;
pCurve->GetStartPoint( ptStart) ;
Vector3d vtStart ;
pCurve->GetStartDir( vtStart) ;
// vettore tangente iniziale non deve salire rispetto a estrusione (poi si prende opposto)
double dStartOnExtr = vtStart * vtTool ;
if ( dStartOnExtr > 0) {
vtStart -= dStartOnExtr * vtTool ;
vtStart.Normalize() ;
}
// determino normale della superficie sul punto iniziale
Vector3d vtNorm ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptStart, vtTool, vtNorm)) {
Point3d ptEnd ;
pCurve->GetEndPoint( ptEnd) ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptEnd, vtTool, vtNorm))
vtNorm = V_NULL ;
}
// determino inizio attacco
Point3d ptP1 ;
if ( ! CalcLeadInStart( ptStart, vtStart, vtTool, vtNorm, ptP1))
return false ;
// eventuale correzione inizio attacco per evitare interferenze
if ( ! GetLastGoodPoint( pCAvTlStm, frSurf, ptStart, ptP1, vtTool, ptP1))
return false ;
// determino elevazione su inizio attacco
double dStElev ;
if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev))
dStElev = dElev ;
dStElev -= ( ptP1 - ptStart) * vtTool ;
// se inizio, approccio globale al punto iniziale
if ( bStart) {
if ( ! AddApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) {
m_pMchMgr->SetLastError( 3111, "Error in SurfFinishing : Approach not computable") ;
return false ;
}
bStart = false ;
}
// altrimenti, approccio di collegamento
else {
if ( ! AddLinkApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) {
m_pMchMgr->SetLastError( 3112, "Error in SurfFinishing : Link not computable") ;
return false ;
}
}
// aggiungo attacco
SetFeed( GetStartFeed()) ;
if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtTool, bSplitArcs)) {
m_pMchMgr->SetLastError( 3113, "Error in SurfFinishing : LeadIn not computable") ;
return false ;
}
}
// elaborazioni sulla curva corrente (sempre un segmento di retta)
ICurveLine* pLine = GetCurveLine( pCurve) ;
if ( pLine == nullptr)
return false ;
Point3d ptP3 = pLine->GetEnd() ;
Vector3d vtMove ; pLine->GetStartDir( vtMove) ;
SetFeed( GetRightFeed( vtMove, vtTool)) ;
if ( AddLinearMove( ptP3) == GDB_ID_NULL)
return false ;
// se ultima entità
if ( i == nMaxInd) {
// dati fine entità
Point3d ptEnd ;
pCurve->GetEndPoint( ptEnd) ;
Vector3d vtEnd ;
pCurve->GetEndDir( vtEnd) ;
// vettore tangente finale non deve scendere rispetto a estrusione
double dEndOnExtr = vtEnd * vtTool ;
if ( dEndOnExtr < 0) {
vtEnd -= dEndOnExtr * vtTool ;
vtEnd.Normalize() ;
}
// determino normale della superficie sul punto finale
Vector3d vtNorm ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptEnd, vtTool, vtNorm)) {
Point3d ptStart ;
pCurve->GetStartPoint( ptStart) ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptStart, vtTool, vtNorm))
vtNorm = V_NULL ;
}
// determino fine uscita
Point3d ptP1 ;
if ( ! CalcLeadOutEnd( ptEnd, vtEnd, vtTool, vtNorm, ptP1))
return false ;
// eventuale correzione fine uscita per evitare interferenze
if ( ! GetLastGoodPoint( pCAvTlStm, frSurf, ptEnd, ptP1, vtTool, ptP1))
return false ;
// aggiungo uscita
SetFeed( GetEndFeed()) ;
if ( ! AddLeadOut( ptEnd, vtEnd, ptP1, vtTool, bSplitArcs)) {
m_pMchMgr->SetLastError( 3114, "Error in SurfFinishing : LeadOut not computable") ;
return false ;
}
// determino elevazione su fine uscita
double dEndElev ;
if ( ! GetElevation( m_nPhase, ptEnd - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dEndElev))
dEndElev = dElev ;
dEndElev -= ( ptP1 - ptEnd) * vtTool ;
// se non è ultimo tratto, aggiungo retrazione di collegamento
if ( false) {
if ( ! AddLinkRetract( ptP1, vtTool, dSafeZ, dEndElev, dAppr)) {
m_pMchMgr->SetLastError( 3112, "Error in SurfFinishing : Link not computable") ;
return false ;
}
}
// altrimenti aggiungo retrazione finale
else {
if ( ! AddRetract( ptP1, vtTool, dSafeZ, dEndElev, dAppr)) {
m_pMchMgr->SetLastError( 3115, "Error in SurfFinishing : Retract not computable") ;
return false ;
}
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::GetZConstFacesInsideSfrParallelToTool( const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf,
const ISurfFlatRegion* pSfr, const Vector3d& vtTool,
set<double>& setZAmbiguos)
{
// controllo dei parametri
setZAmbiguos.clear() ;
if ( pSfr == nullptr || ! pSfr->IsValid())
return false ;
// creo un frame centrato sulla superficie
Frame3d frSfr ;
Point3d ptC ; pSfr->GetCentroid( ptC) ;
if ( ! frSfr.Set( ptC, pSfr->GetNormVersor()) || ! frSfr.IsValid())
return false ;
// porto una copia della superficie in questo frame
PtrOwner<ISurfFlatRegion> pSfrLoc( CloneSurfFlatRegion( pSfr)) ;
if ( IsNull( pSfrLoc) || ! pSfrLoc->IsValid() || ! pSfrLoc->ToLoc( frSfr))
return false ;
// scorro le superfici trimesh selezionate
for ( int nS = 0 ; nS < int( vSrfLoc.size()) ; ++ nS) {
// recupero la superficie
PtrOwner<ISurfTriMesh> pStm( CloneSurfTriMesh( GetSurfTriMesh( vSrfLoc[nS].Get()))) ;
if ( IsNull( pStm) || ! pStm->IsValid())
return false ;
// scorro le facce
for ( int nF = 0 ; nF < pStm->GetFacetCount() ; ++ nF) {
// recupero il centro e la normale della faccia
Point3d ptCenter ;
Vector3d vtNorm ;
if ( pStm->GetFacetCenter( nF, ptCenter, vtNorm)) {
vtNorm.ToGlob( frSurf) ;
if ( AreSameVectorEpsilon( vtNorm, vtTool, 10 * EPS_SMALL)) {
// recupero i contorni della faccia
POLYLINEVECTOR vPL ;
if ( pStm->GetFacetLoops( nF, vPL)) {
// recupero la superficie piana dalle curve
SurfFlatRegionByContours SfrByC ;
for ( int nPL = 0 ; nPL < int( vPL.size()) ; ++ nPL) {
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
if ( IsNull( pCrvCompo) || ! pCrvCompo->FromPolyLine( vPL[nPL]))
return false ;
// porto la curva nel riferimento globale
pCrvCompo->ToGlob( frSurf) ;
// porto la curva nel riferimento della pSfr (per la classificazione)
pCrvCompo->ToLoc( frSfr) ;
// aggiungo la curva alla FlatRegion
SfrByC.AddCurve( Release( pCrvCompo)) ;
}
// recupero la superficie
PtrOwner<ISurfFlatRegion> pSfrFace( SfrByC.GetSurf()) ;
if ( IsNull( pSfrFace) || ! pSfrFace->IsValid()) {
// in questo caso potrei avere goemtrie complesse per le facce della pStm
// inserisco la Z del piano locale nell'insieme
setZAmbiguos.insert( ptCenter.z) ;
continue ;
}
// se esiste intersezione tra pSfrFace e pSfr allora salvo la Z locale
pSfrFace->Intersect( *pSfrLoc) ;
if ( ! IsNull( pSfrFace) && pSfrFace->IsValid()) {
// porto il punto nel riferimento della superficie
ptCenter.ToGlob( frSurf) ;
ptCenter.ToLoc( frSfr) ;
// inserisco la Z del piano locale nell'insieme
setZAmbiguos.insert( ptCenter.z) ;
}
}
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
ICAvParSilhouettesSurfTm*
SurfFinishing::GetParSilhouettesForZConst( const ISURFTMPOVECTOR& vStm, const ISurfFlatRegion* pSfr) const
{
// controllo dei parametri
if ( vStm.empty() || pSfr == nullptr || ! pSfr->IsValid())
return nullptr ;
// inizializzo la classe di calcolo delle silhouette nei piani come sopra
CISURFTMPVECTOR vpStm ; vpStm.reserve( vStm.size()) ;
for ( int i = 0 ; i < int( vStm.size()) ; ++ i)
vpStm.emplace_back( vStm[i]) ;
const double SILH_SHARPED_ANG_TOL = ANG_TOL_STD_DEG ;
PtrOwner<ICAvParSilhouettesSurfTm> pCavParSilh( CreateCAvParSilhouettesSurfTm()) ;
if ( IsNull( pCavParSilh) ||
! pCavParSilh->SetDataForRegion( vpStm, pSfr, m_TParams.m_dSideAng, m_TParams.m_dDiam,
m_TParams.m_dCornRad, m_TParams.m_dMaxMat, GetOffsR(), SILH_SAMPLING, SILH_SHARPED_ANG_TOL))
return nullptr ;
return ( Release( pCavParSilh)) ;
}
//----------------------------------------------------------------------------
ISurfFlatRegion*
SurfFinishing::GetSfrSilhouette( const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const Frame3d& frPocket,
double dDepth) const
{
// inizializzo vettore di puntatori a superfici costanti
CISURFTMPVECTOR vpStm ; vpStm.reserve( vSrfLoc.size()) ;
// scorro le superfici
for ( int i = 0 ; i < int( vSrfLoc.size()) ; ++ i) {
// recupero la superficie TriMesh
const ISurfTriMesh* pStm = GetSurfTriMesh( vSrfLoc[i].Get()) ;
// se valida, la memorizzo
if ( pStm != nullptr && pStm->IsValid() && pStm->GetTriangleCount() > 0)
vpStm.emplace_back( pStm) ;
}
// inizializzo classe di calcolo della silhouette
const double SILH_TOL = 1.0 ;
Frame3d frCurr = frPocket ;
frCurr.ToLoc( frSurf) ;
PtrOwner<ICAvParSilhouettesSurfTm> pCavParSilh( CreateCAvParSilhouettesSurfTm()) ;
if ( IsNull( pCavParSilh) || ! pCavParSilh->SetData( vpStm, frCurr, SILH_TOL))
return nullptr ;
// vettore di PolyLine
POLYLINEVECTOR vPL ;
if ( ! pCavParSilh->GetSilhouette( dDepth, vPL))
return nullptr ;
// creo la regione piana dalle PolyLine ricavate dalla Silhouette
SurfFlatRegionByContours SfrMaker ;
for ( auto& PL : vPL) {
// recupero la curva dalla silhouette
PtrOwner<ICurveComposite> pSilCrv( CreateCurveComposite()) ;
if ( IsNull( pSilCrv))
return nullptr ;
pSilCrv->FromPolyLine( PL) ;
// approssimo con archi
const double SILH_ARC_TOL = 100 * EPS_SMALL ;
const double SILH_ARC_FEA_MAX = 100. ;
PolyArc PA ;
if ( pSilCrv->ApproxWithArcsEx( SILH_ARC_TOL, ANG_TOL_STD_DEG, SILH_ARC_FEA_MAX, PA)) {
PtrOwner<ICurveComposite> pTempCrv( CreateCurveComposite()) ;
if ( ! IsNull( pTempCrv) &&
pTempCrv->FromPolyArc( PA) &&
pTempCrv->RemoveSmallDefects( SILH_ARC_TOL / 2, ANG_TOL_STD_DEG) &&
pTempCrv->MergeCurves( SILH_ARC_TOL / 2, ANG_TOL_STD_DEG))
pSilCrv.Set( pTempCrv) ;
}
pSilCrv->ToGlob( frSurf) ;
// aggiungo per regione
if ( ! SfrMaker.AddCurve( Release( pSilCrv)))
return nullptr ;
}
return ( SfrMaker.GetSurf()) ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::CalcZConstSilCrv( ICAvParSilhouettesSurfTm* pCavParSilh, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfr,
const Vector3d& vtTool, double dDepth, vector<ICRVCOMPOPOVECTOR>& vCrvCompo)
{
/* funzione per calcolare le curve singole di finitura mediante Silhouette e le regioni da non rovinare */
// controllo che la regione piana sia definita correttamente
vCrvCompo.clear() ;
if ( pSfr == nullptr || ! pSfr->IsValid())
return false ;
// NB. Essendo una finitura a Z costante, devo controllare che i piani di finitura non facciano
// overlap con facce delle TriMesh selezionate con normale simile a vtTool
set<double> setZAmbiguos ;
PtrOwner<ISurfFlatRegion> pSfrZAmb( CloneSurfFlatRegion( pSfr)) ;
if ( IsNull( pSfrZAmb) || ! pSfrZAmb->IsValid() ||
! pSfrZAmb->Offset( m_TParams.m_dDiam / 2. + abs( m_Params.m_dOverlap), ICurve::OFF_FILLET))
return false ;
if ( ! GetZConstFacesInsideSfrParallelToTool( vSrfLoc, frSurf, pSfrZAmb, vtTool, setZAmbiguos))
return false ;
// aggiorno la ProgressBar al 40%
ExeProcessEvents( 40, 0) ;
// calcolo la silhouette sui diversi piani
for ( int nPlane = 1 ; nPlane * m_Params.m_dSideStep < dDepth + EPS_SMALL ; ++ nPlane) {
// riservo lo spazio nel vettore delle curve
vCrvCompo.resize( vCrvCompo.size() + 1) ;
// definisco la Zlocale per il calcolo della silhouette
double dZLoc = - nPlane * m_Params.m_dSideStep ;
for ( set<double>::iterator it = setZAmbiguos.begin() ; it != setZAmbiguos.end() ; ++ it) {
if ( abs( *it - dZLoc) < 5 * EPS_SMALL)
dZLoc += ( nPlane == 1 ? - 10 * EPS_SMALL : + 10 * EPS_SMALL) ;
}
// calcolo vettore di PolyLine ottenute al piano corrente
POLYLINEVECTOR vPL ;
if ( ! pCavParSilh->GetSilhouetteInsideRegion( dZLoc, vPL))
return false ;
for ( auto& PL : vPL) {
// recupero la curva dalla silhouette
PtrOwner<ICurveComposite> pSilCrv( CreateCurveComposite()) ;
if ( IsNull( pSilCrv))
return false ;
pSilCrv->FromPolyLine( PL) ;
// approssimo con archi
const double SILH_ARC_TOL = 0.1 * SILH_SAMPLING ;
const double SILH_ARC_FEA_MAX = 100. ;
PolyArc PA ;
if ( pSilCrv->ApproxWithArcsEx( SILH_ARC_TOL, ANG_TOL_STD_DEG, SILH_ARC_FEA_MAX, PA)) {
PtrOwner<ICurveComposite> pTempCrv( CreateCurveComposite()) ;
if ( ! IsNull( pTempCrv) &&
pTempCrv->FromPolyArc( PA) &&
pTempCrv->RemoveSmallDefects( SILH_ARC_TOL / 2., ANG_TOL_STD_DEG) &&
pTempCrv->MergeCurves( SILH_ARC_TOL / 2., ANG_TOL_STD_DEG))
pSilCrv.Set( pTempCrv) ;
}
SimplifyCurve( pSilCrv) ;
vCrvCompo.back().emplace_back( Release( pSilCrv)) ;
}
// controllo validità delle curve
for ( int i = 0 ; i < int( vCrvCompo.back().size()) ; ++ i)
if ( vCrvCompo.back()[i] == nullptr || ! vCrvCompo.back()[i]->IsValid())
return false ;
// preparo i dati per il concatenamento
bool bFirst = true ;
Point3d ptNear = ORIG ;
double dToler = 500 * EPS_SMALL ;
ChainCurves chainC ;
chainC.Init( false, dToler, int( vCrvCompo.back().size())) ;
for ( int i = 0 ; i < int( vCrvCompo.back().size()) ; ++ i) {
// recupero i dati della curva necessari al concatenamento e li assegno
Point3d ptStart, ptEnd ;
Vector3d vtStart, vtEnd ;
if ( ! vCrvCompo.back()[i]->GetStartPoint( ptStart) || ! vCrvCompo.back()[i]->GetStartDir( vtStart) ||
! vCrvCompo.back()[i]->GetEndPoint( ptEnd) || ! vCrvCompo.back()[i]->GetEndDir( vtEnd))
return false ;
if ( ! chainC.AddCurve( int( i + 1), ptStart, vtStart, ptEnd, vtEnd))
return false ;
// se prima curva, assegno inizio della ricerca
if ( bFirst) {
ptNear = ptStart + 10 * EPS_SMALL * vtStart ;
bFirst = false ;
}
}
// vettore delle curve composite risultante
ICRVCOMPOPOVECTOR vCrvCompoChained ;
// recupero i percorsi concatenati
INTVECTOR vnInd ;
while ( chainC.GetChainFromNear( ptNear, true, vnInd)) {
// creo una curva composita
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
if ( IsNull( pCrvCompo))
return false ;
// recupero le curve semplici e le inserisco nella curva composita
for ( size_t i = 0 ; i < vnInd.size() ; ++ i) {
int nId = abs( vnInd[i]) - 1 ;
// la aggiungo alla curva composta
if ( ! pCrvCompo->AddCurve( CloneCurveComposite( vCrvCompo.back()[nId]), true, dToler))
return false ;
}
// aggiorno il nuovo punto vicino
if ( pCrvCompo->GetCurveCount() > 0) {
pCrvCompo->GetEndPoint( ptNear) ;
vCrvCompoChained.emplace_back( Release( pCrvCompo)) ;
}
}
swap( vCrvCompoChained, vCrvCompo.back()) ;
// salvo lo Step come primo temp param della curva e inverto se necessario
for ( int i = 0 ; i < int( vCrvCompo.back().size()) ; ++ i) {
vCrvCompo.back()[i]->SetTempParam( - nPlane * m_Params.m_dSideStep, 0) ;
if ( m_Params.m_bInvert)
vCrvCompo.back()[i]->Invert() ;
}
// aggiorno la ProgressBar
ExeProcessEvents( 40 + int( 40 / ( dDepth / max( 0.1, m_Params.m_dSideStep)) * ( nPlane - 1)), 0) ;
}
// controllo la validità di tutte le curve trovate
for ( int i = 0 ; i < int( vCrvCompo.size()) ; ++ i) {
for ( int j = 0 ; j < int( vCrvCompo[i].size()) ; ++ j) {
if ( vCrvCompo[i][j] == nullptr || ! vCrvCompo[i][j]->IsValid())
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf,
vector<ICRVCOMPOPOVECTOR>& vCrvCompo, const Vector3d& vtTool, const ISurfFlatRegion* pSfr,
double dDepth, ICRVCOMPOPOVECTOR& vCrvPath)
{
/* funzione per collegare le curve trovate creando quindi i percorsi di lavoro */
// NB. La prima tempProp della curva è il piano in cui iniziale e la seconda tempProp è
// il piano a cui finisce
// controllo dei parametri
if ( pSfr == nullptr || ! pSfr->IsValid())
return false ;
PtrOwner<ISurfFlatRegion> pSfrClass( CloneSurfFlatRegion( pSfr)) ;
if ( IsNull( pSfrClass) || ! pSfrClass->IsValid())
return false ;
// porto tutte le curve nel piano XY locale alla pSfr
Frame3d frXY ;
Point3d ptCenter ; pSfr->GetCentroid( ptCenter) ;
if ( ! frXY.Set( ptCenter, vtTool))
return false ;
for ( int i = 0 ; i < int( vCrvCompo.size()) ; ++ i) {
for ( int j = 0 ; j < int( vCrvCompo[i].size()) ; ++ j) {
vCrvCompo[i][j]->ToLoc( frXY) ;
#if ENABLE_ZCONST_DEBUG
int _a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vCrvCompo[i][j]->Clone()) ;
m_pGeomDB->SetMaterial( _a, WHITE) ;
#endif
}
}
// tengo una copia dei bordi della regione
pSfrClass->ToLoc( frXY) ;
#if ENABLE_ZCONST_DEBUG
int _a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrClass->Clone()) ;
m_pGeomDB->SetMaterial( _a, Color( 0., 1., 0., .15)) ;
#endif
ICRVCOMPOPOVECTOR vCrvSfrLoops ;
for ( int nC = 0 ; nC < pSfrClass->GetChunkCount() ; ++ nC) {
for ( int nL = 0 ; nL < pSfrClass->GetLoopCount( nC) ; ++ nL) {
PtrOwner<ICurveComposite> pCrvLoop( ConvertCurveToComposite( pSfrClass->GetLoop( nC, nL))) ;
if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid())
return false ;
// tutti i loop sono orientati come il loop esterno ( aiuta per la classificazione della curve)
if ( nL > 0)
pCrvLoop->Invert() ;
vCrvSfrLoops.emplace_back( Release( pCrvLoop)) ;
#if ENABLE_ZCONST_DEBUG
int _a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vCrvSfrLoops.back()->Clone()) ;
m_pGeomDB->SetMaterial( _a, PURPLE) ;
#endif
}
}
// definisco il piano locale della regione piana
Plane3d plProjection ;
if ( ! plProjection.Set( ORIG, Z_AX))
return false ;
int nCurrRow = 0 ;
// scorro le righe
for ( ; nCurrRow < int( vCrvCompo.size()) - 1 ; ++ nCurrRow) {
// scorro sulle colonne
for ( int nCurrCol = 0 ; nCurrCol < int( vCrvCompo[nCurrRow].size()) ; ++ nCurrCol) {
// se la curva attuale è nulla, passo alla successiva
if ( vCrvCompo[nCurrRow][nCurrCol] == nullptr)
continue ;
// recupero il punto finale della curva corrente
Point3d ptCurrEnd ; vCrvCompo[nCurrRow][nCurrCol]->GetEndPoint( ptCurrEnd) ;
// recupero la distanza con la Sfr
double dSfrDistCurr = vCrvCompo[nCurrRow][nCurrCol]->GetTempParam( 0) ;
// inizializzo spazio per un nuovo percorso ( inserisco la curva corrente)
vCrvPath.resize( vCrvPath.size() + 1) ;
vCrvPath.back().Set( vCrvCompo[nCurrRow][nCurrCol]) ;
// salvo come prima temp prop il numero del piano a cui sono
vCrvPath.back()->SetTempProp( nCurrRow + 1, 0) ;
// scorro sulle righe successive
for ( int nNextRow = nCurrRow + 1 ; nNextRow < int( vCrvCompo.size()) ; ++ nNextRow) {
// cerco le curve valide tra le colonne
double dMinSqDist = INFINITO ; // euristico
int nNextCol_path = -1 ;
for ( int nNextCol = 0 ; nNextCol < int( vCrvCompo[nNextRow].size()) ; ++ nNextCol) {
// se curva già in un Path, cerco la successiva
if ( vCrvCompo[nNextRow][nNextCol] == nullptr)
continue ;
// se la curva successiva è aperta
if ( ! vCrvCompo[nNextRow][nNextCol]->IsClosed()) {
// controllo la distanza con il punto iniziale della curva
Point3d ptS ; vCrvCompo[nNextRow][nNextCol]->GetStartPoint( ptS) ;
double dNextSqDist = SqDist( ptS, ptCurrEnd) ;
if ( dNextSqDist < dMinSqDist) {
dMinSqDist = dNextSqDist ;
nNextCol_path = nNextCol ;
}
// controllo la distanza con il punto finale della curva
Point3d ptE ; vCrvCompo[nNextRow][nNextCol]->GetEndPoint( ptE) ;
dNextSqDist = SqDist( ptE, ptCurrEnd) ;
if ( dNextSqDist < dMinSqDist) {
dMinSqDist = dNextSqDist ;
nNextCol_path = nNextCol ;
vCrvCompo[nNextRow][nNextCol]->Invert() ; // inverto
}
}
// se la curva successiva è chiusa
else {
// cerco il punto a minima distanza
DistPointCurve DistPtCrv( ptCurrEnd, *vCrvCompo[nNextRow][nNextCol]) ;
double dNextSqDist = 0. ;
if ( DistPtCrv.GetSqDist( dNextSqDist)) {
if ( dNextSqDist < dMinSqDist) {
dMinSqDist = dNextSqDist ;
nNextCol_path = nNextCol ;
double dMinPar = 0. ;
int nFlag = 0 ;
if ( DistPtCrv.GetParamAtMinDistPoint( 0., dMinPar, nFlag))
vCrvCompo[nNextRow][nNextCol]->ChangeStartPoint( dMinPar) ;
}
}
}
}
// se non ho trovato nessuna colonna valida
if ( nNextCol_path == -1) {
nCurrRow = 0 ; // azzero il contatore delle righe
break ; // interrompo ciclo sulle righe successive di ricerca
}
// altrimenti creo raccordo e aggiungo la curva al percorso
else {
// definisco un tratto lineare che collega gli estremi
Point3d ptStartLink = ptCurrEnd ;
Point3d ptEndLink ; vCrvCompo[nNextRow][nNextCol_path]->GetStartPoint( ptEndLink) ;
// se i punti sono distanti, allora non considero valido il collegamento
if ( SqDist( ptStartLink, ptEndLink) > m_TParams.m_dDiam * 2) {
nCurrRow = 0 ; // azzero il contatore delle righe
break ; // interrompo ciclo sulle righe successive di ricerca
}
PtrOwner<ICurveLine> pLineLink( CreateCurveLine()) ;
if ( IsNull( pLineLink) || ! pLineLink->Set( ptStartLink, ptEndLink) ||
! pLineLink->IsValid())
return false ;
#if ENABLE_ZCONST_DEBUG
int _b = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pLineLink->Clone()) ;
m_pGeomDB->SetMaterial( _b, ORANGE) ;
#endif
// se la linea è parallela a vtTool( Z_AX), allora ho una parete verticale (localmente)
Vector3d vtLineLink ; pLineLink->GetStartDir( vtLineLink) ;
if ( AreSameOrOppositeVectorEpsilon( vtLineLink, Z_AX, 100 * EPS_SMALL)) {
// in questo caso la proiezione del link è automaticamente sul bordo della pSrfClass
vCrvPath.back()->AddCurve( Release( pLineLink), true, 1500 * EPS_SMALL) ;
vCrvPath.back()->AddCurve( Release( vCrvCompo[nNextRow][nNextCol_path]), true, 1500 * EPS_SMALL) ;
}
// se il collegamento non è parallelo a vtTool (Z_AX)
else {
// in questo caso proietto la curva nel piano locale della pSfrClass ( Z=0 ; Z_AX)
PtrOwner<ICurve> pLineLinkProjected( ProjectCurveOnPlane( *pLineLink, plProjection)) ;
if ( IsNull( pLineLinkProjected) || ! pLineLinkProjected->IsValid())
return false ;
#if ENABLE_ZCONST_DEBUG
int _c = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pLineLinkProjected->Clone()) ;
m_pGeomDB->SetMaterial( _c, YELLOW) ;
#endif
// classifico la curva proiettata in base alla superficie
CRVCVECTOR ccClass ;
if ( ! pSfrClass->GetCurveClassification( *pLineLinkProjected, EPS_SMALL, ccClass))
return false ;
// inizializzo la nuova curva di Link
PtrOwner<ICurveComposite> pCompoLink( CreateCurveComposite()) ;
if ( IsNull( pCompoLink))
return false ;
// scorro sulle classificazioni ottenute
for ( int i = 0 ; i < int( ccClass.size()) ; ++ i) {
// recupero il tratto di curva corrente
PtrOwner<ICurve> pCrv( pLineLinkProjected->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE)) ;
if ( IsNull( pCrv) || ! pCrv->IsValid()) // troppo piccolo...
continue ; // passo al tratto di classificazione successivo
// se la curva non è esterna alla regione, allora la conservo (non rivina le Stm)
if ( ccClass[i].nClass != CRVC_OUT) {
if ( ! pCompoLink->AddCurve( Release( pCrv), true, 25 * EPS_SMALL))
return false ;
}
// se la curva è esterna, allora devo seguire il bordo della regione di classificazione
else {
// recupero gli estremi del segmento di classificazione esterno alla pSfrClass
Point3d ptS_sfr ; pLineLinkProjected->GetPointD1D2( ccClass[i].dParS, ICurve::FROM_MINUS, ptS_sfr) ;
Point3d ptE_sfr ; pLineLinkProjected->GetPointD1D2( ccClass[i].dParE, ICurve::FROM_MINUS, ptE_sfr) ;
// scorro tutti i loop della regione di classificazione
for ( int j = 0 ; j < int( vCrvSfrLoops.size()) ; ++ j) {
// se i punti trovati sono sul loop corrente
if ( vCrvSfrLoops[j]->IsPointOn( ptS_sfr, 25 * EPS_SMALL) &&
vCrvSfrLoops[j]->IsPointOn( ptE_sfr, 25 * EPS_SMALL)) {
// devo capire quale delle due curve (pCrvA, pCrvB) devo seguire sul bordo
double dUS ; vCrvSfrLoops[j]->GetParamAtPoint( ptS_sfr, dUS, 25 * EPS_SMALL) ;
double dUE ; vCrvSfrLoops[j]->GetParamAtPoint( ptE_sfr, dUE, 25 * EPS_SMALL) ;
PtrOwner<ICurveComposite> pCrvA( ConvertCurveToComposite( vCrvSfrLoops[j]->CopyParamRange( dUS, dUE))) ;
PtrOwner<ICurveComposite> pCrvB( ConvertCurveToComposite( vCrvSfrLoops[j]->CopyParamRange( dUE, dUS))) ;
// tra le due curve (pCrvA, pCrvB) scelgo quella con lunghezza minore
double dLenA = INFINITO ; double dLenB = INFINITO ;
if ( ! IsNull( pCrvA) && pCrvA->IsValid())
pCrvA->GetLength( dLenA) ;
if ( ! IsNull( pCrvB) && pCrvB->IsValid()) {
// la pCrvB è sempre percorsa in senso opposto
pCrvB->Invert() ;
pCrvB->GetLength( dLenB) ;
}
// aggiungo la curva
if ( ! pCompoLink->AddCurve( dLenA < dLenB ? Release( pCrvA) : Release( pCrvB), true, 25 * EPS_SMALL))
return false ;
}
}
}
}
// se il link trovato non è valido, errore
if ( ! pCompoLink->IsValid())
return false ;
// porto il link sulla curva attuale di silhouette e lo proietto sulla pStm (sono in locale)
double dSfrDistNext = vCrvCompo[nNextRow][nNextCol_path]->GetTempParam( 0) ;
pCompoLink->Translate( Z_AX * min( dSfrDistCurr, dSfrDistNext)) ;
#if ENABLE_ZCONST_DEBUG
int _d = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompoLink->Clone()) ;
m_pGeomDB->SetMaterial( _d, LIME) ;
#endif
if ( ! CalcZConstProjectedLink( pCAvTlStm, frXY, frSurf, vtTool, dDepth, ptStartLink, ptEndLink, pCompoLink))
return false ;
#if ENABLE_ZCONST_DEBUG
int _e = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompoLink->Clone()) ;
m_pGeomDB->SetMaterial( _e, RED) ;
#endif
// aggiungo le curve ritrovate al percorso attuale
if ( ! vCrvPath.back()->AddCurve( Release( pCompoLink), true, 1500 * EPS_SMALL) ||
! vCrvPath.back()->AddCurve( Release( vCrvCompo[nNextRow][nNextCol_path]), true, 1500 * EPS_SMALL))
return false ;
}
vCrvPath.back()->GetEndPoint( ptCurrEnd) ; // aggiorno il punto finale del percorso
vCrvPath.back()->SetTempProp( nNextRow + 1, 1) ; // salvo come seconda temp prop il piano a cui sono
}
}
}
}
// se non ho percorsi, non faccio nulla
if ( vCrvPath.empty())
return true ;
// se ho percorsi non validi, errore
for ( int i = 0 ; i < int( vCrvPath.size()) ; ++ i) {
if ( vCrvPath[i] == nullptr || ! vCrvPath[i]->IsValid())
return false ;
}
// preso come riferimento il primo percorso, ordino i successivi in base alla vicinanza
Point3d ptRef ; vCrvPath.front()->GetEndPoint( ptRef) ;
double dSqMaxDist = INFINITO ;
for ( int i = 1 ; i < int( vCrvPath.size()) ; ++ i) {
int nNextInd = i + 1 ;
for ( int j = nNextInd ; j < int( vCrvPath.size()) ; ++ j) {
Point3d ptS ; vCrvPath[j]->GetStartPoint( ptS) ;
double dCurrSqDist = SqDist( ptS, ptRef) ;
if ( dCurrSqDist < dSqMaxDist) {
dSqMaxDist = dCurrSqDist ;
nNextInd = j ;
}
}
if ( nNextInd != i + 1)
swap( vCrvPath[i], vCrvPath[nNextInd]) ;
dSqMaxDist = INFINITO ;
}
// riporto i percorsi nel frame originale
for ( int i = 0 ; i < int( vCrvPath.size()) ; ++ i)
vCrvPath[i]->ToGlob( frXY) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::CalcZConstProjectedLink( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frPocket,
const Frame3d& frSurf, const Vector3d& vtTool, double dDepth,
const Point3d ptStart_forced, const Point3d ptEnd_forced,
ICurveComposite* pCrv)
{
// funzione per proiettare una curva su una supericie trimesh passando per la silhouette
// controllo dei parametri
if ( pCAvTlStm == nullptr ||
pCrv == nullptr || ! pCrv->IsValid())
return false ;
// approssimo la curva con una polilinea
PolyLine PL ;
if ( ! pCrv->ApproxWithLines( m_Params.m_dApprox, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL))
return false ;
// eventuale aggiunta di punti per garantire max distanza
const double MIN_DIST = 1. ;
const double MAX_DIST = 50. ;
double dDist = Clamp( m_TParams.m_dDiam / 2, MIN_DIST, MAX_DIST) ;
if ( ! PL.AdjustForMaxSegmentLen( dDist))
return false ;
// porto nel riferimento delle superfici
PL.LocToLoc( frPocket, frSurf) ;
// porto i dati geometrici in locale alle superfici
Vector3d vtAxL = vtTool ;
vtAxL.ToLoc( frSurf) ;
Vector3d vtMoveL = vtAxL ;
// traslo della lunghezza utensile diminuita dell'affondamento
PL.Translate( vtAxL * ( m_TParams.m_dLen - dDepth)) ;
// eseguo il test del percorso ( CONTROLLARE PROGRESS BAR DENTRO QUESTA FUNZIONE)
if ( ! pCAvTlStm->TestPath( PL.GetUPointList(), vtAxL, vtMoveL, m_Params.m_dApprox))
return false ;
// contro-traslo della lunghezza utensile
PL.Translate( - vtAxL * m_TParams.m_dLen) ;
// riporto la polilinea nel riferimento della curva
PL.LocToLoc( frSurf, frPocket) ;
// elimino i punti allineati
PL.RemoveAlignedPoints( 0.8 * m_Params.m_dApprox) ;
// sostituisco primo ed ultimo punto con quelli forzati
PL.EraseFirstUPoint() ;
PL.EraseLastUPoint() ;
PL.AddUPoint( 0, ptStart_forced, false) ;
PL.AddUPoint( PL.GetPointNbr(), ptEnd_forced, true) ;
// controllo di non essere sceso oltre la depth (il link non per forza è vicino ad una curva di livello)
PNTULIST& myPtUList = PL.GetUPointList() ;
for ( POINTU& myPtU : myPtUList) {
if ( myPtU.first.z < - dDepth)
myPtU.first.z = - dDepth ;
}
// creo una curva composita a partire dalla polilinea
PtrOwner< ICurveComposite> pCompo( CreateCurveComposite()) ;
if ( IsNull( pCompo) || ! pCompo->FromPolyLine( PL))
return false ;
// sostituisco la vecchia curva con la nuova
pCrv->CopyFrom( pCompo) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::AddZConst( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfr,
const Vector3d& vtTool, double dDepth, double dElev, bool bSplitArcs)
{
// controllo che la regione sia definita correttamente
if ( pSfr == nullptr || ! pSfr->IsValid())
return false ;
// aggiorno la ProgressBar del 5% per simulare l'inizio della funzione
ExeProcessEvents( 5, 0) ;
// aggiusto la regione a seconda dei parametri
PtrOwner<ISurfFlatRegion> pSfrClass( pSfr->CreateOffsetSurf( - m_TParams.m_dDiam / 2. + m_Params.m_dOverlap, ICurve::OFF_FILLET)) ;
if ( IsNull( pSfrClass) || ! pSfrClass->IsValid())
return false ;
// inizializzo la classe di calcolo delle silhouette nei piani come sopra
ISURFTMPOVECTOR vpStm ; vpStm.reserve( vSrfLoc.size()) ;
for ( int i = 0 ; i < int( vSrfLoc.size()) ; ++ i) {
PtrOwner<ISurfTriMesh> pStm( CloneSurfTriMesh( GetSurfTriMesh( vSrfLoc[i].Get()))) ;
if ( ! IsNull( pStm) && pStm->IsValid() && pStm->GetTriangleCount() > 0) {
pStm->ToGlob( frSurf) ;
vpStm.emplace_back( Release( pStm)) ;
}
}
PtrOwner<ICAvParSilhouettesSurfTm> pCavParSilh( GetParSilhouettesForZConst( vpStm, pSfrClass)) ;
if ( IsNull( pCavParSilh))
return false ;
// aggiorno la ProgressBar al 40% per simulare l'inizio della funzione
ExeProcessEvents( 30, 0) ;
// recupero le curve singole definite dal bordo della Silhouette
vector<ICRVCOMPOPOVECTOR> vCrvCompo ;
if ( ! CalcZConstSilCrv( pCavParSilh, vSrfLoc, frSurf, pSfrClass, vtTool, dDepth, vCrvCompo)) {
m_pMchMgr->SetLastError( 3126, "Error in SurfFinishing : Computing ZConst Curves failed") ;
return false ;
}
// se non ho curve, esco
bool bNoCrv = true ;
for ( int i = 0 ; i < int( vCrvCompo.size()) && bNoCrv ; ++ i)
bNoCrv = ( vCrvCompo[i].empty()) ;
if ( bNoCrv)
return true ;
// collego tra loro le curve trovate
ICRVCOMPOPOVECTOR vCrvPath ;
if ( ! CreateZConstPaths( pCAvTlStm, frSurf, vCrvCompo, vtTool, pSfrClass, dDepth, vCrvPath)) {
m_pMchMgr->SetLastError( 3127, "Error in SurfFinishing : Computing ZConst Paths failed") ;
return false ;
}
// se non ho percorsi, errore
if ( vCrvPath.empty())
return false ;
ExeProcessEvents( 90, 0) ;
// recupero distanze di sicurezza
double dSafeZ = GetSafeZ() ;
// lunghezza di approccio/retrazione
double dAppr = m_Params.m_dStartPos ;
// ciclo sulle curve risultanti
bool bStart = true ;
for ( int k = 0 ; k < int( vCrvPath.size()) ; ++ k) {
// determino in che piano di partenza e il piano di arrivo
int nStartPlane = vCrvPath[k]->GetTempProp( 0) ;
int nEndPlane = vCrvPath[k]->GetTempProp( 1) ;
// ciclo sulle curve elementari
int nMaxInd = vCrvPath[k]->GetCurveCount() - 1 ;
for ( int i = 0 ; i <= nMaxInd ; ++ i) {
// curva corrente
const ICurve* pCrvC = vCrvPath[k]->GetCurve( i) ;
// copio la curva
PtrOwner<ICurve> pCurve( pCrvC->Clone()) ;
if ( IsNull( pCurve))
return false ;
// se prima entità
if ( i == 0) {
// dati inizio entità
Point3d ptStart ; pCurve->GetStartPoint( ptStart) ;
Vector3d vtStart ; pCurve->GetStartDir( vtStart) ;
// vettore tangente iniziale non deve salire rispetto a estrusione (poi si prende opposto)
double dStartOnExtr = vtStart * vtTool ;
if ( dStartOnExtr > 0) {
vtStart -= dStartOnExtr * vtTool ;
vtStart.Normalize() ;
}
// determino normale della superficie sul punto iniziale
Vector3d vtNorm ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptStart, vtTool, vtNorm)) {
Point3d ptEnd ;
pCurve->GetEndPoint( ptEnd) ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptEnd, vtTool, vtNorm))
vtNorm = V_NULL ;
}
// determino inizio attacco
Point3d ptP1 ;
if ( ! CalcLeadInStart( ptStart, vtStart, vtTool, vtNorm, ptP1))
return false ;
// eventuale correzione inizio attacco per evitare interferenze
if ( ! GetLastGoodPoint( pCAvTlStm, frSurf, ptStart, ptP1, vtTool, ptP1))
return false ;
// controllo che tale punto sia al di fuori della regione piana
bool bIsInside = false ;
if ( IsPointInsideSurfFr( ptP1 + vtTool * ( m_Params.m_dSideStep * nStartPlane), pSfrClass, EPS_SMALL, bIsInside))
ptP1 = ptStart ;
// determino elevazione su inizio attacco
double dStElev ;
if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev))
dStElev = dElev ;
dStElev -= ( ptP1 - ptStart) * vtTool ;
// se inizio, approccio globale al punto iniziale
if ( bStart) {
if ( ! AddApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) {
m_pMchMgr->SetLastError( 3111, "Error in SurfFinishing : Approach not computable") ;
return false ;
}
bStart = false ;
}
// altrimenti, approccio di collegamento
else {
if ( ! AddLinkApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) {
m_pMchMgr->SetLastError( 3112, "Error in SurfFinishing : Link not computable") ;
return false ;
}
}
// aggiungo attacco
SetFeed( GetStartFeed()) ;
if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtTool, bSplitArcs)) {
m_pMchMgr->SetLastError( 3113, "Error in SurfFinishing : LeadIn not computable") ;
return false ;
}
}
// elaborazioni sulla curva corrente (sempre un segmento di retta)
if ( pCurve->GetType() == CRV_LINE) {
ICurveLine* pLine = GetCurveLine( pCurve) ;
Point3d ptP3 = pLine->GetEnd() ;
Vector3d vtMove ; pLine->GetStartDir( vtMove) ;
SetFeed( GetRightFeed( vtMove, vtTool)) ;
if ( AddLinearMove( ptP3) == GDB_ID_NULL)
return false ;
}
else if ( pCurve->GetType() == CRV_ARC) {
ICurveArc* pArc = GetCurveArc( pCurve) ;
Point3d ptCen = pArc->GetCenter() ;
double dAngCen = pArc->GetAngCenter() ;
Vector3d vtN = pArc->GetNormVersor() ;
Point3d ptP3 ; pArc->GetEndPoint( ptP3) ;
SetFeed( GetFeed()) ;
if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL)
return false ;
}
// se ultima entità
if ( i == nMaxInd) {
// dati fine entità
Point3d ptEnd ; pCurve->GetEndPoint( ptEnd) ;
Vector3d vtEnd ; pCurve->GetEndDir( vtEnd) ;
// vettore tangente finale non deve scendere rispetto a estrusione
double dEndOnExtr = vtEnd * vtTool ;
if ( dEndOnExtr < 0) {
vtEnd -= dEndOnExtr * vtTool ;
vtEnd.Normalize() ;
}
// determino normale della superficie sul punto finale
Vector3d vtNorm ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptEnd, vtTool, vtNorm)) {
Point3d ptStart ;
pCurve->GetStartPoint( ptStart) ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptStart, vtTool, vtNorm))
vtNorm = V_NULL ;
}
// determino fine uscita
Point3d ptP1 ;
if ( ! CalcLeadOutEnd( ptEnd, vtEnd, vtTool, vtNorm, ptP1))
return false ;
// eventuale correzione fine uscita per evitare interferenze
if ( ! GetLastGoodPoint( pCAvTlStm, frSurf, ptEnd, ptP1, vtTool, ptP1))
return false ;
// controllo che tale punto sia al di fuori della regione piana
bool bIsInside = false ;
if ( IsPointInsideSurfFr( ptP1 + vtTool * ( m_Params.m_dSideStep * nStartPlane), pSfrClass, EPS_SMALL, bIsInside))
ptP1 = ptEnd ;
// se ultima uscita globale del percorso
if ( k == int( vCrvPath.size()) - 1) {
// aggiungo LeadOut
SetFeed( GetEndFeed()) ;
if ( ! AddLeadOut( ptEnd, vtEnd, ptP1, vtTool, bSplitArcs)) {
m_pMchMgr->SetLastError( 3114, "Error in SurfFinishing : LeadOut not computable") ;
return false ;
}
// aggiungo retroazione finale
if ( ! AddRetract( ptP1, vtTool, dSafeZ, nEndPlane * m_Params.m_dSideStep, dAppr)) {
m_pMchMgr->SetLastError( 3115, "Error in SurfFinishing : Retract not computable") ;
return false ;
}
}
// altrimenti
else {
// determino elevazione su fine uscita
double dEndElev ;
if ( ! GetElevation( m_nPhase, ptEnd - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dEndElev))
dEndElev = dElev ;
dEndElev -= ( ptP1 - ptEnd) * vtTool ;
if ( ! AddRetract( ptP1, vtTool, dSafeZ, dEndElev, dAppr)) {
m_pMchMgr->SetLastError( 3115, "Error in SurfFinishing : Retract not computable") ;
return false ;
}
}
}
}
}
ExeProcessEvents( 100, 0) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::ApproxSilhouetteClosedPLForOptimal( PolyLine& PL, double dSampleTol, double dMaxLinTol, double dAngTol, double dLinFeaTol,
ICurveComposite* pCompoPL)
{
// approssimazione di una polyline di Silhouette per rimuovere Spikes di proiezione
// controllo dei parametri
if ( pCompoPL == nullptr)
return false ;
pCompoPL->Clear() ;
// se aperta errore
Plane3d plPL ;
double dArea ;
if ( ! PL.IsClosedAndFlat( plPL, dArea))
return false ;
// semplifico rimuovendo i punti allineati
PL.RemoveAlignedPoints( dSampleTol + 10 * EPS_SMALL) ;
// essendo chiusa, se presenti meno di 4 punti, non faccio nulla
int nPts = PL.GetPointNbr() ;
if ( nPts < 4)
return true ;
// porto la PolyLine nel frame LocaleXY
Frame3d frLoc ;
if ( ! frLoc.Set( plPL.GetPoint(), plPL.GetVersN()))
return false ;
PL.ToLoc( frLoc) ;
// --------------------------- scelta del punto iniziale ------------------------------
// creo un vettore contenente tutti i punti ( cerco nel mentre il segmento più lungo)
PNTVECTOR vPt ; vPt.reserve( nPts) ;
int nLongEdge = -1 ;
double dMaxSqLen = 0. ;
Point3d myPt ;
if ( ! PL.GetFirstPoint( myPt))
return false ;
vPt.emplace_back( myPt) ;
while ( PL.GetNextPoint( myPt)) {
double dCurrSqDist = SqDist( vPt.back(), myPt) ;
if ( dCurrSqDist > dMaxSqLen) {
dMaxSqLen = dCurrSqDist ;
nLongEdge = int( vPt.size()) - 1 ;
}
vPt.emplace_back( myPt) ;
}
if ( nLongEdge < 0 || nLongEdge > nPts - 2)
return false ;
// calcolo il punto iniziale come punto medio del segmento più lungo
Point3d ptStart = Media( vPt[nLongEdge], vPt[nLongEdge + 1]) ;
ChangePolyLineStart( PL, ptStart, 10 * EPS_SMALL) ;
nPts = PL.GetPointNbr() ;
// ---------------------- modifica dei punti Spike ---------------------------------
// creo un vettore di punti a partire dai punti della PolyLine
PNTVECTOR vPts ; vPts.reserve( nPts) ;
PL.GetFirstPoint( myPt) ;
vPts.emplace_back( myPt) ;
while ( PL.GetNextPoint( myPt))
vPts.emplace_back( myPt) ;
// dichiaro i versori tangenti consecutivi per il percorso della PolyLinea
Vector3d vtTanPrev, vtTan, vtTanAfter ;
// recupero il cosendo della tolleranza angolare
double dCosAngTol = abs( cos( dAngTol * DEGTORAD)) ;
// calcolo il quadrato della tolleranza lineare
double dSqMaxLinTol = dMaxLinTol * dMaxLinTol ;
// ciclo tutti i punti della PolyLine
for ( int i = 2 ; i < int( vPts.size()) - 1 ; ++ i) {
// se distanza tra punto attuale e precedente sopra al tolleranza, passo ai successivi
if ( SqDist( vPts[i], vPts[i-1]) > dSqMaxLinTol)
continue ;
// calcolo il versore tangente del segmento pecedente
vtTanPrev = vPts[i-1] - vPts[i-2] ;
vtTanPrev.Normalize() ;
// calcolo versore tangente attuale
vtTan = vPts[i] - vPts[i-1] ;
vtTan.Normalize() ;
// recupero la direzione successia
vtTanAfter = vPts[i+1] - vPts[i] ;
vtTanAfter.Normalize() ;
// controllo se l'angolo tra la direzione attuale e precedente supera la tolleranza
if ( abs( vtTanPrev * vtTan) > dCosAngTol && abs( vtTan * vtTanAfter) > dCosAngTol)
continue ; // se uno dei due sotto la tolleranza, analizzo segmento successivo
// se Spike individuato, modifico il punto corrente con il punto medio del segmento attuale
vPts[i] = Media( vPts[i], vPts[i-1]) ;
// il punto precedente diventa uguale all' i-2-esimo
vPts[i-1] = vPts[i-2] ;
}
// a partire da questi punti, creo la PolyLine
double dPar = -1 ;
PolyLine myPL ;
myPL.AddUPoint( ++ dPar, vPts[0]) ; // il primo punto è automaticamente inserito
Point3d myLastPtInPL = vPts[0] ;
for ( int i = 1 ; i < int( vPts.size()) ; ++ i) {
// se il punto corrente è già inserito nella PolyLine, passo al successivo
if ( AreSamePointApprox( vPts[i], myLastPtInPL))
continue ;
// altrimenti inserisco il punto nella Polyline e aggiorno il punto finale
myPL.AddUPoint( ++ dPar, vPts[i]) ;
myLastPtInPL = vPts[i] ;
}
// chiudo la PolyLine per sicurezza
myPL.Close() ;
// swap
swap( PL, myPL) ;
// recupero la curva composita dalla polyLine
if ( ! pCompoPL->FromPolyLine( PL) || ! pCompoPL->IsValid())
return false ;
// approssimo con archi
PolyArc PA ;
double dMyLinFea = dLinFeaTol ;
double dMyAngTol = dAngTol ;
if ( dMaxLinTol > LIN_TOL_STD) {
double dCoeff = ( dMaxLinTol - LIN_TOL_STD) / LIN_TOL_STD ;
dMyLinFea = min( LIN_FEA_STD + 1.0 * dCoeff * LIN_FEA_STD, 400.) ;
dMyAngTol = min( ANG_TOL_STD_DEG + 0.2 * dCoeff * ANG_TOL_STD_DEG, 60.) ;
}
if ( pCompoPL->ApproxWithArcsEx( dMaxLinTol, dMyAngTol, dMyLinFea, PA)) {
PtrOwner<ICurveComposite> pTempCrv( CreateCurveComposite()) ;
if ( ! IsNull( pTempCrv) &&
pTempCrv->FromPolyArc( PA) &&
pTempCrv->RemoveSmallDefects( dMaxLinTol, ANG_TOL_STD_DEG) &&
pTempCrv->MergeCurves( dMaxLinTol, ANG_TOL_STD_DEG)) {
pCompoPL->CopyFrom( pTempCrv) ;
}
}
// riporto la curva nel frame di partenza
pCompoPL->ToGlob( frLoc) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::GetSfrBySilhouette( ICAvParSilhouettesSurfTm* pCavParSilh, double dDepth,
double dSilTolSamp, double dSilTolLin,
double dSilTolAng, ISurfFlatRegion* pSfrSil)
{
// funzione per resitutire una regione piana data la classe di calcolo per silhouette
// controllo dei parametri
if ( pSfrSil == nullptr)
return false ;
pSfrSil->Clear() ;
// recupero il vettore di PolyLine della silhouette
POLYLINEVECTOR vPL ;
if ( ! pCavParSilh->GetSilhouette( - dDepth, vPL))
return false ;
// creo la regione piana dalle PolyLine ricavate dalla Silhouette
SurfFlatRegionByContours SfrMaker ;
for ( auto& PL : vPL) {
// recupero la curva in base alla polyLine
PtrOwner<ICurveComposite> pSilCrv( CreateCurveComposite()) ;
if ( IsNull( pSilCrv))
return false ;
if ( ! ApproxSilhouetteClosedPLForOptimal( PL, dSilTolSamp, dSilTolLin, ANG_TOL_STD_DEG, LIN_FEA_STD, pSilCrv))
return false ;
// aggiungo per regione
if ( ! SfrMaker.AddCurve( Release( pSilCrv)))
return false ;
}
// definisco la regione piana
PtrOwner<ISurfFlatRegion> pSfrTmp( SfrMaker.GetSurf()) ;
if ( ! IsNull( pSfrTmp) && pSfrTmp->IsValid())
pSfrSil->CopyFrom( pSfrTmp) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::SplitStmTrianglesForSpiralAndZConst( const ISurfTriMesh* pStm, const Frame3d& frSurf,
const Vector3d& vtTool, double dClippingAngle, double dTolerAngle,
StmFromTriangleSoup& TriaSoup, double& dMaxFrontTriaRad) const
{
// Funzione per ciclare i triangoli di una TriMesh (*pStm) partendo da nT_start e terminando a nT_end
// I triangoli che formano un angolo in valore assoluto con vtTool, maggiore di dClippingAngle
// vengono inseriti nella zuppa TriaSoup
// dMaxFrontTriaRad è il raggio massimo dei triangoli con normale che si discosta da vtTool per
// meno di dTolerAngle (triangoli frontalieri)
// controllo della superficie
if ( pStm == nullptr || ! pStm->IsValid())
return false ;
// porto il versore utensile nel riferimento locale
Vector3d vtToolLoc = vtTool ; vtToolLoc.ToLoc( frSurf) ;
// aggiusto i parametri
dClippingAngle = Clamp( dClippingAngle, 30., 60.) ; // [30°,60°]
dTolerAngle = Clamp( dTolerAngle, 1., 5.) ; // [1°,5°]
// definizione delle costanti
double dCosLimit = cos( dClippingAngle * DEGTORAD) ;
double dCosLimSup = cos( ( dClippingAngle - dTolerAngle) * DEGTORAD) ;
double dCosLimInf = cos( max( 0., ( dClippingAngle + dTolerAngle)) * DEGTORAD) ;
double dAbsCosPerpTol = dTolerAngle * DEGTORAD ; // x->PI/2, cos(x) ~ -x + PI/2
int nTria = pStm->GetTriangleCount() ;
// scorro i triangoli della superficie
for ( int nT = 0 ; nT < nTria ; ++ nT) {
// recupero il triangolo corrente (controllo la sua validità)
Triangle3d Tria ; pStm->GetTriangle( nT, Tria) ;
if ( ! Tria.IsValid())
continue ;
// recupero la normale del triangolo
Vector3d vtN_tria = Tria.GetN() ;
// se i due versori sono quasi paralleli il triangolo vengono saltati
// ( se faccia piana equiversa a vtToolLoc allora è in Spiral, se opposta non la considero)
if ( AreSameOrOppositeVectorEpsilon( vtN_tria, vtToolLoc, 50 * EPS_SMALL))
continue ;
// recupero il valore coseno dell'angolo
double dCos = vtN_tria * vtToolLoc ;
// se triangolo è forntaliero, lo inserisco nel vettore
if ( dCos < dCosLimSup && dCos > dCosLimInf) {
// recupero il raggio della sfera che contine il triangolo
BBox3d BBoxTria ;
double dRad ;
if ( ! Tria.GetLocalBBox( BBoxTria) || ! BBoxTria.GetRadius( dRad))
continue ;
// se raggio più grande del limite superiore, aggiorno
if ( dRad > dMaxFrontTriaRad)
dMaxFrontTriaRad = dRad ;
}
// se la normale è circa perpendicolare a vtToolLoc, salto il triangolo (crea loop non validi)
if ( abs( dCos) < dAbsCosPerpTol)
continue ;
// se la normale del triangolo è sotto la tolleranza, lo inserisco nella zuppa
// più il prodottoscalare tende a 0, più i versori sono distanti
if ( abs( dCos) < dCosLimit + EPS_ANG_ZERO)
TriaSoup.AddTriangle( Tria.GetP( 0), Tria.GetP( 1), Tria.GetP( 2)) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::SplitStmInTwoSilSfrByClippingAngle( const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfrCnt,
double dDepth, const Vector3d& vtTool, double dClippingAngle, ISurfFlatRegion* pSfrSpiral,
ISurfFlatRegion* pSfrZConst)
{
// controllo delle regioni piane
if ( pSfrSpiral == nullptr || pSfrZConst == nullptr ||
pSfrCnt == nullptr || ! pSfrCnt->IsValid())
return false ;
pSfrSpiral->Clear() ;
pSfrZConst->Clear() ;
// definisco il piano di taglio alla profondità massima
Point3d ptCenter ; pSfrCnt->GetCentroid( ptCenter) ;
Plane3d plClipping ;
Point3d ptPlCl = GetToLoc( ptCenter, frSurf) ;
Vector3d vtNCl = GetToLoc( vtTool, frSurf) ;
if ( ! plClipping.Set( ptPlCl - vtNCl * dDepth, - vtNCl))
return false ;
// parametri e costanti per il calcolo della regione
double dMaxRad = 100. * EPS_SMALL ; // raggio massimo della sfera che contiene i triangoli frontalieri
const double OFFS_TRIA_ANG_TOL = 2. ; // tolleranza di ricerca dei triangoli frontalieri
const double OFFS_CORR = 0. ; // offset correttivo regione piana ZConst
// creazione della zuppa di triangoli per la Zconst e zuppa per triangoli perpendicolari a vtTool
StmFromTriangleSoup StmSoup ;
StmSoup.Start() ;
// scorro il vettore delle regioni piane
for ( int i = 0 ; i < int( vSrfLoc.size()) ; ++ i) {
// recupero la regione come superficie trimesh (controllo la sua validità)
PtrOwner<ISurfTriMesh> pStm( CloneSurfTriMesh( GetSurfTriMesh( vSrfLoc[i].Get()))) ;
if ( IsNull( pStm) || ! pStm->IsValid())
continue ;
// NB. devo tagliare la supericie con un piano diretto come vtTool a profondità dDepth
// ( altrimenti rischio di calcolare regioni piane inutili )
if ( ! pStm->Cut( plClipping, true))
return false ;
// recupero la zuppa per ZConst
if ( ! SplitStmTrianglesForSpiralAndZConst( pStm, frSurf, vtTool, dClippingAngle, OFFS_TRIA_ANG_TOL, StmSoup, dMaxRad))
return false ;
dMaxRad = Clamp( dMaxRad, 100 * EPS_SMALL, 5.) ; // per sicurezza
}
StmSoup.End() ;
// definisco vettori superfici locali ZConst e superficiTM perpendicolari a vtTool
ISURFTMPOVECTOR vStmLocZConst ;
// recupero le superfici trimesh
PtrOwner<ISurfTriMesh> pStmCurr( StmSoup.GetSurf()) ;
while ( ! IsNull( pStmCurr) && pStmCurr->IsValid() && pStmCurr->GetTriangleCount() > 0) {
// porto la superficie nel sistema di riferimento globale
pStmCurr->ToGlob( frSurf) ;
#if ENABLE_OPTIMAL_DEBUG
int _o = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmCurr->Clone()) ;
m_pGeomDB->SetMaterial( _o, PURPLE) ;
#endif
vStmLocZConst.emplace_back( Release( pStmCurr)) ;
pStmCurr.Set( StmSoup.GetSurf()) ;
} ;
// definisco il frame di calcolo per la superficie in base alla pSfrCnt
Frame3d frLoc ;
if ( ! frLoc.Set( ptCenter, vtTool))
return false ;
// definisco la costante di campionamento per la silhouette
const double SILH_TOL = 1. ;
// construisco la regione piana per ZConst
pSfrSpiral->CopyFrom( pSfrCnt) ; // superficie per spiral uguale all'originale
if ( ! vStmLocZConst.empty()) {
// definisco il vettore di TriMesh
CISURFTMPVECTOR vStmConst ; vStmConst.reserve( vStmLocZConst.size()) ;
for ( int i = 0 ; i < int( vStmLocZConst.size()) ; ++ i)
vStmConst.emplace_back( vStmLocZConst[i]) ;
// inizializzo classe di calcolo della Silhoeutte
PtrOwner<ICAvParSilhouettesSurfTm> pCavParSilh( CreateCAvParSilhouettesSurfTm()) ;
if ( IsNull( pCavParSilh) || ! pCavParSilh->SetData( vStmConst, frLoc, SILH_TOL))
return false ;
// recupero la regione piana
if ( ! GetSfrBySilhouette( pCavParSilh, dDepth, SILH_TOL, 2. * dMaxRad, ANG_TOL_STD_DEG, pSfrZConst))
return false ;
// se regione valida, la porto nel sistema di riferimento globale
if ( pSfrZConst->IsValid()) {
// traslo la superficie sopra al grezzo
bool bOK = pSfrZConst->Translate( dDepth * vtTool) ;
// offset di correzione...
bOK = bOK && pSfrZConst->Offset( OFFS_CORR, ICurve::OFF_FILLET) ;
// limito la superficie a ZConst alla regione di contorno
bOK = bOK && pSfrZConst->Intersect( *pSfrCnt) ;
// definizione superficie Spiral per sottrazione
bOK = bOK && pSfrSpiral->Subtract( *pSfrZConst) ;
if ( ! bOK)
return false ;
}
}
#if ENABLE_OPTIMAL_DEBUG
int _a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrSpiral->Clone()) ;
m_pGeomDB->SetMaterial( _a, Color( 255., 0., 255., .25)) ;
_a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrZConst->Clone()) ;
m_pGeomDB->SetMaterial( _a, Color( 0., 255., 0., .25)) ;
LOG_ERROR( GetEMkLogger(), ToString( dMaxRad).c_str()) ;
#endif
// elimino i piccoli chunk imprecisi
for ( int nC = 0 ; nC < pSfrSpiral->GetChunkCount() ; ++ nC) {
// verifico se l'Offset massimo del chunk è sopra alla tolleranza
double dMaxOffs = EPS_SMALL ;
pSfrSpiral->GetChunkMaxOffset( nC, dMaxOffs) ;
// rimuovo il Chunk c-esimo se l'Offset massimo è minore della tolleranza
if ( dMaxOffs < dMaxRad) {
pSfrSpiral->EraseChunk( nC) ;
-- nC ;
}
}
for ( int nC = 0 ; nC < pSfrZConst->GetChunkCount() ; ++ nC) {
// verifico se l'Offset massimo del chunk è sopra alla tolleranza
double dMaxOffs = EPS_SMALL ;
pSfrZConst->GetChunkMaxOffset( nC, dMaxOffs) ;
// rimuovo il Chunk c-esimo se l'Offset massimo è minore della tolleranza
if ( dMaxOffs < dMaxRad) {
pSfrZConst->EraseChunk( nC) ;
-- nC ;
}
}
// aggiorno la ProgressBar al 40%
ExeProcessEvents( 40, 0) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::OrderOptimalPathsByZLoc( const ISurfFlatRegion* pSfr, VECTORPATHS& vCrvPaths)
{
// controllo dei parametri
if ( pSfr == nullptr || ! pSfr->IsValid())
return false ;
// se ho un solo percorso, non faccio nulla
if ( int( vCrvPaths.size()) == 1)
return true ;
// creo un frame sulla superficie
Frame3d frOrder ;
Point3d ptOrder ; pSfr->GetCentroid( ptOrder) ;
Vector3d vtOrder = pSfr->GetNormVersor() ;
if ( ! frOrder.Set( ptOrder, vtOrder))
return false ;
DBLVECTOR vZorder( vCrvPaths.size()) ;
for ( int i = 0 ; i < int( vCrvPaths.size()) ; ++ i) {
Point3d ptStart ; vCrvPaths[i].pCrvPath->GetStartPoint( ptStart) ;
ptStart.ToLoc( frOrder) ;
vZorder[i] = ptStart.z ;
}
// swap degli indici per ordine delle Z locali
for ( int i = 0 ; i < int( vZorder.size()) - 1 ; ++ i) {
for ( int j = i + 1 ; j < int( vZorder.size()) ; ++ j) {
if ( vZorder[j] > vZorder[i]) {
swap( vZorder[j], vZorder[i]) ;
swap( vCrvPaths[j], vCrvPaths[i]) ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::ChooseFinishingForOptimal( const ISurfFlatRegion* pSfr, int nChunk, bool& bSpiral,
double& dSideAng)
{
// controllo dei parametri
if ( pSfr == nullptr || ! pSfr->IsValid())
return false ;
// controllo valore di nChunk
if ( nChunk < 0 || nChunk >= pSfr->GetChunkCount())
return false ;
// informazioni sul Chunk
int nLines = 0 ; double dMaxLineLen = 0. ; Vector3d vtTanMaxLine ;
int nArcs = 0 ; double dMaxArcLen = 0. ;
BBox3d BBox ; Vector3d vtX ;
for ( int nL = 0 ; nL < pSfr->GetLoopCount( nChunk) ; ++ nL) {
// recupero il loop come curva composita
PtrOwner<ICurveComposite> pCompoLoop( ConvertCurveToComposite( pSfr->GetLoop( nChunk, nL))) ;
if ( IsNull( pCompoLoop) || ! pCompoLoop->IsValid())
return false ;
// se loop esterno calcolo il Box
if ( nL == 0) {
PolyLine PL ;
if ( ! pCompoLoop->ApproxWithLines( 100 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, PL))
return false ;
Point3d ptCenter ;
double dLen ; double dHeight ;
if ( ! PL.GetMinAreaRectangleXY( ptCenter, vtX, dLen, dHeight))
return false ;
}
// scorro le curve del Loop
for ( int nU = 0 ; nU < pCompoLoop->GetCurveCount() ; ++ nU) {
const ICurve* pCurve = pCompoLoop->GetCurve( nU) ;
if ( pCurve == nullptr || ! pCurve->IsValid())
return false ;
// se arco
if ( pCurve->GetType() == CRV_ARC) {
++ nArcs ;
double dLen ; pCurve->GetLength( dLen) ;
if ( dLen > dMaxArcLen)
dMaxArcLen = dLen ;
}
// se linea
else if ( pCurve->GetType() == CRV_LINE) {
++ nLines ;
double dLen ; pCurve->GetLength( dLen) ;
if ( dLen > dMaxLineLen) {
dMaxLineLen = dLen ;
pCurve->GetStartDir( vtTanMaxLine) ;
}
}
}
}
// di base lavorazione Spiral
bSpiral = true ;
// se l'entità più lunga è la linea
if ( dMaxLineLen > dMaxArcLen) {
// se ci sono in genere più linee che archi (60% linee)
if ( nLines / ( nLines + nArcs + 1) > .6) {
// se la direzione principale della linea concide con la direzione massima del box minimo
if ( AreSameOrOppositeVectorApprox( vtTanMaxLine, vtX)) {
bSpiral = false ; // ZigZag
X_AX.GetAngle( vtX, dSideAng) ;
dSideAng = abs( dSideAng) ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::AddOptimal( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfr,
const Vector3d& vtTool, double dDepth, double dElev, bool bSplitArcs)
{
// controllo che la regione sia definita correttamente
if ( pSfr == nullptr || ! pSfr->IsValid())
return false ;
// aggiorno la ProgressBar del 5% per simulare l'inizio della funzione
ExeProcessEvents( 5, 0) ;
// recupero distanze di sicurezza
double dSafeZ = GetSafeZ() ;
// lunghezza di approccio/retrazione
double dAppr = m_Params.m_dStartPos ;
// vettore dei percorsi da calcolare
VECTORPATHS vPaths ;
// definizione angolo di tolleranza per lavorazioni Spiral e ZConst
double dClippingAngle = 3. * ANG_TOL_STD_DEG ;
PtrOwner<ISurfFlatRegion> pSfrSpiral( CreateSurfFlatRegion()) ;
PtrOwner<ISurfFlatRegion> pSfrZConst( CreateSurfFlatRegion()) ;
if ( ! SplitStmInTwoSilSfrByClippingAngle( vSrfLoc, frSurf, pSfr, dDepth, vtTool, dClippingAngle, pSfrSpiral, pSfrZConst))
return false ;
// ----------------------- Lavorazione Spiral/ZigZag -------------------------------
if ( ! IsNull( pSfrSpiral) && pSfrSpiral->IsValid()) {
// determino il riferimento di base della svuotatura
Frame3d frPocket ;
Point3d ptCen ; pSfr->GetCentroid( ptCen) ;
frPocket.Set( ptCen, vtTool) ;
// se richiesto parametro SkipMaxDown, devo limitare questa superficie alla vera Silhouette
bool bSkipMaxDown = true ;
GetValInNotes( m_Params.m_sUserNotes, "SkipMaxDown", bSkipMaxDown) ;
PtrOwner<ISurfFlatRegion> pSfrSil_real( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrSil_real))
return false ;
if ( bSkipMaxDown) {
// riduco la regione sulla Silhouette corretta
pSfrSil_real.Set( GetSfrSilhouette( vSrfLoc, frSurf, frPocket, - dDepth)) ;
if ( IsNull( pSfrSil_real) || ! pSfrSil_real->IsValid()) {
m_pMchMgr->SetLastError( 3124, "Error in SurfFinishing : region not computable") ;
return false ;
}
// intersezione
pSfrSil_real->Offset( - m_Params.m_dSideStep + 10 * EPS_SMALL, ICurve::OFF_FILLET) ;
if ( ! pSfrSpiral->Intersect( *pSfrSil_real))
return false ;
}
// le curve di finitura spiral devono stare sul bordo della regione trovata
pSfrSpiral->Offset( m_Params.m_dSideStep, ICurve::OFF_FILLET) ;
// mi assicuro di non uscire dalla superficie originale
PtrOwner<ISurfFlatRegion> pSfrOverlap( pSfr->CreateOffsetSurf( m_Params.m_dOverlap, ICurve::OFF_FILLET)) ;
if ( ! IsNull( pSfrOverlap) && pSfrOverlap->IsValid())
pSfrSpiral->Intersect( *pSfrOverlap) ;
else
pSfrSpiral->Intersect( *pSfr) ;
// lavoro ogni singolo Chunk singolarmente ( non estendo lati aperti per eveitare merge con gli stessi Chunks)
for ( int nC = 0 ; nC < pSfrSpiral->GetChunkCount() ; ++ nC) {
// recupero il Chunk come regione piana
PtrOwner<ISurfFlatRegion> pSfrToWork( pSfrSpiral->CloneChunk( nC)) ;
if ( IsNull( pSfrToWork) || ! pSfrToWork->IsValid())
return false ;
// imposto i lati chiusi
for ( int nCC = 0 ; nCC < pSfrToWork->GetChunkCount() ; ++ nCC) {
for ( int nL = 0 ; nL < pSfrToWork->GetLoopCount( nCC) ; ++ nL) {
for ( int nU = 0 ; nU < pSfrToWork->GetLoopCurveCount( nCC, nL) ; ++ nU)
pSfrToWork->SetCurveTempProp( nCC, nL, nU, 0, TEMP_PROP_CLOSE_EDGE) ;
}
}
// lavorazione Spiral
ICRVCOMPOPOVECTOR vpCrvs ;
if ( ! CalcPocketing( pSfrToWork, m_Params.m_dSideStep, 0., m_Params.m_dSideStep, m_Params.m_dSideAngle,
POCKET_SPIRALIN, false, false, true, false, P_INVALID, nullptr, vpCrvs)) {
m_pMchMgr->SetLastError( 3125, "Error in SurfFinishing : CalcPocketing failed") ;
return false ;
}
// ciclo sui percorsi ricavati risultanti
double dProgCoeff = 1. / max( int( vpCrvs.size()), 1) ;
for ( int k = 0 ; k < int( vpCrvs.size()) ; ++ k) {
// definisco un nuovo percorso (in locale)
vPaths.resize( vPaths.size() + 1) ;
vPaths.back().pCrvPath.Set( Release( vpCrvs[k])) ;
vPaths.back().pCrvPath->ToLoc( frPocket) ;
vPaths.back().nType = SURFFIN_SUB_SPIRALIN ;
// li correggo per non interferire con le superfici
if ( pCAvTlStm != nullptr) {
// approssimo la curva con una polilinea
PolyLine PL ;
if ( ! vPaths.back().pCrvPath->ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL))
return false ;
// eventuale aggiunta di punti per garantire max distanza
const double MIN_DIST = 1. ;
const double MAX_DIST = 50. ;
double dDist = Clamp( m_TParams.m_dDiam / 2, MIN_DIST, MAX_DIST) ;
if ( ! PL.AdjustForMaxSegmentLen( dDist))
return false ;
// porto nel riferimento delle superfici
PL.LocToLoc( frPocket, frSurf) ;
// porto i dati geometrici in locale alle superfici
Vector3d vtAxL = vtTool ;
vtAxL.ToLoc( frSurf) ;
Vector3d vtMoveL = vtAxL ;
// traslo della lunghezza utensile diminuita dell'affondamento
PL.Translate( vtAxL * ( m_TParams.m_dLen - dDepth)) ;
// eseguo CAv
if ( ! pCAvTlStm->TestPath( PL.GetUPointList(), vtAxL, vtMoveL, m_Params.m_dApprox, ( k + 1) * dProgCoeff))
return false ;
// contro-traslo della lunghezza utensile
PL.Translate( - vtAxL * m_TParams.m_dLen) ;
// riporto la polilinea nel riferimento della curva
PL.LocToLoc( frSurf, frPocket) ;
// elimino i punti allineati
PL.RemoveAlignedPoints( 0.8 * m_Params.m_dApprox) ;
// creo una curva composita a partire dalla polilinea
PtrOwner< ICurveComposite> pCompo( CreateCurveComposite()) ;
if ( IsNull( pCompo) || ! pCompo->FromPolyLine( PL))
return false ;
// sostituisco la vecchia curva con la nuova
vPaths.back().pCrvPath.Set( pCompo) ;
}
}
}
// porto tutti i percorsi nel frame globale
for ( int i = 0 ; i < int( vPaths.size()) ; ++ i)
vPaths[i].pCrvPath->ToGlob( frPocket) ;
}
// aggiorno la ProgressBar al 60%
ExeProcessEvents( 5, 0) ;
#if ENABLE_OPTIMAL_DEBUG
// disegno i percorsi per controllo
int ___a = int( vPaths.size()) ;
for ( int i = 0 ; i < int( vPaths.size()) ; ++ i) {
int _n = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vPaths[i].pCrvPath->Clone()) ;
m_pGeomDB->SetMaterial( _n, RED) ;
}
#endif
// ----------------------- Lavorazione Zconst -------------------------------
if ( ! IsNull( pSfrZConst) && pSfrZConst->IsValid()) {
// recupero dai parametri eventuale Offset di sovrapposizione per ZConst
double dZConstOverlap = m_TParams.m_dDiam / 2 ;
if ( GetValInNotes( m_Params.m_sUserNotes, "ZConstOverlap", dZConstOverlap))
dZConstOverlap = Clamp( dZConstOverlap, 0., m_TParams.m_dDiam / 2) ;
dZConstOverlap += m_TParams.m_dDiam / 2 ;
// effettuo un Offset del raggio utensile ( o definito da parametro) per la superficie a ZConst
pSfrZConst->Offset( dZConstOverlap, ICurve::OFF_FILLET) ;
// lavoro ogni singolo Chunk singolarmente ( non estendo lati aperti per evitare merge con gli stessi Chunks)
for ( int nC = 0 ; nC < pSfrZConst->GetChunkCount() ; ++ nC) {
// recupero il Chunk come regione piana
PtrOwner<ISurfFlatRegion> pSfrToWork( pSfrZConst->CloneChunk( nC)) ;
if ( IsNull( pSfrToWork) || ! pSfrToWork->IsValid())
return false ;
// mi assicuro di non uscire dalla superficie originale
PtrOwner<ISurfFlatRegion> pSfrOverlap( pSfr->CreateOffsetSurf( m_Params.m_dOverlap, ICurve::OFF_FILLET)) ;
if ( ! IsNull( pSfrOverlap) && pSfrOverlap->IsValid())
pSfrToWork->Intersect( *pSfrOverlap) ;
else
pSfrToWork->Intersect( *pSfr) ;
// aggiusto la regione a seconda dei parametri ( per riportarmi al caso di AddZConst)
pSfrToWork->Offset( - m_TParams.m_dDiam / 2., ICurve::OFF_FILLET) ;
// imposto i lati chiusi
for ( int nCC = 0 ; nCC < pSfrToWork->GetChunkCount() ; ++ nCC) {
for ( int nL = 0 ; nL < pSfrToWork->GetLoopCount( nCC) ; ++ nL) {
for ( int nU = 0 ; nU < pSfrToWork->GetLoopCurveCount( nCC, nL) ; ++ nU)
pSfrToWork->SetCurveTempProp( nC, nL, nU, 0, TEMP_PROP_CLOSE_EDGE) ;
}
}
// inizializzo la classe di calcolo delle silhouette nei piani come sopra
ISURFTMPOVECTOR vpStm ; vpStm.reserve( vSrfLoc.size()) ;
for ( int i = 0 ; i < int( vSrfLoc.size()) ; ++ i) {
PtrOwner<ISurfTriMesh> pStm( CloneSurfTriMesh( GetSurfTriMesh( vSrfLoc[i].Get()))) ;
if ( ! IsNull( pStm) && pStm->IsValid() && pStm->GetTriangleCount() > 0) {
pStm->ToGlob( frSurf) ;
vpStm.emplace_back( Release( pStm)) ;
}
}
PtrOwner<ICAvParSilhouettesSurfTm> pCavParSilh( GetParSilhouettesForZConst( vpStm, pSfrToWork)) ;
if ( IsNull( pCavParSilh))
return false ;
// recupero le curve singole definite dal bordo della Silhouette
vector<ICRVCOMPOPOVECTOR> vCrvCompo ;
if ( ! CalcZConstSilCrv( pCavParSilh, vSrfLoc, frSurf, pSfrToWork, vtTool, dDepth, vCrvCompo)) {
m_pMchMgr->SetLastError( 3126, "Error in SurfFinishing : Computing ZConst Curves failed") ;
return false ;
}
// se ho delle curve, allora unisco i percorsi trovati
if ( ! vCrvCompo.empty()) {
// collego tra loro le curve trovate
ICRVCOMPOPOVECTOR vCrv ;
if ( ! CreateZConstPaths( pCAvTlStm, frSurf, vCrvCompo, vtTool, pSfrToWork, dDepth, vCrv)) {
m_pMchMgr->SetLastError( 3127, "Error in SurfFinishing : Computing ZConst Paths failed") ;
return false ;
}
// aggiungo i percorsi trovati
for ( int i = 0 ; i < int( vCrv.size()) ; ++ i) {
vPaths.resize( vPaths.size() + 1) ;
vPaths.back().pCrvPath.Set( Release( vCrv[i])) ;
vPaths.back().nType = SURFFIN_SUB_ZIGZAG ;
}
}
}
}
// aggiorno la ProgressBar all' 80%
ExeProcessEvents( 80, 0) ;
#if ENABLE_OPTIMAL_DEBUG
// disegno i percorsi per controllo
for ( int i = ___a ; i < int( vPaths.size()) ; ++ i) {
int _n = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vPaths[i].pCrvPath->Clone()) ;
m_pGeomDB->SetMaterial( _n, GREEN) ;
}
#endif
// ordino i percorsi in base alla Zlocale
if ( ! OrderOptimalPathsByZLoc( pSfr, vPaths))
return false ;
// aggiorno la ProgressBar all' 80%
ExeProcessEvents( 90, 0) ;
// aggiusto la regione a seconda dei parametri
PtrOwner<ISurfFlatRegion> pSfrClass( pSfr->CreateOffsetSurf( - m_TParams.m_dDiam / 2. + m_Params.m_dOverlap, ICurve::OFF_FILLET)) ;
if ( IsNull( pSfrClass) || ! pSfrClass->IsValid())
return false ;
// piano definito dalla pSfr
Point3d ptCenter ; pSfr->GetCentroid( ptCenter) ;
Plane3d plSfr ;
if ( ! plSfr.Set( ptCenter, vtTool))
return false ;
// inserisco i percorsi
bool bStart = true ;
// ciclo sulle curve risultanti
for ( int k = 0 ; k < int( vPaths.size()) ; ++ k) {
// se la curva non è valida, passo alla successiva
if ( IsNull( vPaths[k].pCrvPath) || ! vPaths[k].pCrvPath->IsValid())
continue ;
// determino in che piano di partenza e il piano di arrivo se ZConst
int nStartPlane = 0 ;
int nEndPlane = 0 ;
if ( vPaths[k].nType == SURFFIN_SUB_Z_CONST) {
nStartPlane = vPaths[k].pCrvPath->GetTempProp( 0) ;
nEndPlane = vPaths[k].pCrvPath->GetTempProp( 1) ;
}
// ciclo sulle curve elementari
int nMaxInd = vPaths[k].pCrvPath->GetCurveCount() - 1 ;
for ( int i = 0 ; i <= nMaxInd ; ++ i) {
// curva corrente
const ICurve* pCrvC = vPaths[k].pCrvPath->GetCurve( i) ;
// copio la curva
PtrOwner<ICurve> pCurve( pCrvC->Clone()) ;
if ( IsNull( pCurve))
return false ;
// se prima entità
if ( i == 0) {
// dati inizio entità
Point3d ptStart ; pCurve->GetStartPoint( ptStart) ;
Vector3d vtStart ; pCurve->GetStartDir( vtStart) ;
// vettore tangente iniziale non deve salire rispetto a estrusione (poi si prende opposto)
double dStartOnExtr = vtStart * vtTool ;
if ( dStartOnExtr > 0) {
vtStart -= dStartOnExtr * vtTool ;
vtStart.Normalize() ;
}
// determino normale della superficie sul punto iniziale
Vector3d vtNorm ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptStart, vtTool, vtNorm)) {
Point3d ptEnd ;
pCurve->GetEndPoint( ptEnd) ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptEnd, vtTool, vtNorm))
vtNorm = V_NULL ;
}
// determino inizio attacco
Point3d ptP1 ;
if ( ! CalcLeadInStart( ptStart, vtStart, vtTool, vtNorm, ptP1))
return false ;
// eventuale correzione inizio attacco per evitare interferenze
if ( ! GetLastGoodPoint( pCAvTlStm, frSurf, ptStart, ptP1, vtTool, ptP1))
return false ;
// controllo che tale punto sia al di fuori della regione piana
if ( vPaths[k].nType == SURFFIN_SUB_Z_CONST) {
bool bIsInside = false ;
if ( IsPointInsideSurfFr( ptP1 + vtTool * ( m_Params.m_dSideStep * nStartPlane), pSfrClass, EPS_SMALL, bIsInside) && ! bIsInside)
ptP1 = ptStart ;
}
else {
bool bIsInside = false ;
if ( IsPointInsideSurfFr( ProjectPointOnPlane( ptP1, plSfr), pSfrClass, EPS_SMALL, bIsInside) && ! bIsInside)
ptP1 = ptStart ;
}
// determino elevazione su inizio attacco
double dStElev ;
if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev))
dStElev = dElev ;
dStElev -= ( ptP1 - ptStart) * vtTool ;
// se inizio, approccio globale al punto iniziale
if ( bStart) {
if ( ! AddApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) {
m_pMchMgr->SetLastError( 3111, "Error in SurfFinishing : Approach not computable") ;
return false ;
}
bStart = false ;
}
// altrimenti, approccio di collegamento
else {
if ( ! AddLinkApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) {
m_pMchMgr->SetLastError( 3112, "Error in SurfFinishing : Link not computable") ;
return false ;
}
}
// aggiungo attacco
SetFeed( GetStartFeed()) ;
if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtTool, bSplitArcs)) {
m_pMchMgr->SetLastError( 3113, "Error in SurfFinishing : LeadIn not computable") ;
return false ;
}
}
// elaborazioni sulla curva corrente (sempre un segmento di retta)
if ( pCurve->GetType() == CRV_LINE) {
ICurveLine* pLine = GetCurveLine( pCurve) ;
Point3d ptP3 = pLine->GetEnd() ;
Vector3d vtMove ; pLine->GetStartDir( vtMove) ;
SetFeed( GetRightFeed( vtMove, vtTool)) ;
if ( AddLinearMove( ptP3) == GDB_ID_NULL)
return false ;
}
else if ( pCurve->GetType() == CRV_ARC) {
ICurveArc* pArc = GetCurveArc( pCurve) ;
Point3d ptCen = pArc->GetCenter() ;
double dAngCen = pArc->GetAngCenter() ;
Vector3d vtN = pArc->GetNormVersor() ;
Point3d ptP3 ; pArc->GetEndPoint( ptP3) ;
SetFeed( GetFeed()) ;
if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL)
return false ;
}
// se ultima entità
if ( i == nMaxInd) {
// dati fine entità
Point3d ptEnd ; pCurve->GetEndPoint( ptEnd) ;
Vector3d vtEnd ; pCurve->GetEndDir( vtEnd) ;
// vettore tangente finale non deve scendere rispetto a estrusione
double dEndOnExtr = vtEnd * vtTool ;
if ( dEndOnExtr < 0) {
vtEnd -= dEndOnExtr * vtTool ;
vtEnd.Normalize() ;
}
// determino normale della superficie sul punto finale
Vector3d vtNorm ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptEnd, vtTool, vtNorm)) {
Point3d ptStart ;
pCurve->GetStartPoint( ptStart) ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptStart, vtTool, vtNorm))
vtNorm = V_NULL ;
}
// determino fine uscita
Point3d ptP1 ;
if ( ! CalcLeadOutEnd( ptEnd, vtEnd, vtTool, vtNorm, ptP1))
return false ;
// eventuale correzione fine uscita per evitare interferenze
if ( ! GetLastGoodPoint( pCAvTlStm, frSurf, ptEnd, ptP1, vtTool, ptP1))
return false ;
// controllo che tale punto sia al di fuori della regione piana
bool bIsInside = false ;
if ( IsPointInsideSurfFr( ptP1 + vtTool * ( m_Params.m_dSideStep * nStartPlane), pSfrClass, EPS_SMALL, bIsInside))
ptP1 = ptEnd ;
// se ultima uscita globale del percorso
if ( k == int( vPaths.size()) - 1) {
// aggiungo LeadOut
SetFeed( GetEndFeed()) ;
if ( ! AddLeadOut( ptEnd, vtEnd, ptP1, vtTool, bSplitArcs)) {
m_pMchMgr->SetLastError( 3114, "Error in SurfFinishing : LeadOut not computable") ;
return false ;
}
// aggiungo retroazione finale
if ( ! AddRetract( ptP1, vtTool, dSafeZ, nEndPlane * m_Params.m_dSideStep, dAppr)) {
m_pMchMgr->SetLastError( 3115, "Error in SurfFinishing : Retract not computable") ;
return false ;
}
}
// altrimenti
else {
// determino elevazione su fine uscita
double dEndElev ;
if ( ! GetElevation( m_nPhase, ptEnd - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dEndElev))
dEndElev = dElev ;
dEndElev -= ( ptP1 - ptEnd) * vtTool ;
if ( ! AddRetract( ptP1, vtTool, dSafeZ, dEndElev, dAppr)) {
m_pMchMgr->SetLastError( 3115, "Error in SurfFinishing : Retract not computable") ;
return false ;
}
}
}
}
}
// aggiorno la ProgressBar all' 100%
ExeProcessEvents( 100, 0) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::AddProjection( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf,
const ICurveComposite* pCrvCompo, const Vector3d& vtTool, double dDepth, double dElev, bool bSplitArcs)
{
// controllo che la curva sia valida
if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid())
return false ;
// recupero distanze di sicurezza
double dSafeZ = GetSafeZ() ;
// lunghezza di approccio/retrazione
double dAppr = m_Params.m_dStartPos ;
// definisco un sistema di riferimento locale alla curva
Point3d ptStart ; pCrvCompo->GetStartPoint( ptStart) ;
Frame3d frLoc ;
if ( ! frLoc.Set( ptStart, vtTool))
return false ;
// definisco il frame inverso per il calcolo del Box3d
Frame3d frLocInv = frLoc ;
if ( ! frLocInv.Invert())
return false ;
// definisco variabili globali
BBox3d BBox3Loc ; // box totale delle superici rispetto a frLoc
ISURFTMPOVECTOR vpStm ; // superfici TriMesh selezionate in globale
ICRVCOMPOPOVECTOR vCrvToProj ; // vettore delle curve da proiettare sulla superficie
// scorro il vettore di superfici selezionate
for ( int i = 0 ; i < int( vSrfLoc.size()) ; ++ i) {
// porto la supercicie nel riferimento globale come TriMesh
PtrOwner<ISurfTriMesh> pStm( CloneSurfTriMesh( GetSurfTriMesh( vSrfLoc[i].Get()))) ;
if ( IsNull( pStm) || ! pStm->IsValid() || ! pStm->ToGlob( frSurf))
return false ;
// calcolo il box rispetto a frLoc e sommo i contributi
BBox3d BBox ;
if ( ! pStm->GetBBox( frLocInv, BBox))
return false ;
BBox3Loc.Add( BBox) ;
// memorizzo la superficie nel vettore
vpStm.emplace_back( Release( pStm)) ;
}
// recupero flag per saltare parti a massimo affondamento
bool bSkipMaxDown = true ;
GetValInNotes( m_Params.m_sUserNotes, "SkipMaxDown", bSkipMaxDown) ;
if ( bSkipMaxDown) {
// definisco i dati di calcolo della Silhouette
const double SILH_TOL = 1.0 ;
CISURFTMPVECTOR vSurf ; vSurf.reserve( vpStm.size()) ;
for ( int i = 0; i < int( vpStm.size()) ; ++ i)
vSurf.emplace_back( vpStm[i]) ;
PtrOwner<ICAvParSilhouettesSurfTm> pCavParSilh( CreateCAvParSilhouettesSurfTm()) ;
if ( IsNull( pCavParSilh) || ! pCavParSilh->SetData( vSurf, frLoc, SILH_TOL))
return false ;
// recupero il vettore di PolyLine della silhouette
POLYLINEVECTOR vPL ;
if ( ! pCavParSilh->GetSilhouette( BBox3Loc.GetMin().z , vPL))
return false ;
// creo la regione piana dalle PolyLine ricavate dalla Silhouette
SurfFlatRegionByContours SfrMaker ;
for ( auto& PL : vPL) {
// recupero la curva dalla silhouette
PtrOwner<ICurveComposite> pSilCrv( CreateCurveComposite()) ;
if ( IsNull( pSilCrv))
return false ;
pSilCrv->FromPolyLine( PL) ;
// approssimo con archi
const double SILH_ARC_TOL = 0.1 * SILH_TOL ;
const double SILH_ARC_FEA_MAX = 100. ;
PolyArc PA ;
if ( pSilCrv->ApproxWithArcsEx( SILH_ARC_TOL, ANG_TOL_STD_DEG, SILH_ARC_FEA_MAX, PA)) {
PtrOwner<ICurveComposite> pTempCrv( CreateCurveComposite()) ;
if ( ! IsNull( pTempCrv) &&
pTempCrv->FromPolyArc( PA) &&
pTempCrv->RemoveSmallDefects( SILH_ARC_TOL / 2, ANG_TOL_STD_DEG) &&
pTempCrv->MergeCurves( SILH_ARC_TOL / 2, ANG_TOL_STD_DEG))
pSilCrv.Set( pTempCrv) ;
}
// aggiungo per regione
if ( ! SfrMaker.AddCurve( Release( pSilCrv))) {
m_pMchMgr->SetLastError( 3124, "Error in SurfFinishing : region not computable") ;
return false ;
}
}
// definisco la regione piana
PtrOwner<ISurfFlatRegion> pSfrSil( SfrMaker.GetSurf()) ;
if ( ! IsNull( pSfrSil) && pSfrSil->IsValid()) {
// Offset alla Silhouette
double dPockRadOffs = m_TParams.m_dDiam - m_Params.m_dSideStep - m_Params.m_dOverlap ;
pSfrSil->Offset( dPockRadOffs, ICurve::OFF_CHAMFER) ;
// porto la curva e la Silhouette nel frame locale per classificazione ( alla stezza zLoc)
PtrOwner<ICurveComposite> pCrvCompoCL( CloneCurveComposite( pCrvCompo)) ;
if ( IsNull( pCrvCompoCL) || ! pCrvCompoCL->IsValid())
return false ;
pCrvCompoCL->Translate( BBox3Loc.GetMin().z * vtTool) ;
pCrvCompoCL->ToLoc( frLoc) ;
pSfrSil->ToLoc( frLoc) ;
// classifico
CRVCVECTOR ccClass ;
if ( pSfrSil->GetCurveClassification( *pCrvCompoCL, EPS_SMALL, ccClass)) {
for ( int i = 0 ; i < int( ccClass.size()) ; ++ i) {
// se tratto di curva interno
if ( ccClass[i].nClass != CRVC_OUT) {
// recupero la curva
PtrOwner<ICurve> pCrvInt( pCrvCompo->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE)) ;
if ( ! IsNull( pCrvInt) && pCrvInt->IsValid())
vCrvToProj.emplace_back( ConvertCurveToComposite( Release( pCrvInt))) ;
}
}
}
}
}
else
vCrvToProj.emplace_back( CloneCurveComposite( pCrvCompo)) ;
// per ogni tratto di curva ricavato
for ( int i = 0 ; i < int( vCrvToProj.size()) ; ++ i) {
// se curva non valida, passo alla successiva
if ( vCrvToProj[i] == nullptr || ! vCrvToProj[i]->IsValid())
continue ;
// recupero la PolyLinea associata alla curva
PolyLine PL ;
if ( ! vCrvToProj[i]->ApproxWithLines( EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, PL))
return false ;
// recupero la distanza di traslazione della Polyline e la traslo
PL.Translate( -dDepth * vtTool) ;
// calcolo direzione di allontanamento dalle superfici
const double MIN_DIST = 1. ;
const double MAX_DIST = 50. ;
double dDist = Clamp( m_TParams.m_dDiam / 2, MIN_DIST, MAX_DIST) ;
if ( ! PL.AdjustForMaxSegmentLen( dDist))
return false ;
// porto la polyline nel frame delle superfici
Vector3d vtToolL = GetToLoc( vtTool, frSurf) ;
PL.ToLoc( frSurf) ;
// porto i punti dal tip al naso mandrino
PL.Translate( vtToolL * m_TParams.m_dLen) ;
// eseguo il test del percorso
if ( ! pCAvTlStm->TestPath( PL.GetUPointList(), vtToolL, vtToolL, m_Params.m_dApprox))
return false ;
// traslo della lunghezza utensile
PL.Translate( - vtToolL * m_TParams.m_dLen) ;
// riporto la polyline nel frame globale
PL.ToGlob( frSurf) ;
// elimino i punti allineati
PL.RemoveAlignedPoints( 0.8 * m_Params.m_dApprox) ;
// recupero la curva composita dalla PolyLine
PtrOwner<ICurveComposite> pCrvPath( CreateCurveComposite()) ;
if ( IsNull( pCrvPath) || ! pCrvPath->FromPolyLine( PL) || ! pCrvPath->IsValid())
return false ;
// ciclo sulle curve elementari
bool bStart = true ;
int nMaxInd = pCrvPath->GetCurveCount() - 1 ;
for ( int i = 0 ; i <= nMaxInd ; ++ i) {
// curva corrente
const ICurve* pCrvC = pCrvPath->GetCurve( i) ;
// copio la curva
PtrOwner<ICurve> pCurve( pCrvC->Clone()) ;
if ( IsNull( pCurve))
return false ;
// se prima entità
if ( i == 0) {
// dati inizio entità
Point3d ptStart ; pCurve->GetStartPoint( ptStart) ;
Vector3d vtStart ; pCurve->GetStartDir( vtStart) ;
// vettore tangente iniziale non deve salire rispetto a estrusione (poi si prende opposto)
double dStartOnExtr = vtStart * vtTool ;
if ( dStartOnExtr > 0) {
vtStart -= dStartOnExtr * vtTool ;
vtStart.Normalize() ;
}
// determino normale della superficie sul punto iniziale
Vector3d vtNorm ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptStart, vtTool, vtNorm)) {
Point3d ptEnd ; pCurve->GetEndPoint( ptEnd) ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptEnd, vtTool, vtNorm))
vtNorm = V_NULL ;
}
// determino inizio attacco
Point3d ptP1 ;
if ( ! CalcLeadInStart( ptStart, vtStart, vtTool, vtNorm, ptP1))
return false ;
// eventuale correzione inizio attacco per evitare interferenze
if ( ! GetLastGoodPoint( pCAvTlStm, frSurf, ptStart, ptP1, vtTool, ptP1))
return false ;
// determino elevazione su inizio attacco
double dStElev ;
if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev))
dStElev = dElev ;
dStElev -= ( ptP1 - ptStart) * vtTool ;
// se inizio, approccio globale al punto iniziale
if ( bStart) {
if ( ! AddApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) {
m_pMchMgr->SetLastError( 3111, "Error in SurfFinishing : Approach not computable") ;
return false ;
}
bStart = false ;
}
// altrimenti, approccio di collegamento
else {
if ( ! AddLinkApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) {
m_pMchMgr->SetLastError( 3112, "Error in SurfFinishing : Link not computable") ;
return false ;
}
}
// aggiungo attacco
SetFeed( GetStartFeed()) ;
if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtTool, bSplitArcs)) {
m_pMchMgr->SetLastError( 3113, "Error in SurfFinishing : LeadIn not computable") ;
return false ;
}
}
// elaborazioni sulla curva corrente (sempre un segmento di retta)
ICurveLine* pLine = GetCurveLine( pCurve) ;
if ( pLine == nullptr)
return false ;
Point3d ptP3 = pLine->GetEnd() ;
Vector3d vtMove ; pLine->GetStartDir( vtMove) ;
SetFeed( GetRightFeed( vtMove, vtTool)) ;
if ( AddLinearMove( ptP3) == GDB_ID_NULL)
return false ;
// se ultima entità
if ( i == nMaxInd) {
// dati fine entità
Point3d ptEnd ; pCurve->GetEndPoint( ptEnd) ;
Vector3d vtEnd ; pCurve->GetEndDir( vtEnd) ;
// vettore tangente finale non deve scendere rispetto a estrusione
double dEndOnExtr = vtEnd * vtTool ;
if ( dEndOnExtr < 0) {
vtEnd -= dEndOnExtr * vtTool ;
vtEnd.Normalize() ;
}
// determino normale della superficie sul punto finale
Vector3d vtNorm ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptEnd, vtTool, vtNorm)) {
Point3d ptStart ; pCurve->GetStartPoint( ptStart) ;
if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptStart, vtTool, vtNorm))
vtNorm = V_NULL ;
}
// determino fine uscita
Point3d ptP1 ;
if ( ! CalcLeadOutEnd( ptEnd, vtEnd, vtTool, vtNorm, ptP1))
return false ;
// eventuale correzione fine uscita per evitare interferenze
if ( ! GetLastGoodPoint( pCAvTlStm, frSurf, ptEnd, ptP1, vtTool, ptP1))
return false ;
// aggiungo uscita
SetFeed( GetEndFeed()) ;
if ( ! AddLeadOut( ptEnd, vtEnd, ptP1, vtTool, bSplitArcs)) {
m_pMchMgr->SetLastError( 3114, "Error in SurfFinishing : LeadOut not computable") ;
return false ;
}
// determino elevazione su fine uscita
double dEndElev ;
if ( ! GetElevation( m_nPhase, ptEnd - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dEndElev))
dEndElev = dElev ;
dEndElev -= ( ptP1 - ptEnd) * vtTool ;
// altrimenti aggiungo retrazione finale
if ( ! AddRetract( ptP1, vtTool, dSafeZ, dEndElev, dAppr)) {
m_pMchMgr->SetLastError( 3115, "Error in SurfFinishing : Retract not computable") ;
return false ;
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::AddApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr)
{
SetFlag( 1) ;
// se sopra attacco c'è spazio per sicurezza o approccio
double dSafeDist = dSafeZ ;
if ( dElev + max( dSafeDist, dAppr) > 10 * EPS_SMALL) {
// se distanza di sicurezza minore di distanza di inizio
if ( dSafeDist < dAppr + 10 * EPS_SMALL) {
// 1 -> punto sopra inizio
Point3d ptP1 = ptP + vtTool * ( dElev + dAppr) ;
if ( AddRapidStart( ptP1) == GDB_ID_NULL)
return false ;
}
else {
// 1a -> punto sopra inizio
Point3d ptP1b = ptP + vtTool * ( dElev + dAppr) ;
Point3d ptP1a = ptP1b + vtTool * ( dSafeDist - dAppr) ;
if ( ( AddRapidStart( ptP1a) == GDB_ID_NULL))
return false ;
// 1b -> punto appena sopra inizio
if ( ( dElev + dAppr) > EPS_SMALL) {
SetFlag( 0) ;
if ( AddRapidMove( ptP1b) == GDB_ID_NULL)
return false ;
}
}
// affondo al punto iniziale
SetFlag( 0) ;
SetFeed( GetTipFeed()) ;
if ( AddLinearMove( ptP) == GDB_ID_NULL)
return false ;
}
else {
// affondo diretto al punto iniziale
SetFlag( 0) ;
if ( AddRapidStart( ptP) == GDB_ID_NULL)
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::AddLinkApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr)
{
// se sopra attacco c'è spazio per approccio
if ( ( dElev + dAppr) > 10 * EPS_SMALL) {
// 1b -> punto appena sopra inizio
Point3d ptP1b = ptP + vtTool * ( dElev + dAppr) ;
if ( ( dElev + dAppr) > EPS_SMALL) {
SetFlag( 0) ;
if ( AddRapidMove( ptP1b) == GDB_ID_NULL)
return false ;
}
// affondo al punto iniziale
SetFlag( 0) ;
SetFeed( GetTipFeed()) ;
if ( AddLinearMove( ptP) == GDB_ID_NULL)
return false ;
}
else {
// affondo diretto al punto iniziale
SetFlag( 0) ;
if ( AddRapidMove( ptP) == GDB_ID_NULL)
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::AddLinkRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr)
{
// se sopra uscita c'è spazio per approccio
if ( ( dElev + dAppr) > 10 * EPS_SMALL) {
// 4 -> movimento di risalita sopra il punto finale
SetFeed( GetEndFeed()) ;
Point3d ptP4 = ptP + vtTool * ( dElev + dAppr) ;
if ( AddLinearMove( ptP4) == GDB_ID_NULL)
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::AddRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr)
{
// se sopra uscita c'è spazio per sicurezza o approccio
double dSafeDist = dSafeZ ;
if ( dElev + max( dSafeDist, dAppr) > 10 * EPS_SMALL) {
if ( dSafeDist < dAppr + 10 * EPS_SMALL) {
// 4 -> movimento di risalita sopra il punto finale
SetFeed( GetEndFeed()) ;
Point3d ptP4 = ptP + vtTool * ( dElev + dAppr) ;
if ( AddLinearMove( ptP4) == GDB_ID_NULL)
return false ;
}
else {
// 4a -> movimento di risalita appena sopra il punto finale
Point3d ptP4a = ptP + vtTool * ( dElev + dAppr) ;
if ( dElev + dAppr > EPS_SMALL) {
SetFeed( GetEndFeed()) ;
if ( AddLinearMove( ptP4a) == GDB_ID_NULL)
return false ;
}
// 4b -> movimento di risalita sopra il punto finale
Point3d ptP4b = ptP4a + vtTool * ( dSafeDist - dAppr) ;
if ( AddRapidMove( ptP4b) == GDB_ID_NULL)
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------------
int
SurfFinishing::GetLeadInType( void) const
{
if ( abs( m_Params.m_dLiTang) < min( 0.1 * m_TParams.m_dDiam, 0.1) &&
abs( m_Params.m_dLiPerp) < min( 0.1 * m_TParams.m_dDiam, 0.1))
return SURFFIN_LI_NONE ;
return m_Params.m_nLeadInType ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::CalcLeadInStart( const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtTool, const Vector3d& vtNorm, Point3d& ptP1) const
{
// Assegno tipo e parametri
int nType = GetLeadInType() ;
double dTang = m_Params.m_dLiTang ;
double dPerp = m_Params.m_dLiPerp ;
// Calcolo punto iniziale
switch ( nType) {
case SURFFIN_LI_NONE :
ptP1 = ptStart ;
return true ;
case SURFFIN_LI_LINEAR :
case SURFFIN_LI_TANGENT :
{
Vector3d vtPerp = vtStart ;
Vector3d vtRot = OrthoCompo( vtTool, vtStart) ;
vtPerp.Rotate( vtRot, 0, -1) ;
if ( vtPerp * vtNorm < -EPS_ZERO)
vtPerp.Invert() ;
ptP1 = ptStart - vtStart * dTang + vtPerp * dPerp ;
}
return true ;
default :
return false ;
}
}
//----------------------------------------------------------------------------
bool
SurfFinishing::AddLeadIn( const Point3d& ptP1, const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtTool, bool bSplitArcs)
{
// Se inizio e fine coincidono, non devo fare alcunchè
if ( AreSamePointApprox( ptP1, ptStart))
return true ;
// Assegno il tipo
int nType = GetLeadInType() ;
// Eseguo a seconda del tipo
switch ( nType) {
case SURFFIN_LI_NONE :
return true ;
case SURFFIN_LI_LINEAR :
return ( AddLinearMove( ptStart, bSplitArcs, MCH_CL_LEADIN) != GDB_ID_NULL) ;
case SURFFIN_LI_TANGENT :
PtrOwner<ICurve> pCrv( GetArc2PVN( ptStart, ptP1, -vtStart, vtTool)) ;
if ( IsNull( pCrv))
return false ;
pCrv->Invert() ;
return ( AddCurveMove( pCrv, bSplitArcs, MCH_CL_LEADIN) != GDB_ID_NULL) ;
}
return true ;
}
//----------------------------------------------------------------------------
int
SurfFinishing::GetLeadOutType( void) const
{
if ( abs( m_Params.m_dLoTang) < min( 0.1 * m_TParams.m_dDiam, 0.1) &&
abs( m_Params.m_dLoPerp) < min( 0.1 * m_TParams.m_dDiam, 0.1) &&
m_Params.m_nLeadOutType != SURFFIN_LO_AS_LI)
return SURFFIN_LO_NONE ;
return m_Params.m_nLeadOutType ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::CalcLeadOutEnd( const Point3d& ptEnd, const Vector3d& vtEnd, const Vector3d& vtTool, const Vector3d& vtNorm, Point3d& ptP1) const
{
// Assegno tipo e parametri
int nType = GetLeadOutType() ;
double dTang = m_Params.m_dLoTang ;
double dPerp = m_Params.m_dLoPerp ;
// se uscita come ingresso
if ( nType == SURFFIN_LO_AS_LI) {
int nLiType = GetLeadInType() ;
switch ( nLiType) {
case SURFFIN_LI_LINEAR : nType = SURFFIN_LO_LINEAR ; break ;
case SURFFIN_LI_TANGENT : nType = SURFFIN_LO_TANGENT ; break ;
default : nType = SURFFIN_LO_NONE ; break ;
}
dTang = m_Params.m_dLiTang ;
dPerp = m_Params.m_dLiPerp ;
}
// Calcolo punto finale
switch ( nType) {
case SURFFIN_LO_NONE :
ptP1 = ptEnd ;
return true ;
case SURFFIN_LO_LINEAR :
case SURFFIN_LO_TANGENT :
{
// calcolo punto finale dell'uscita
Vector3d vtPerp = vtEnd ;
Vector3d vtRot = OrthoCompo( vtTool, vtEnd) ;
vtPerp.Rotate( vtRot, 0, -1) ;
if ( vtPerp * vtNorm < -EPS_ZERO)
vtPerp.Invert() ;
ptP1 = ptEnd + vtEnd * dTang + vtPerp * dPerp ;
}
return true ;
default :
return false ;
}
}
//----------------------------------------------------------------------------
bool
SurfFinishing::AddLeadOut( const Point3d& ptEnd, const Vector3d& vtEnd, const Point3d& ptP1, const Vector3d& vtTool, bool bSplitArcs)
{
// Se inizio e fine coincidono, non devo fare alcunchè
if ( AreSamePointApprox( ptEnd, ptP1))
return true ;
// Assegno tipo e parametri
int nType = GetLeadOutType() ;
// se uscita come ingresso
if ( nType == SURFFIN_LO_AS_LI) {
int nLiType = GetLeadInType() ;
switch ( nLiType) {
case SURFFIN_LI_LINEAR : nType = SURFFIN_LO_LINEAR ; break ;
case SURFFIN_LI_TANGENT : nType = SURFFIN_LO_TANGENT ; break ;
default : nType = SURFFIN_LO_NONE ; break ;
}
}
// eseguo a seconda del tipo
switch ( nType) {
case SURFFIN_LO_NONE :
return true ;
case SURFFIN_LO_LINEAR :
return ( AddLinearMove( ptP1, bSplitArcs, MCH_CL_LEADOUT) != GDB_ID_NULL) ;
case SURFFIN_LO_TANGENT :
// inserisco uscita
PtrOwner<ICurve> pCrv( GetArc2PVN( ptEnd, ptP1, vtEnd, vtTool)) ;
if ( IsNull( pCrv))
return false ;
// assegno direzione finale dell'uscita
Vector3d vtDirF ;
if ( ! pCrv->GetEndDir( vtDirF))
return false ;
// emetto movimento
return ( AddCurveMove( pCrv, bSplitArcs, MCH_CL_LEADOUT) != GDB_ID_NULL) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::GetLastGoodPoint( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf,
const Point3d& ptStart, const Point3d& ptEnd, const Vector3d& vtTool, Point3d& ptP1) const
{
// porto i punti e il versore nel riferimento superficie
Point3d ptStartL = GetToLoc( ptStart, frSurf) ;
Point3d ptEndL = GetToLoc( ptEnd, frSurf) ;
Vector3d vtToolL = GetToLoc( vtTool, frSurf) ;
// porto i punti dal tip al naso mandrino
ptStartL += vtToolL * m_TParams.m_dLen ;
ptEndL += vtToolL * m_TParams.m_dLen ;
// verifico che il movimento non interferisca con la superficie
PNTULIST lstPntU{ { ptStartL, 0}, { ptEndL, 1}} ;
if ( ! pCAvTlStm->TestPath( lstPntU, vtToolL, vtToolL, m_Params.m_dApprox, 0))
return false ;
// cerco l'ultimo punto non spostato per evitare collisione
bool bFound = false ;
auto currPU = lstPntU.begin() ;
while ( ! bFound && currPU != lstPntU.end()) {
auto nextPU = next( currPU) ;
if ( nextPU == lstPntU.end() || nextPU->second > m_Params.m_dApprox){
bFound = true ;
ptP1 = GetToGlob( currPU->first - vtToolL * m_TParams.m_dLen, frSurf) ;
}
currPU = nextPU ;
}
return bFound ;
}
//----------------------------------------------------------------------------
bool
SurfFinishing::GetSurfaceNormalAtPoint( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf,
const Point3d& ptTool, const Vector3d& vtTool, Vector3d& vtNorm) const
{
// porto il punto e il versore nel riferimento superficie
Point3d ptToolL = GetToLoc( ptTool, frSurf) ;
Vector3d vtToolL = GetToLoc( vtTool, frSurf) ;
// porto i punti dal tip al naso mandrino
ptToolL += vtToolL * m_TParams.m_dLen ;
// affondo di poco il punto per ricavare ultima superficie di contatto e sua normale
double dMove ;
Vector3d vtNormL ;
if ( ! pCAvTlStm->TestPosition( ptToolL - vtToolL, vtToolL, vtToolL, dMove, &vtNormL) || dMove < EPS_SMALL)
return false ;
// porto la normale in globale
vtNorm = GetToGlob( vtNormL, frSurf) ;
return true ;
}
//----------------------------------------------------------------------------
double
SurfFinishing::GetRightFeed( const Vector3d& vtMove, const Vector3d& vtTool) const
{
// Determino i versori
Vector3d vtM = vtMove ;
vtM.Normalize() ;
Vector3d vtT = vtTool ;
vtT.Normalize() ;
// Angolo tra movimento e versore utensile
double dCosMove = vtM * vtT ;
// Se l'utensile non ha movimento significativo di punta, si restituisce la feed standard
if ( dCosMove > - COS_ORTO_ANG_SMALL)
return GetFeed() ;
// Altrimenti non si deve superare la massima velocità di punta prevista
return min( GetFeed(), GetTipFeed() / abs( dCosMove)) ;
}
//----------------------------------------------------------------------------
double
SurfFinishing::GetRadiusForStartEndElevation( void) const
{
const double DELTA_ELEV_RAD = 4.0 ;
double dDeltaRad = min( DELTA_ELEV_RAD, 0.5 * m_TParams.m_dTDiam) ;
return ( 0.5 * m_TParams.m_dTDiam + dDeltaRad) ;
}