b74f0d407d
- 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.
4711 lines
196 KiB
C++
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) ;
|
|
}
|