Files
EgtMachKernel/SurfRoughing.cpp
Riccardo Elitropi 1b97ec5310 EgtMachKernel :
- in PocketingNT, SurfFinishing e SurfRoughing aggiunto flag per Conventional Milling per curve di svuotatura singole.
2026-05-11 10:03:58 +02:00

5031 lines
214 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2024-2024
//----------------------------------------------------------------------------
// File : SurfRoughing.cpp Data : 24.05.24 Versione : 2.6e5
// Contenuto : Implementazione gestione sgrossatura superfici.
//
// Note : Questa lavorazione è sempre espressa nel riferimento globale.
//
// Modifiche : 24.05.24 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "MachMgr.h"
#include "DllMain.h"
#include "SurfRoughing.h"
#include "OperationConst.h"
#include "OperUserNotesConst.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/EGkSurfTriMesh.h"
#include "/EgtDev/Include/EGkSurfBezier.h"
#include "/EgtDev/Include/EGkSfrCreate.h"
#include "/EgtDev/Include/EGkStmStandard.h"
#include "/EgtDev/Include/EGkCalcPocketing.h"
#include "/EgtDev/Include/EGkSurfLocal.h"
#include "/EgtDev/Include/EGkCAvSilhouetteSurfTm.h"
#include "/EgtDev/Include/EGkIntervals.h"
#include "/EgtDev/Include/EGkStringUtils3d.h"
#include "/EgtDev/Include/EGkUserObjFactory.h"
#include "/EgtDev/Include/EGnStringKeyVal.h"
#include "/EgtDev/Include/EGkDistPointCurve.h"
#include "/EgtDev/Include/EGkDistPointSurfFr.h"
#include "/EgtDev/Include/EGkCurveAux.h"
#include "/EgtDev/Include/EGkDistPointSurfTm.h"
#include "/EgtDev/Include/EGkIntersPlaneSurfTm.h"
#include "/EgtDev/Include/EGkStmFromCurves.h"
#include "/EgtDev/Include/EGkPolygon3d.h"
#include "/EgtDev/Include/EGkPolygonElevation.h"
// per far dimenticare macro di WinUser.h
#undef GetClassName
using namespace std ;
//------------------------------ Errors --------------------------------------
// 3001 = "Error in SurfRoughing : UpdateToolData failed"
// 3002 = "Error in SurfRoughing : Tool loading failed"
// 3003 = "Error in SurfRoughing : Chaining failed"
// 3004 = "Error in SurfRoughing : Open Contour"
// 3005 = "Error in SurfRoughing : Contour Not Flat"
// 3006 = "Error in SurfRoughing : Tool Dir not perpendicular to Flat Area"
// 3007 = "Error in SurfRoughing : Empty RawBox"
// 3008 = "Error in SurfRoughing : Depth not computable"
// 3009 = "Error in SurfRoughing : Offset not computable"
// 3010 = "Error in SurfRoughing : Toolpath not computable"
// 3011 = "Error in SurfRoughing : Approach not computable"
// 3012 = "Error in SurfRoughing : Link not computable"
// 3013 = "Error in SurfRoughing : LeadIn not computable"
// 3014 = "Error in SurfRoughing : LeadOut not computable"
// 3015 = "Error in SurfRoughing : Retract not computable"
// 3016 = "Error in SurfRoughing : axes values not calculable"
// 3017 = "Error in SurfRoughing : outstroke xx"
// 3018 = "Error in SurfRoughing : link movements not calculable"
// 3019 = "Error in SurfRoughing : link outstroke"
// 3020 = "Error in SurfRoughing : post apply not calculable"
// 3021 = "Error in SurfRoughing : Linear Approx not computable"
// 3022 = "Error in SurfRoughing : aggregate from bottom not allowed"
// 3023 = "Error in SurfRoughing : missing surfaces"
// 3024 = "Error in SurfRoughing : region not computable"
// 3025 = "Error in SurfRoughing : RawPart not computable"
// 3026 = "Error in SurfRoughing : Detecting open edges failed"
// 3027 = "Error in SurfRoughing : Slicing Raw failed"
// 3028 = "Error in SurfRoughing : Error in CalcPocketing"
// 3029 = "Error in SurfRoughing : Simplify Chunks for SubSteps failed"
// 3030 = "Error in SurfRoughing : Conformal ZigZag not valid at step (xx)"
// 3031 = "Error in SurfRoughing : LeadIn with Mill NoTip in material"
// 3032 = "Error in SurfRoughing : Curves with different extrusion"
// 3033 = "Error in SurfRoughing : CalcRegion elevation failed"
// 3034 = "Error in SurfRoughing : Linking paths failed"
// 3035 = "Error in SurfRoughing : Entity without Info"
// 3036 = "Error in SurfRoughing : special apply not calculable"
// 3051 = "Warning in SurfRoughing : Skipped entity (xx)"
// 3052 = "Warning in SurfRoughing : No machinable path"
// 3053 = "Warning in SurfRoughing : Tool name changed (xx)"
// 3054 = "Warning in SurfRoughing : Tool data changed (xx)"
// 3055 = "Warning in SurfRoughing : CalcPocketing failed with substep (xx)"
// 3056 = "Warning in SurfRoughing : invalid Conformal ZigZag at substep (xx)"
// 3057 = "Warning in SurfRoughing : Depth reduced at (xx)"
//----------------------------------------------------------------------------
static string KEY_SURF_POCK = "SurfPock_" ;
static string KEY_SURF_LIMIT = "SurfLimit_" ;
static string KEY_OPEN = "OPEN" ;
static string KEY_THICK = "THICK" ;
static string SRF_SUPP_LAYER_NAME = "SUPP" ;
static string KEY_DEPTH = "DEPTH" ;
static string KEY_RELATIVE_DEPTH = "RELATIVEDEPTH" ;
static string KEY_ZLOCFEEDCOEF = "ZLOCFEEDCOEFF" ;
static string KEY_SUBSTEP = "SUBSTEP" ;
#define ENABLE_DEBUG_SFR 0
#define ENABLE_DEBUG_STM_NORMAL_SHADER 0
#define ENABLE_DEBUG_REMOVED_REGION 0
#define ENABLE_DEBUG_FEEDS 0
#define ENABLE_DEBUG_SFR_BOOLEANS 0
#define ENABLE_DEBUG_SFR_COLLISION 0
#define ENABLE_DEBUG_ZPLANE 0
#define ENBALE_DEBUG_LINK 0
#define ENABLE_DEBUG_ORDER_ZCHUNK 0
#if ENABLE_DEBUG_SFR || ENABLE_DEBUG_STM_NORMAL_SHADER || ENABLE_DEBUG_REMOVED_REGION || \
ENABLE_DEBUG_FEEDS || ENABLE_DEBUG_SFR_BOOLEANS || ENABLE_DEBUG_SFR_COLLISION || ENABLE_DEBUG_ZPLANE || \
ENBALE_DEBUG_LINK || ENABLE_DEBUG_ORDER_ZCHUNK
#include "/EgtDev/Include/EGkGeoPoint3d.h"
#include "/EgtDev/Include/EGkGeoVector3d.h"
#include "/EgtDev/Include/EgtPerfCounter.h"
#include "/EgtDev/Include/EGkExtText.h"
string sPathSrfBool = "C:\\Temp\\" ;
int nGrpDebugFeed = GDB_ID_NULL, nLayDebugFeed = GDB_ID_NULL ;
#endif
const double STEP_TOL = 10. * EPS_SMALL ;
const double SIL_DEPTH_TOL = 100. * EPS_SMALL ;
const double OFFS_CORR_OPEN_EDGES = 25. * EPS_SMALL ;
const double TOL_OFFS_CORNER_COLL = 50. * EPS_SMALL ;
const double DIST_TABLE = 5. * EPS_SMALL ;
//----------------------------------------------------------------------------
USEROBJ_REGISTER( GetOperationClass( OPER_SURFROUGHING), SurfRoughing) ;
//----------------------------------------------------------------------------
const string&
SurfRoughing::GetClassName( void) const
{
return USEROBJ_GETNAME( SurfRoughing) ;
}
//----------------------------------------------------------------------------
SurfRoughing*
SurfRoughing::Clone( void) const
{
// alloco oggetto
SurfRoughing* pSrR = new(nothrow) SurfRoughing ;
// eseguo copia dei dati
if ( pSrR != nullptr) {
try {
pSrR->m_vId = m_vId ;
pSrR->m_pMchMgr = m_pMchMgr ;
pSrR->m_nPhase = m_nPhase ;
pSrR->m_Params = m_Params ;
pSrR->m_TParams = m_TParams ;
pSrR->m_dTHoldBase = m_dTHoldBase ;
pSrR->m_dTHoldLen = m_dTHoldLen ;
pSrR->m_dTHoldDiam = m_dTHoldDiam ;
pSrR->m_nStatus = m_nStatus ;
pSrR->m_nPaths = m_nPaths ;
pSrR->m_dMaxHelixRad = m_dMaxHelixRad ;
}
catch( ...) {
delete pSrR ;
return nullptr ;
}
}
// ritorno l'oggetto
return pSrR ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::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
SurfRoughing::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
SurfRoughing::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 ;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
SurfRoughing::SurfRoughing( 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 ;
m_dMaxHelixRad = INFINITO ;
m_dSubStepToler = 2.0 / 2 ;
m_dStepToler = 1.0 / 2 ;
m_bDetectPlaneZ = false ;
m_bOrderZ = false ;
m_bRunning = false ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::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 SurfRoughingData* pDdata = GetSurfRoughingData( 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
SurfRoughing::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
SurfRoughing::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
SurfRoughing::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_OFFSL :
if ( AreSameLenValue( dVal, m_TParams.m_dOffsL))
dVal = UNKNOWN_PAR ;
if ( ! AreSameLenValue( dVal, m_Params.m_dOffsL))
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dOffsL = 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_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_STEP :
if ( ! AreSameLenValue( dVal, m_Params.m_dStep))
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dStep = dVal ;
return true ;
case MPA_SUBSTEP :
if ( ! AreSameLenValue( dVal, m_Params.m_dSubStep))
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dSubStep = 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_LIELEV :
if ( abs( dVal - m_Params.m_dLiElev) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dLiElev = 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_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_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
SurfRoughing::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
SurfRoughing::SetGeometry( const SELVECTOR& vIds)
{
// verifico validità gestore DB geometrico
if ( m_pGeomDB == nullptr)
return false ;
// copia temporanea e reset della geometria corrente
SELVECTOR vOldId = m_vId ;
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 SurfRoughing : Skipped entity " + ToString( Id) ;
m_pMchMgr->SetWarning( 3051, sInfo) ;
continue ;
}
// posso aggiungere alla lista
m_vId.emplace_back( Id) ;
}
// aggiorno lo stato
if ( m_vId != vOldId)
m_nStatus |= MCH_ST_GEO_MODIF ;
// restituisco presenza geometria da lavorare
return ( ! m_vId.empty()) ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::Preview( bool bRecalc)
{
// non esiste preview, si fa apply
return Apply( bRecalc, false) ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::Apply( bool bRecalc, bool bPostApply)
{
// se calcoli già in corso, esco
if ( m_bRunning) {
LOG_DBG_INFO( GetEMkLogger(), "SurfRoughing::Apply already running") ;
return true ;
}
m_bRunning = true ;
bool bOk = MyApply( bRecalc, bPostApply) ;
m_bRunning = false ;
return bOk ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::MyApply( 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
if ( ! UpdateToolData()) {
m_pMchMgr->SetLastError( 3001, "Error in SurfRoughing : UpdateToolData failed") ;
return false ;
}
// non è prevista sgrossatura superficie con aggregato da sotto
if ( IsAggrBottom( m_TParams.m_sHead)) {
m_pMchMgr->SetLastError( 3022, "Error in SurfRoughing : aggregate from bottom not allowed") ;
return false ;
}
// se modificata geometria, necessario ricalcolo
if ( ( m_nStatus & MCH_ST_GEO_MODIF) != 0)
bRecalc = true ;
// verifico se necessario continuare nell'aggiornamento
if ( ! bRecalc && ( m_nStatus == MCH_ST_OK || m_nStatus == MCH_ST_NO_POSTAPPL)) {
// confermo i percorsi di lavorazione
m_nPaths = nCurrPaths ;
string sLog = string( "SurfRoughing 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( 3002, "Error in SurfRoughing : 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) ;
// 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) ;
// elimino eventuale gruppo geometria simmetrica per lavorazione in doppio
int nDblId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_DBL) ;
if ( nDblId != GDB_ID_NULL) {
m_pGeomDB->Erase( nDblId) ;
nDblId = GDB_ID_NULL ;
}
// se necessario, eseguo concatenamento ed inserisco i percorsi sotto la geometria ausiliaria
if ( bChain && ! Chain( nAuxId)) {
m_pMchMgr->SetLastError( 3003, "Error in SurfRoughing : Chaining failed") ;
return false ;
}
// lavoro ogni singola regione piana
bool bOk = true ;
int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ;
while ( nPathId != GDB_ID_NULL) {
if ( ! ProcessPath( nPathId, GDB_ID_NULL, nClId))
bOk = false ;
nPathId = m_pGeomDB->GetNextGroup( nPathId) ;
}
if ( ! bOk)
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(), "SurfRoughing apply done") ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::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( 3052, "Warning in SurfRoughing : 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( 3016, "Error in SurfRoughing : axes values not calculable") ;
else
m_pMchMgr->SetLastError( 3017, "Error in SurfRoughing : outstroke ") ;
return false ;
}
// assegno estremi degli assi dei vari percorsi di lavorazione e della lavorazione nel suo complesso
CalcAndSetAxesBBox() ;
// esecuzione eventuali personalizzazioni speciali
string sSpecErr ;
if ( bPostApply && ! SpecialApply( sSpecErr)) {
if ( ! IsEmptyOrSpaces( sSpecErr))
m_pMchMgr->SetLastError( 3036, sSpecErr) ;
else
m_pMchMgr->SetLastError( 3036, "Error in SurfRoughing : special apply not calculable") ;
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( 3018, "Error in SurfRoughing : link movements not calculable") ;
else
m_pMchMgr->SetLastError( 3019, "Error in SurfRoughing : link outstroke ") ;
return false ;
}
// esecuzione eventuali personalizzazioni finali
string sPostErr ;
if ( bPostApply && ! PostApply( sPostErr)) {
if ( ! IsEmptyOrSpaces( sPostErr))
m_pMchMgr->SetLastError( 3020, sPostErr) ;
else
m_pMchMgr->SetLastError( 3020, "Error in SurfRoughing : post apply not calculable") ;
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::GetParam( int nType, bool& bVal) const
{
switch ( nType) {
case MPA_INVERT :
bVal = m_Params.m_bInvert ;
return true ;
}
bVal = false ;
return false ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::GetParam( int nType, int& nVal) const
{
switch ( nType) {
case MPA_TYPE :
nVal = MT_SURFROUGHING ;
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
SurfRoughing::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_OFFSL :
dVal = GetOffsL() ;
return true ;
case MPA_STARTPOS :
dVal = m_Params.m_dStartPos ;
return true ;
case MPA_OVERL :
dVal = m_Params.m_dOverlap ;
return true ;
case MPA_STEP :
dVal = m_Params.m_dStep ;
return true ;
case MPA_SUBSTEP :
dVal = m_Params.m_dSubStep ;
return true ;
case MPA_SIDESTEP :
dVal = m_Params.m_dSideStep ;
return true ;
case MPA_SIDEANGLE :
dVal = m_Params.m_dSideAngle ;
return true ;
case MPA_LIELEV :
dVal = m_Params.m_dLiElev ;
return true ;
case MPA_LITANG :
dVal = m_Params.m_dLiTang ;
return true ;
case MPA_LOTANG :
dVal = m_Params.m_dLoTang ;
return true ;
case MPA_APPROX :
dVal = m_Params.m_dApprox ;
return true ;
}
dVal = 0 ;
return false ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::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&
SurfRoughing::GetToolData( void) const
{
return m_TParams ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::UpdateToolData()
{
// 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 SurfRoughing : tool name changed (" +
m_Params.m_sToolName + "->" + m_TParams.m_sName + ")" ;
m_pMchMgr->SetWarning( 3053, sInfo) ;
m_Params.m_sToolName = m_TParams.m_sName ;
}
if ( bChanged) {
string sInfo = "Warning in SurfRoughing : tool data changed (" +
m_Params.m_sToolName + ")" ;
m_pMchMgr->SetWarning( 3054, sInfo) ;
}
// se modificato, aggiusto lo stato
if ( bChanged)
m_nStatus = MCH_ST_TO_VERIFY ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::GetGeometry( SELVECTOR& vIds) const
{
// restituisco l'elenco delle entità
vIds = m_vId ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::AdjustEndPointForAxesCalc( const CamData* pCamData, Point3d& ptP) const
{
// compenso il raggio dell'utensile
ptP += pCamData->GetCorrDir() * ( m_TParams.m_dDiam / 2) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::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) ;
}
// se altrimenti è superficie Bezier
else if ( pGObj->GetType() == SRF_BEZIER) {
const ISurfBezier* pSurf = ::GetSurfBezier( pGObj) ;
return ( pSurf != nullptr && pSurf->IsValid()) ;
}
// altrimenti errore
else
return false ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::GetCurves( SelData Id, ICURVEPLIST& lstPC)
{
// ammessi : curve, superfici TriMesh e superfici Bezier
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 ;
// recupero il tipo
int nType = pGObj->GetType() ;
// se curva
if ( ( nType & 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 superficie TriMesh
else if ( nType == SRF_TRIMESH)
return true ;
// se superficie Bezier
else if ( nType == SRF_BEZIER)
return true ;
// altrimenti errore
else
return false ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::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 SurfRoughing : Skipped entity " + ToString( Id) ;
m_pMchMgr->SetWarning( 3051, sInfo) ;
}
for ( auto pCrv : lstPC) {
vpCrvs.emplace_back( pCrv) ;
vInds.emplace_back( Id) ;
}
}
// 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( 3032, "Error in SurfRoughing : Curves with different extrusion") ;
return false ;
}
}
}
// recupero i percorsi concatenati e definisco la regione piana di sgrossatura
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
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
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 ;
// se la curva non è chiusa, errore
if ( ! pCrvCompo->IsClosed()) {
m_pMchMgr->SetLastError( 3004, "Error in SurfRoughing : Open Contour") ;
return false ;
}
// 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( 3005, "Error in SurfRoughing : Contour Not Flat") ;
else
m_pMchMgr->SetLastError( 3006, "Error in SurfRoughing : Tool Dir not perpendicular to Flat Area") ;
return false ;
}
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 = 0 ;
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 ;
// scorro i loop della regione
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 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
SurfRoughing::CalcRegionElevation( const ICurveComposite* pCompo, const Vector3d& vtTool, double dDepth, double dRad, double dLen,
double& dElev) const
{
// inizializzo l'elevazione
dElev = 0 ;
// approssimo la curva con una polilinea che uso per creare il poligono equivalente
PolyLine PL ;
if ( ! pCompo->ApproxWithLines( LIN_TOL_RAW, ANG_TOL_MAX_DEG, ICurve::APL_SPECIAL, PL))
return false ;
Polygon3d pgFacet ;
if ( ! pgFacet.FromPolyLine( PL))
return false ;
// aggiungo l'affondamento
pgFacet.Translate( -dDepth * vtTool) ;
// inizializzo elevazioni per ogni grezzo
INTDBLVECTOR vRawElev ;
// ciclo sui grezzi della fase
int nRawId = m_pMchMgr->GetFirstRawPart() ;
while ( nRawId != GDB_ID_NULL) {
// verifico che il grezzo compaia nella fase
if ( m_pMchMgr->VerifyRawPartPhase( nRawId, m_nPhase)) {
// recupero la trimesh del grezzo
int nStmId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_SOLID) ;
const ISurfTriMesh* pStm = GetSurfTriMesh( m_pGeomDB->GetGeoObj( nStmId)) ;
if ( pStm != nullptr) {
// recupero il riferimento della trimesh
Frame3d frStm ;
m_pGeomDB->GetGlobFrame( nStmId, frStm) ;
// porto il poligono in questo riferimento
Polygon3d pgFacetL = pgFacet ;
pgFacetL.ToLoc( frStm) ;
// calcolo l'elevazione
double dCurrElev ;
if ( ! PolygonElevationInClosedSurfTm( pgFacetL, *pStm, true, dCurrElev))
return false ;
if ( dCurrElev > EPS_SMALL)
vRawElev.emplace_back( nStmId, dCurrElev) ;
}
}
// passo al grezzo successivo
nRawId = m_pMchMgr->GetNextRawPart( nRawId) ;
}
// se trovate elevazioni
if ( ! vRawElev.empty()) {
// ordino il vettore secondo l'elevazione crescente
sort( vRawElev.begin(), vRawElev.end(), []( const INTDBL& a, const INTDBL& b)
{ return a.second < b.second ; }) ;
// box dell'insieme delle posizioni utensile all'inizioe
const double MAX_DIST_RAW = 200.0 ;
BBox3d b3Tool ;
pgFacet.GetLocalBBox( b3Tool) ;
b3Tool.Add( b3Tool.GetMin() + dLen * vtTool) ;
b3Tool.Add( b3Tool.GetMax() + dLen * vtTool) ;
if ( vtTool.IsX())
b3Tool.Expand( 0, dRad, dRad) ;
else if ( vtTool.IsY())
b3Tool.Expand( dRad, 0, dRad) ;
else if ( vtTool.IsZ())
b3Tool.Expand( dRad, dRad, 0) ;
else {
double dExpandX = dRad * sqrt( 1 - vtTool.x * vtTool.x) ;
double dExpandY = dRad * sqrt( 1 - vtTool.y * vtTool.y) ;
double dExpandZ = dRad * sqrt( 1 - vtTool.z * vtTool.z) ;
b3Tool.Expand( dExpandX, dExpandY, dExpandZ) ;
}
b3Tool.Expand( MAX_DIST_RAW) ;
// verifico la reale interferenza dell'utensile con i diversi grezzi
for ( int i = 0 ; i < int( vRawElev.size()) ; ++ i) {
// box del grezzo
BBox3d b3Raw ;
m_pGeomDB->GetGlobalBBox( vRawElev[i].first, b3Raw) ;
// confronto con il box dell'utensile nella posizione precedente
BBox3d b3CurrTool = b3Tool ;
b3CurrTool.Translate( dElev * vtTool) ;
if ( b3Raw.Overlaps( b3CurrTool))
dElev = vRawElev[i].second ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::ProcessPath( int nPathId, int nPvId, int nClId)
{
// aggiorno la ProgressBar del 5% per simulare l'inizio della funzione
ExeProcessEvents( 5, 0) ;
// 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 ;
PtrOwner<ISurfFlatRegion> pSfrSgro( CloneSurfFlatRegion( m_pGeomDB->GetGeoObj( nCopyId))) ;
if ( IsNull( pSfrSgro) || ! pSfrSgro->IsValid())
return false ;
// recupero estrusione
Vector3d vtExtr = Z_AX ;
if ( m_pGeomDB->ExistsInfo( nSfrId, KEY_EXTR))
m_pGeomDB->GetInfo( nSfrId, KEY_EXTR, vtExtr) ;
// controllo che l'estrusione sia coerente con la normale della superficie
if ( AreSameOrOppositeVectorApprox( pSfrSgro->GetNormVersor(), vtExtr)) {
if ( AreOppositeVectorApprox( pSfrSgro->GetNormVersor(), vtExtr))
pSfrSgro->Invert() ;
}
else {
m_pMchMgr->SetLastError( 3006, "Error in SurfRoughing : Tool Dir not perpendicular to Flat Area") ;
return false ;
}
// recupero lo spessore e valuto l'espressione dell'affondamento
double dThick = 0. ;
if ( m_pGeomDB->ExistsInfo( nSfrId, KEY_THICK))
m_pGeomDB->GetInfo( nSfrId, KEY_THICK, dThick) ;
ExeLuaSetGlobNumVar( "TH", abs( dThick)) ;
double dDepth ;
string sMyDepth = m_Params.m_sDepth ;
if ( ! ExeLuaEvalNumExpr( ToUpper( sMyDepth), &dDepth)) {
m_pMchMgr->SetLastError( 3008, "Error in SurfRoughing : Depth not computable") ;
return false ;
}
// se spessore positivo, lo sottraggo dal 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( 3007, "Error in SurfRoughing : Empty RawBox") ;
return false ;
}
// recupero nome del path
string sPathName ;
m_pGeomDB->GetName( nPathId, sPathName) ;
// assegno il versore fresa
Vector3d vtTool = vtExtr ;
// calcolo l'elevazione al di sopra di tale regione e l'affondamento al di sotto
double dSfrMaxElev = 0. ;
double dSfrMaxDepth = 0. ;
for ( int nC = 0 ; nC < pSfrSgro->GetChunkCount() ; ++ nC) {
for ( int nL = 0 ; nL < pSfrSgro->GetLoopCount( nC) ; ++ nL) {
// recupero la curva
PtrOwner<ICurveComposite> pCrvLoop( ConvertCurveToComposite( pSfrSgro->GetLoop( nC, nL))) ;
if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid())
return false ;
// se isola inverto
if ( nL > 0)
pCrvLoop->Invert() ;
// determino l'elevazione
double dSfrElev = 0. ;
if ( ! CalcRegionElevation( pCrvLoop, vtTool, 0., 0.5 * m_TParams.m_dDiam, m_TParams.m_dLen, dSfrElev)) {
m_pMchMgr->SetLastError( 3033, "Error in SurfRoughing : Calc Region elevation failed") ;
return false ;
}
// aggiorno l'elevazione massima
dSfrMaxElev = max( dSfrElev, dSfrMaxElev) ;
// determino l'affondamento
pCrvLoop->Invert() ;
double dSfrDepth = 0. ;
if ( ! CalcRegionElevation( pCrvLoop, vtTool, 0., 0.5 * m_TParams.m_dDiam, m_TParams.m_dLen, dSfrDepth)) {
m_pMchMgr->SetLastError( 3033, "Error in SurfRoughing : Calc Region elevation failed") ;
return false ;
}
// aggiorno l'affondamento massimo
dSfrMaxDepth = max( dSfrDepth, dSfrMaxDepth) ;
}
}
// se la regione interseca il grezzo
if ( dSfrMaxElev > EPS_SMALL) {
// eventuale imposizione massima elevazione da note utente
double dMaxElev ;
if ( GetValInNotes( m_Params.m_sUserNotes, UN_MAXELEV, dMaxElev) && dSfrMaxElev > dMaxElev - dDepth)
dSfrMaxElev = dMaxElev - dDepth ;
// la regione viene traslata dell'elevazione trovata lungo vtTool
pSfrSgro->Translate( dSfrMaxElev * vtTool) ;
// la Depth viene incrementata del valore di traslazione
dDepth += dSfrMaxElev ;
dSfrMaxDepth += dSfrMaxElev ;
}
// aggiustiamo l'affondamento se eccesivo
const double MAX_DEPTH_EXTRA = 3 ;
dDepth = min( dDepth, dSfrMaxDepth + MAX_DEPTH_EXTRA) ;
// controllo se richiesto PlaneZDetection
bool bPlaneZDetection = false ;
m_bDetectPlaneZ = ( GetValInNotes( m_Params.m_sUserNotes, UN_PLANEZ, bPlaneZDetection) && bPlaneZDetection) ;
// controllo se richiesto ordinamento dei Chunk lungo vtTool
bool bOrderZ = false ;
m_bOrderZ = ( GetValInNotes( m_Params.m_sUserNotes, UN_ORDER, bOrderZ) && bOrderZ) ;
// NB. [ le superfici vengono riordinate e divise per Chunks prima di essere inserite nel gruppo
// temporaneo. L'analisi per la superficie di Sgrossatura, Limite e Removed non dipende
// dall'ordine, ma semplicemente dalla quota Z del piano di sgrossatura ]
// controllo se presente parametro di Offset radiale per superfici di supporto
double dSuppRadOffs = 5. ;
double dSuppRadOffsByNotes = 0. ;
if ( GetValInNotes( m_Params.m_sUserNotes, UN_SUPP_RAD_OFFS, dSuppRadOffsByNotes) &&
dSuppRadOffsByNotes > - EPS_ZERO)
dSuppRadOffs = dSuppRadOffsByNotes ;
// creo un frame centrato sulla superficie
Frame3d frSfr ;
Point3d ptCenter ; pSfrSgro->GetCentroid( ptCenter) ;
if ( ! frSfr.Set( ptCenter, vtTool))
return false ;
// non prevista gestione anteprima di lavorazione
// 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) ;
// recupero le superfici attive e le superfici di supporto
INTVECTOR vSurfId ;
INTVECTOR vSurfSuppId ;
GetActiveSurfaces( vSurfId, vSurfSuppId) ;
if ( vSurfId.empty()) {
m_pMchMgr->SetLastError( 3023, "Error in SurfRoughing : missing surfaces") ;
return false ;
}
// recupero il grezzo
PtrOwner<ISurfTriMesh> pStmRaw( GetRaw()) ;
if ( IsNull( pStmRaw)) {
m_pMchMgr->SetLastError( 3025, "Error in SurfRoughing : RawPart not computable") ;
return false ;
}
// verifico se presente parametro di Overlap
if ( m_Params.m_dOverlap > 10. * EPS_SMALL) {
if ( ! pSfrSgro->Offset( m_Params.m_dOverlap, ICurve::OFF_EXTEND) || ! pSfrSgro->IsValid())
return false ;
}
// inizializzo la classe di intersezione tra grezzo e piani paralleli ( quelli di lavoro)
// traslo leggermente il grezzo per gestire il primo e l'ultimo Step
pStmRaw->Translate( - vtTool * 5 * EPS_SMALL) ;
IntersParPlanesSurfTm IPPStm( frSfr, *pStmRaw) ;
// costruisco una superficie di estrusione della curva (devo determinare parte della regione limite)
Vector3d vtLimitExtr = - vtTool * 1.5 * max( b3Raw.GetDimX(), max( b3Raw.GetDimY(), b3Raw.GetDimZ())) ;
PtrOwner<ISurfTriMesh> pStmLimit( GetStmOutSideSfr( pSfrSgro, dDepth, pStmRaw, vtLimitExtr)) ;
if ( IsNull( pStmLimit))
return false ;
// determino la regione piana di tavola e ventose per evitare collisioni
// NB. creo una regione piana perchè questa è statica per ogni step, non si adatta
PtrOwner<ISurfFlatRegion> pSfrColl( CreateSurfFlatRegion()) ;
PtrOwner<ISurfFlatRegion> pSfrSearchCorners( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrColl) || IsNull( pSfrSearchCorners) ||
! GetToolCollisionRegion( pSfrSgro, dDepth, pSfrColl, pSfrSearchCorners))
return false ;
// inizializzo la classe di intersezione tra la superficie trimesh limite e piani paralleli ( quelli di lavoro)
IntersParPlanesSurfTm IPPStm1( frSfr, *pStmLimit) ;
// inizializzo la classe di calcolo delle silhouette per le superfici attive nei piani come sopra
SURFLOCALVECTOR vSurfL ; vSurfL.reserve( vSurfId.size()) ;
CISURFTMPVECTOR vpStm ; vpStm.reserve( vSurfId.size()) ;
for ( int i = 0 ; i < int( vSurfId.size()) ; ++ i) {
// superfici ammesse : TriMesh, Bezier
vSurfL.emplace_back( m_pGeomDB, vSurfId[i], GLOB_FRM) ;
if ( vSurfL[i].Get() == nullptr)
return false ;
const ISurf* pSurf = GetSurf( vSurfL[i].Get()) ;
if ( pSurf != nullptr && pSurf->IsValid()) {
int nType = pSurf->GetType() ;
// se TriMesh
if ( nType == SRF_TRIMESH) {
const ISurfTriMesh* pStm = GetSurfTriMesh( pSurf) ;
if ( pStm != nullptr && pStm->IsValid() && pStm->GetTriangleCount() > 0)
vpStm.emplace_back( pStm) ;
}
// se Bezier
else if ( nType == SRF_BEZIER) {
const ISurfBezier* pSBz = GetSurfBezier( pSurf) ;
if ( pSBz != nullptr && pSBz->IsValid()) {
double dOldTol = GetSurfBezierAuxSurfRefinedTol() ;
SetSurfBezierAuxSurfRefinedTol( 5. * EPS_SMALL) ;
const ISurfTriMesh* pStm = pSBz->GetAuxSurfRefined() ;
SetSurfBezierAuxSurfRefinedTol( dOldTol) ;
if ( pStm != nullptr && pStm->IsValid() && pStm->GetTriangleCount() > 0)
vpStm.emplace_back( pStm) ;
}
}
#if ENABLE_DEBUG_STM_NORMAL_SHADER
DrawNormalShaderSurfTm( vpStm.back(), ToString( i)) ;
#endif
}
}
const double SILH_TOL = 1.0 ;
PtrOwner<ICAvParSilhouettesSurfTm> pCavParSilh( CreateCAvParSilhouettesSurfTm()) ;
if ( IsNull( pCavParSilh) || ! pCavParSilh->SetData( vpStm, frSfr, SILH_TOL))
return false ;
// inizializzo la classe di calcolo delle silhouette per le superfici di supporto nei piani come sopra
SURFLOCALVECTOR vSurfL_supp ;
CISURFTMPVECTOR vpStm_supp ;
PtrOwner<ICAvParSilhouettesSurfTm> pCavParSilh_supp( CreateCAvParSilhouettesSurfTm()) ;
if ( IsNull( pCavParSilh_supp))
return false ;
if ( ! vSurfSuppId.empty()) {
vSurfL_supp.reserve( vSurfSuppId.size()) ;
vpStm.reserve( vSurfSuppId.size()) ;
for ( int i = 0 ; i < int( vSurfSuppId.size()) ; ++ i) {
// superfici ammesse : TriMesh, Bezier
vSurfL_supp.emplace_back( m_pGeomDB, vSurfSuppId[i], GLOB_FRM) ;
if ( vSurfL_supp[i].Get() == nullptr)
return false ;
const ISurf* pSurf = GetSurf( vSurfL_supp[i].Get()) ;
if ( pSurf != nullptr && pSurf->IsValid()) {
int nType = pSurf->GetType() ;
// se TriMesh
if ( nType == SRF_TRIMESH) {
const ISurfTriMesh* pStm = GetSurfTriMesh( pSurf) ;
if ( pStm != nullptr && pStm->IsValid() && pStm->GetTriangleCount() > 0)
vpStm_supp.emplace_back( pStm) ;
}
// se Bezier
else if ( nType == SRF_BEZIER) {
const ISurfBezier* pSBz = GetSurfBezier( pSurf) ;
if ( pSBz != nullptr && pSBz->IsValid()) {
double dOldTol = GetSurfBezierAuxSurfRefinedTol() ;
SetSurfBezierAuxSurfRefinedTol( 5. * EPS_SMALL) ;
const ISurfTriMesh* pStm = pSBz->GetAuxSurfRefined() ;
SetSurfBezierAuxSurfRefinedTol( dOldTol) ;
if ( pStm != nullptr && pStm->IsValid() && pStm->GetTriangleCount() > 0)
vpStm_supp.emplace_back( pStm) ;
}
}
}
}
if ( ! pCavParSilh_supp->SetData( vpStm_supp, frSfr, SILH_TOL))
return false ;
}
// vettore Id salvati nel gruppo Temp
INTINTVECTOR vPocket ;
// vettore delle curve composite con proprietà Aperto/Chiuso riferite ai vari step della curva originale
ICRVCOMPOPOVECTOR vCrvPocketCompo ;
// definisco la dimensione dello step ( base ) e il numero di passate
double dOkStep = min( m_Params.m_dStep, m_TParams.m_dMaxMat + EPS_SMALL) ;
int nStep = max( 1, static_cast<int>( ceil( dDepth / dOkStep))) ;
double dStep = dDepth / nStep ;
// definisco la dimensione degli step intermedi ( subSteps ) e il numero di passate [ se definiti ]
double dOkSubStep = -1. ;
int nSubStep = -1 ;
double dSubStep = -1. ;
if ( m_Params.m_dSubStep > EPS_SMALL && m_Params.m_dSubStep < m_Params.m_dStep && dDepth > m_Params.m_dSubStep) {
dOkSubStep = min( m_Params.m_dSubStep, m_TParams.m_dMaxMat + EPS_SMALL) ;
nSubStep = nStep * max( 1, static_cast<int>( ceil( dOkStep / dOkSubStep))) ;
dSubStep = dDepth / nSubStep ;
}
// se richiesto PlaneZ detection, aggiungo altri step intermedi ( planeZSteps )
PLANEZFACEVECTOR vPlaneZ ;
if ( m_bDetectPlaneZ) {
if ( ! DetectPlaneZ( vpStm, frSfr, vtTool, vPlaneZ, - GetOffsL(), dDepth - GetOffsL()))
return false ;
#if ENABLE_DEBUG_ZPLANE
for ( int nP = 0 ; nP < int( vPlaneZ.size()) ; ++ nP) {
int _a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vPlaneZ[nP].first->Clone()) ;
m_pGeomDB->SetMaterial( _a, Color( 1., 0., 0., .25)) ;
}
#endif
}
// definisco un vettore per Step/SubSteps durante la loro creazione
STEPINFOTMPSRVECTOR vStepInfo ;
vStepInfo.reserve( nStep + max( 0, nSubStep) + int( vPlaneZ.size())) ;
// inserimento degli step ( ed eventuali PlaneZ se SubSteps non presenti)
for ( int i = 0 ; i < nStep ; ++ i) {
vStepInfo.emplace_back( -1, - ( i + 1) * dStep, false, false, 1., nullptr, nullptr) ;
// se non ho SubStep ma PlaneZ, inserisco i PlaneZ
if ( nSubStep == -1) {
for ( int j = 0 ; j < int( vPlaneZ.size()) ; ++ j) {
if ( vPlaneZ[j].second > - ( i + 1) * dStep + STEP_TOL && vPlaneZ[j].second < - i * dStep - STEP_TOL) {
vStepInfo.emplace_back( i, vPlaneZ[j].second, false, true, -1., nullptr, nullptr) ;
vStepInfo.back().pSfrPlaneZ = Release( vPlaneZ[j].first) ;
}
}
}
}
INTDBLVECTOR vExtraStep ; // Depth per PlaneZ e SubSteps
for ( int i = 0 ; i < nSubStep ; ++ i)
vExtraStep.emplace_back( make_pair( -1, - ( i + 1) * dSubStep)) ;
if ( nSubStep != -1) {
for ( int i = 0 ; i < int( vPlaneZ.size()) ; ++ i)
vExtraStep.emplace_back( make_pair( i, vPlaneZ[i].second)) ;
sort( vExtraStep.begin(), vExtraStep.end(), []( const INTDBL& a, const INTDBL& b)
{ return a.second > b.second ; }) ;
}
// ... e poi gli step extra
int nIndRef = 0 ; // ( step base sottostante allo step extra corrente )
int nIndPrev = 0 ; // ( indice finale di copia degli step extra )
// creo un vettore di step extra presenti tra lo step base ( nIndRef-1)-esimo e nIndRef-esimo
// ( NB. Il primo intervallo sta tra -1 e 0, in quanto lo Step base a filo del grezzo non è presente)
for ( int i = 0 ; i < int( vExtraStep.size()) ; ++ i) {
// se step extra coincidente con lo step, copio gli step extra utili
if ( abs( vExtraStep[i].second - vStepInfo[nIndRef].dDepth) < STEP_TOL) {
for ( int j = i - 1 ; j >= nIndPrev ; -- j) {
int nMyInd = ( j == i - 1 ? nIndRef : int( vStepInfo.size()) - 1) ;
bool bSS = ( vExtraStep[j].first == -1) ;
vStepInfo.emplace_back( nMyInd, vExtraStep[j].second, bSS, ! bSS,
-1. , nullptr, nullptr) ;
if ( ! bSS)
vStepInfo.back().pSfrPlaneZ = Release( vPlaneZ[vExtraStep[j].first].first) ;
}
++ nIndRef ;
nIndPrev = i + 1 ;
}
}
// definisco il vettore per salvataggio delle regione e dei loro parametri nel GeomDB
SFRGEODBINFOVECTOR vInfoSfrGeomDB ;
vInfoSfrGeomDB.reserve( vStepInfo.size()) ;
// su tutti gli step ricavati, calcolo le PolyLine delle Silhouette
int nPocket = 0 ; // numero effettivo di Pocketing calcolate
int nProgressBarStep = 0 ; // step per progressBar
for ( auto it = vStepInfo.begin() ; it != vStepInfo.end() ; ++ it) {
// aggiorno step per progressBar
++ nProgressBarStep ;
// affondamento per calcolo regioni (limito poco sotto il grezzo)
double dSfrDepth = it->dDepth ;
double dSfrDeltaDepth = 0 ;
if ( dSfrDepth < -dSfrMaxDepth) {
dSfrDeltaDepth = dSfrDepth + dSfrMaxDepth ;
dSfrDepth = -dSfrMaxDepth ;
}
/* ******************** Regione definita dai contorni ******************** */
// regione di lavoro allo step corrente ( definita dalla curva di lavoro )
PtrOwner<ISurfFlatRegion> pSfr( CloneSurfFlatRegion( pSfrSgro)) ;
if ( IsNull( pSfr) || ! pSfr->IsValid()) {
m_pMchMgr->SetLastError( 3024, "Error in SurfRoughing : region not computable") ;
return false ;
}
pSfr->Translate( ( dSfrDepth + GetOffsL()) * vtTool) ;
/* ******************** Regione adattata al grezzo ******************** */
// questa regione bisogna ridurla basandosi sulla geometria del grezzo, in modo da non lavorare
// parti in eccesso ; taglio il grezzo sul piano corrente e interseco con questa regione
PtrOwner<ISurfFlatRegion> pSfrRaw( GetSfrByStmIntersection( IPPStm, dSfrDepth + GetOffsL(), 0)) ;
if ( IsNull( pSfrRaw)) {
m_pMchMgr->SetLastError( 3027, "Error in SurfRoughing : Slicing Raw failed") ;
return false ;
}
if ( pSfrRaw->IsValid() && pSfrRaw->GetChunkCount() > 0)
pSfr->Intersect( *pSfrRaw) ;
else
continue ; // step fuori dal grezzo, passo al successivo
// definisco la regione rimossa temporanea
PtrOwner<ISurfFlatRegion> pSfrRemoved_tmp( CloneSurfFlatRegion( pSfr)) ;
if ( IsNull( pSfrRemoved_tmp))
return false ;
/* ***************** Regione piana esterna ai contorni ****************** */
// regione definita dalla parte di grezzo al di fuori della curva di sgrossatura
// unita ad eventuale regione di collisione
PtrOwner<ISurfFlatRegion> pSfrOutCompo( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrOutCompo))
return false ;
if ( pStmLimit->IsValid() && pStmLimit->GetTriangleCount() > 0) {
pSfrOutCompo.Set( GetSfrByStmIntersection( IPPStm1, dSfrDepth + GetOffsL(), 0)) ;
if ( IsNull( pSfrOutCompo)) {
m_pMchMgr->SetLastError( 3027, "Error in SurfRoughing : Slicing Raw failed") ;
return false ;
}
}
if ( ! IsNull( pSfrColl) && pSfrColl->IsValid()) {
PtrOwner<ISurfFlatRegion> pSfrCollTransl( CloneSurfFlatRegion( pSfrColl)) ;
if ( IsNull( pSfrCollTransl) || ! pSfrCollTransl->IsValid())
return false ;
pSfrCollTransl->Translate( ( dSfrDepth + GetOffsL()) * vtTool) ;
if ( IsNull( pSfrOutCompo) || ! pSfrOutCompo->IsValid())
pSfrOutCompo.Set( CloneSurfFlatRegion( pSfrCollTransl)) ;
else
pSfrOutCompo->Add( *pSfrCollTransl) ;
}
/* *************************** Silhouette **************************** */
// determino la regione da non lavorare ( dalle geometrie selezionate) e la sottraggo
double dSilDepth = dSfrDepth - ( it->bPlaneZStep ? SIL_DEPTH_TOL : 0.) ;
bool bOkSil = false ;
PtrOwner<ISurfFlatRegion> pSfrSil_Hypothetical( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrSil_Hypothetical))
return false ;
PtrOwner<ISurfFlatRegion> pSfrSil( GetSfrSilhouette( pCavParSilh, dSilDepth, SILH_TOL, bOkSil)) ;
if ( ! bOkSil) {
m_pMchMgr->SetLastError( 3024, "Error in SurfRoughing : region not computable") ;
return false ;
}
if ( ! IsNull( pSfrSil) && ! it->bPlaneZStep) {
// provo prima con un Offset Chamfer, se non funziona provo con il Fillet ( pezza da sistemare ! )
PtrOwner<ISurfFlatRegion> pSfrSilCheck( pSfrSil->CreateOffsetSurf( GetOffsR(), ICurve::OFF_CHAMFER)) ;
if ( IsNull( pSfrSilCheck) || ! pSfrSilCheck->IsValid()) {
m_pMchMgr->SetLastError( 3024, "Error in SurfRoughing : region not computable") ;
return false ;
}
pSfrSil_Hypothetical.Set( CloneSurfFlatRegion( pSfrSilCheck)) ; // regione di silhouette ipotetica
// sottraggo le parti da non lavorare
if ( ! pSfr->Subtract( *pSfrSilCheck)) {
// se non riesco, provo con un Offset di tipo Fillet
pSfrSil->Offset( GetOffsR(), ICurve::OFF_FILLET) ;
pSfrSil_Hypothetical.Set( CloneSurfFlatRegion( pSfrSil)) ; // regione di silhouette ipotetica
if ( ! pSfr->Subtract( *pSfrSil))
return false ;
}
else
pSfrSil.Set( Release( pSfrSilCheck)) ;
}
if ( ! pSfr->IsValid() || pSfr->GetChunkCount() == 0) // se superficie non valida
continue ; // passo allo step successivo ( la silhouette coincide con il grezzo )
/* ************************** Superfici di supporto ************************ */
// sottraggo i contributi dovuti a regioni di supporto ( mediante Offset in 2d)
if ( ! vSurfL_supp.empty()) {
bool bOkSil_supp = false ;
PtrOwner<ISurfFlatRegion> pSfrSil_supp( GetSfrSilhouette( pCavParSilh_supp, dSilDepth, SILH_TOL, bOkSil_supp)) ;
if ( ! bOkSil_supp) {
m_pMchMgr->SetLastError( 3024, "Error in SurfRoughing : region not computable") ;
return false ;
}
if ( ! IsNull( pSfrSil_supp)) {
// Offset radiale sulla Silhouette
pSfrSil_supp->Offset( dSuppRadOffs + GetOffsR(), ICurve::OFF_CHAMFER) ;
// Sottraggo le parti da non lavorare
pSfr->Subtract( *pSfrSil_supp) ;
// Aggiungo la regione alla Silhouette
if ( ! IsNull( pSfrSil) && pSfrSil->IsValid() && pSfrSil->GetChunkCount() > 0)
pSfrSil->Add( *pSfrSil_supp) ;
else
pSfrSil.Set( Release( pSfrSil_supp)) ;
// Aggiorno la regione Ipotetica
if ( ! IsNull( pSfrSil_Hypothetical) && pSfrSil_Hypothetical->IsValid() && pSfrSil_Hypothetical->GetChunkCount() > 0)
pSfrSil_Hypothetical->Add( *pSfrSil_supp) ;
else
pSfrSil_Hypothetical.Set( Release( pSfrSil_supp)) ;
}
// Se superficie non valida, passo allo step successivo
if ( ! pSfr->IsValid() || pSfr->GetChunkCount() == 0)
continue ;
}
// salvo la superficie rimossa
delete( it->pSfrRemoved) ;
it->pSfrRemoved = CloneSurfFlatRegion( pSfrRemoved_tmp) ;
if ( ! IsNull( pSfrSil_Hypothetical) && pSfrSil_Hypothetical->IsValid() && pSfrSil_Hypothetical->GetChunkCount() > 0) {
pSfrSil_Hypothetical->Offset( m_TParams.m_dDiam / 2, ICurve::OFF_FILLET) ; // si può ingrandire leggermente (più conservativo)
pSfrSil_Hypothetical->Offset( - m_TParams.m_dDiam / 2, ICurve::OFF_FILLET) ;
// la silhouette ipotetica ora ha i lati chiusi definiti dal rotalamento del tool lungo il chiuso reale
it->pSfrRemoved->Subtract( *pSfrSil_Hypothetical) ; // la rimossa dipende dalla silhouette ipotetica (non quella reale)
}
// se PlaneZ
if ( it->bPlaneZStep && ! IsNull( pSfrSil) && pSfrSil->IsValid()) {
pSfrSil->Offset( GetOffsR(), ICurve::OFF_CHAMFER) ; // offset radiale sulla Silhouette
it->pSfrRemoved->Subtract( *pSfrSil) ; // sottraggo le parti da non lavorare
}
// inizializzo Regione piana per gestione lati aperti
PtrOwner<ISurfFlatRegion> pSfrOpenClose( CloneSurfFlatRegion( pSfrRaw)) ;
if ( IsNull( pSfrOpenClose))
return false ;
/* *************************** Gestione StepExtra **************************** */
if ( it->bSubStep) {
// recupero l'indice nel vettore dello step di riferimento
int nIndRef = it->nIndRef ;
while ( ( vStepInfo[nIndRef].bSubStep) &&
( vStepInfo[nIndRef].pSfrRemoved == nullptr || ! vStepInfo[nIndRef].pSfrRemoved->IsValid())) {
nIndRef = vStepInfo[nIndRef].nIndRef ;
}
// recupero la superficie progressiva dello step di riferimento
PtrOwner<ISurfFlatRegion> pSfrRemovedRef( CloneSurfFlatRegion( vStepInfo[nIndRef].pSfrRemoved)) ;
if ( ! IsNull( pSfrRemovedRef) && pSfrRemovedRef->IsValid()) { // se valida
pSfrRemovedRef->Offset( OFFS_CORR_OPEN_EDGES, ICurve::OFF_FILLET) ; // correzione per booleane
if ( ! pSfr->Subtract( *pSfrRemovedRef)) { // sottraggo la regione svuotata in precedenza
#if ENABLE_DEBUG_SFR_BOOLEANS
SaveSfrBooleans( pSfr, pSfrRef, sPathSrfBool + "Sub_" + to_string( it->dDepth) + ".nge") ;
#endif
// NB. In attesa di una versione più robusta per le booleane tra regioni piane, il substep viene scartato
continue ;
}
// aggiorno Regione piana per gestione lati aperti
pSfrOpenClose->Subtract( *pSfrRemovedRef) ;
}
}
else if ( it->bPlaneZStep && ! IsNull( pSfrSil) && pSfrSil->IsValid()) {
PtrOwner<ISurfFlatRegion> pSfrRef( CloneSurfFlatRegion( it->pSfrRemoved)) ;
if ( ! IsNull( pSfrRef) && pSfrRef->IsValid())
pSfrRef->Offset( OFFS_CORR_OPEN_EDGES + GetOffsR(), ICurve::OFF_FILLET) ; // correzione
// cerco il Chunk nC-esimo della silhouette da rimuovere
PtrOwner<ISurfFlatRegion> pSfrPlaneZ( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrPlaneZ))
return false ;
for ( int nC = 0 ; nC < pSfrSil->GetChunkCount() ; ++ nC) {
PtrOwner<ISurfFlatRegion> pSfrSilChunk( pSfrSil->CloneChunk( nC)) ;
PtrOwner<ISurfFlatRegion> pSfrMyFace( CloneSurfFlatRegion( it->pSfrPlaneZ)) ;
if ( IsNull( pSfrSilChunk) || IsNull( pSfrMyFace) ||
! pSfrSilChunk->IsValid() || ! pSfrMyFace->IsValid())
return false ;
pSfrMyFace->Intersect( *pSfrSilChunk) ;
if ( ! IsNull( pSfrMyFace) && pSfrMyFace->IsValid()) {
if ( pSfrPlaneZ->IsValid() && pSfrPlaneZ->GetChunkCount() > 0)
pSfrPlaneZ->Add( *pSfrSilChunk) ;
else
pSfrPlaneZ.Set( pSfrSilChunk) ;
}
}
// se regione PlaneZ valida
if ( ! IsNull( pSfrPlaneZ) && pSfrPlaneZ->IsValid()) {
// cerco le isole chiuse calcolando la silhouette leggermente sopra al piano
delete( it->pSfrPlaneZ) ;
it->pSfrPlaneZ = nullptr ;
double dSilIslDepth = it->dDepth + SIL_DEPTH_TOL ;
bool bOkSil_isl = false ;
PtrOwner<ISurfFlatRegion> pSfrSilIslands( GetSfrSilhouette( pCavParSilh, dSilIslDepth, SILH_TOL, bOkSil_isl)) ;
if ( ! bOkSil_isl) {
m_pMchMgr->SetLastError( 3024, "Error in SurfRoughing : region not computable") ;
return false ;
}
// pulisco la regione di Silhouette
pSfrSil->Clear() ;
if ( ! IsNull( pSfrSilIslands) && pSfrSilIslands->IsValid()) {
// se ho delle isole valide, le sottraggo alla regione di PlaneZ
pSfrSilIslands->Offset( GetOffsR(), ICurve::OFF_CHAMFER) ;
pSfrPlaneZ->Subtract( *pSfrSilIslands) ;
// aggiorno la regione limite
if ( pSfrSil->IsValid())
pSfrSil->Add( *pSfrSilIslands) ;
else
pSfrSil.Set( pSfrSilIslands) ;
}
// la regione rimossa è la regione calcolata, con isole comprese
delete( it->pSfrRemoved) ;
it->pSfrRemoved = CloneSurfFlatRegion( pSfr) ;
if ( ! IsNull( pSfrSilIslands) && pSfrSilIslands->IsValid()) {
if ( it->pSfrRemoved != nullptr && it->pSfrRemoved->IsValid())
it->pSfrRemoved->Subtract( *pSfrSilIslands) ;
}
// setto la superficie PlaneZ
it->pSfrPlaneZ = Release( pSfrPlaneZ) ;
}
if ( it->pSfrPlaneZ != nullptr && it->pSfrPlaneZ->IsValid())
pSfr->Intersect( *it->pSfrPlaneZ) ; // intersezione con silhouette
// aggiorno Regione piana per gestione lati aperti
if ( ! IsNull( pSfrRef) && pSfrRef->IsValid())
pSfrOpenClose->Subtract( *pSfrRef) ;
}
// se regione risultante non vuota
if ( pSfr->IsValid() && pSfr->GetChunkCount() > 0) {
// *************************** Regione Limite ***************************
// la regione limite definisce le aree dove l'utensile non deve passare
PtrOwner<ISurfFlatRegion> pSfrLimit( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrLimit))
return false ;
if ( ! IsNull( pSfrOutCompo) && pSfrOutCompo->IsValid())
pSfrLimit.Set( pSfrOutCompo) ;
if ( ! IsNull( pSfrSil) && pSfrSil->IsValid()) {
if ( ! IsNull( pSfrLimit) && pSfrLimit->IsValid())
pSfrLimit->Add( *pSfrSil) ;
else
pSfrLimit.Set( pSfrSil) ;
}
// rimuovo tutti i chunk troppo snelli
if ( it->bSubStep) {
if ( ! RemoveChunksUnderTolerance( pSfr, m_dSubStepToler, pSfrLimit, it->pSfrRemoved)) {
m_pMchMgr->SetLastError( 3029, "Error in SurfRoughing : Simplify Chunks for SubSteps failed") ;
return false ;
}
// se dopo la semplificazione non rimane nulla, allora passo allo step successivo
if ( ! pSfr->IsValid() || pSfr->GetChunkCount() == 0) {
delete( it->pSfrRemoved) ; // non ho rimosso nulla allo step corrente
it->pSfrRemoved = nullptr ;
continue ;
}
}
// determino i lati aperti ( mediante vicinanza dei tratti di curva al volume progressivo non svuotato)
if ( ! ChooseCloseOrOpenEdge( pSfr, pSfrOpenClose)) {
m_pMchMgr->SetLastError( 3026, "Error in SurfRoughing : Detecting open edges failed") ;
return false ;
}
// se step base, rimuovo i Chunk sotto una certa tolleranza
if ( ! it->bSubStep && ! it->bPlaneZStep) {
RemoveChunksUnderTolerance( pSfr, m_dStepToler, pSfrLimit) ;
// se dopo la semplificazione non rimane nulla, allora passo allo step successivo
if ( ! pSfr->IsValid() || pSfr->GetChunkCount() == 0) {
delete( it->pSfrRemoved) ; // non ho rimosso nulla allo step corrente
it->pSfrRemoved = nullptr ;
continue ;
}
}
// chiudo tutti i lati aperti troppo corti
if ( ! CloseOpenEdgesUnderTolerance( pSfr, m_TParams.m_dDiam - 200 * EPS_SMALL)) {
m_pMchMgr->SetLastError( 3029, "Error in SurfRoughing : Simplify Chunks for SubSteps failed") ;
return false ;
}
// rimuovo i Chunk troppo snelli ( la regione è cambiata rispetto a prima)
if ( it->bSubStep) {
// rimuovo tutti i Chunk snelli
RemoveChunksUnderTolerance( pSfr, m_dSubStepToler, pSfrLimit) ;
// se dopo la semplificazione non rimane nulla, allora passo allo step successivo
if ( ! pSfr->IsValid() || pSfr->GetChunkCount() == 0) {
delete( it->pSfrRemoved) ; // non ho rimosso nulla allo step corrente
it->pSfrRemoved = nullptr ;
continue ;
}
}
// se rischiesto, calcolo la regione di Corner allo/al Step/SubStep corrente
bool bSfrCorner = ( ! IsNull( pSfrColl) && pSfrColl->IsValid() &&
! IsNull( pSfrSearchCorners) && pSfrSearchCorners->IsValid()) ;
if ( bSfrCorner) {
PtrOwner<ISurfFlatRegion> pSfrCorner( GetSfrCornerColl( pSfr, pSfrLimit, pSfrColl, pSfrSearchCorners)) ;
if ( ! IsNull( pSfrCorner) && pSfrCorner->IsValid()) {
pSfr->Add( *pSfrCorner) ;
if ( ! ChooseCloseOrOpenEdge( pSfr, pSfrOpenClose)) {
m_pMchMgr->SetLastError( 3026, "Error in SurfRoughing : Detecting open edges failed") ;
return false ;
}
}
}
#if ENABLE_DEBUG_SFR
DrawLoopsSurf( pSfr, false, Color( .0, 1., 0., .5), it->bSubStep, ToString( it->dDepth)) ;
#endif
// eventuale traslazione per ultima passata appena sotto il grezzo
if ( dSfrDeltaDepth < -EPS_SMALL)
pSfr->Translate( dSfrDeltaDepth * vtTool) ;
// memorizzo le superfici ricavate con le loro relative informazioni nel vettore
vInfoSfrGeomDB.resize( vInfoSfrGeomDB.size() + 1) ;
vInfoSfrGeomDB.back().pSfr.Set( Release( pSfr)) ;
vInfoSfrGeomDB.back().pSfrLimit.Set( nullptr) ;
if ( ! IsNull( pSfrLimit) && pSfrLimit->IsValid())
vInfoSfrGeomDB.back().pSfrLimit.Set( Release( pSfrLimit)) ;
vInfoSfrGeomDB.back().pSfrRemoved.Set( nullptr) ;
if ( it->pSfrRemoved != nullptr && it->pSfrRemoved->IsValid())
vInfoSfrGeomDB.back().pSfrRemoved.Set( CloneSurfFlatRegion( it->pSfrRemoved)) ;
vInfoSfrGeomDB.back().bSubStep = ( it->bSubStep || it->bPlaneZStep) ;
vInfoSfrGeomDB.back().dDepth = it->dDepth + GetOffsL() ;
if ( ! vInfoSfrGeomDB.back().bSubStep)
vInfoSfrGeomDB.back().dRelativeDepth = - dStep ;
else
vInfoSfrGeomDB.back().dRelativeDepth = dStep * floor( - vInfoSfrGeomDB.back().dDepth / dStep) + vInfoSfrGeomDB.back().dDepth ;
double dZLocFeedCoef = GetAdaptedCoeffFeed( ( it->bSubStep || it->bPlaneZStep), it->dDepth, dStep) ;
vInfoSfrGeomDB.back().dZLocCoefFeed = dZLocFeedCoef ;
// aggiorno la progressBar
ExeProcessEvents( 5 + nProgressBarStep * 45 / int( vStepInfo.size()), 0) ;
}
else {
delete( it->pSfrRemoved) ; // non ho rimosso nulla
it->pSfrRemoved = nullptr ;
// aggiorno la progressBar
ExeProcessEvents( 5 + nProgressBarStep * 45 / int( vStepInfo.size()), 0) ;
}
}
// assegno il vettore estrazione al gruppo del percorso
m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ;
// Imposto dati comuni
SetPathId( nPxId) ;
SetToolDir( vtTool) ;
Vector3d vtAux ;
if ( GetValInNotes( m_Params.m_sUserNotes, UN_VTAUXDIR, vtAux))
vtAux.Normalize() ;
SetAuxDir( vtAux) ;
// se richiesto ordine per ZChunk, aggiusto le geometrie inserite nel gruppo
if ( m_bOrderZ)
OrderByZChunk( vInfoSfrGeomDB, nTempId, pSfrSgro) ;
// inserisco le superfici ricavate nel gruppo temporaneo
for ( int i = 0 ; i < int( vInfoSfrGeomDB.size()) ; ++ i) {
// --- superficie da lavorare
int nNew_SfrPock_Id = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nTempId, Release( vInfoSfrGeomDB[i].pSfr)) ; ;
if ( nNew_SfrPock_Id == GDB_ID_NULL) {
m_pMchMgr->SetLastError( 3024, "Error in SurfRoughing : region not computable") ;
return false ;
}
m_pGeomDB->SetMaterial( nNew_SfrPock_Id, GREEN) ;
m_pGeomDB->SetName( nNew_SfrPock_Id, KEY_SURF_POCK + ToString( nPocket)) ;
m_pGeomDB->SetInfo( nNew_SfrPock_Id, KEY_DEPTH, ToString( vInfoSfrGeomDB[i].dDepth)) ;
m_pGeomDB->SetInfo( nNew_SfrPock_Id, KEY_RELATIVE_DEPTH, ToString( vInfoSfrGeomDB[i].dRelativeDepth)) ;
m_pGeomDB->SetInfo( nNew_SfrPock_Id, KEY_ZLOCFEEDCOEF, ToString( vInfoSfrGeomDB[i].dZLocCoefFeed)) ;
m_pGeomDB->SetInfo( nNew_SfrPock_Id, KEY_SUBSTEP, ToString( vInfoSfrGeomDB[i].bSubStep)) ;
// --- superficie limite
int nNew_SfrLimit_Id = GDB_ID_NULL ;
if ( ! IsNull( vInfoSfrGeomDB[i].pSfrLimit) && vInfoSfrGeomDB[i].pSfrLimit->IsValid()) {
#if ENABLE_DEBUG_SFR
DrawLoopsSurf( vInfoSfrGeomDB[i].pSfrLimit, true, Color( .5, .5, .5, .5), vInfoSfrGeomDB[i].bSubStep, ToString( vInfoSfrGeomDB[i].dDepth)) ;
#endif
nNew_SfrLimit_Id = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nTempId, Release( vInfoSfrGeomDB[i].pSfrLimit)) ;
if ( nNew_SfrLimit_Id == GDB_ID_NULL) {
m_pMchMgr->SetLastError( 3024, "Error in SurfRoughing : region not computable") ;
return false ;
}
m_pGeomDB->SetMaterial( nNew_SfrLimit_Id, ORANGE) ;
m_pGeomDB->SetName( nNew_SfrLimit_Id, KEY_SURF_LIMIT + ToString( nPocket)) ;
}
++ nPocket ;
vPocket.emplace_back( make_pair( nNew_SfrPock_Id, nNew_SfrLimit_Id)) ;
}
// Eseguo le svuotature
if ( ! AddRoughing( vPocket, vtTool, dDepth, dStep, dSubStep, bSplitArcs))
return false ;
}
// incremento numero di percorsi
++ m_nPaths ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::DetectPlaneZ( const CISURFTMPVECTOR& vpStm, const Frame3d& frCompo, const Vector3d& vtTool,
PLANEZFACEVECTOR& vPlaneZ, double dMinDepth, double dMaxDepth) const
{
// se non richiesta analisi planeZ, esco
vPlaneZ.clear() ;
if ( ! m_bDetectPlaneZ)
return true ;
// scorro il vettore di superfici su cui individuare le facce con normale vtTool
for ( int i = 0 ; i < int( vpStm.size()) ; ++ i) {
// per ogni superficie valida, scorro le facce
if ( vpStm[i] == nullptr || ! vpStm[i]->IsValid() || ! vpStm[i]->GetTriangleCount())
continue ;
for ( int nF = 0 ; nF < vpStm[i]->GetFacetCount() ; ++ nF) {
// recupero centro e versore normale della faccia, verificando il parallelismo con vtTool
Point3d ptCen ;
Vector3d vtFaceN ;
if ( ! vpStm[i]->GetFacetCenter( nF, ptCen, vtFaceN) ||
! AreSameVectorEpsilon( vtTool, vtFaceN, 25 * EPS_SMALL))
continue ;
// se faccia parallela a vtTool, ricavo la sua depth ( ptCen.z)
ptCen.ToLoc( frCompo) ;
// se fuori dal range, non la considero
if ( abs( ptCen.z) < dMinDepth + 2 * EPS_SMALL || abs( ptCen.z) > dMaxDepth - 2 * EPS_SMALL)
continue ;
// se area troppo piccola, non la considero ( almeno area come faccia utensile)
double dArea = 0. ;
if ( ! vpStm[i]->GetFacetArea( nF, dArea) || dArea < PIGRECO * m_TParams.m_dDiam * m_TParams.m_dDiam / 4.)
continue ;
// recupero la superficie piana della faccia
POLYLINEVECTOR vPL ;
if ( ! vpStm[i]->GetFacetLoops( nF, vPL))
continue ;
PtrOwner<ISurfFlatRegion> pSfrFace( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrFace))
return false ;
for ( int j = 0 ; j < int( vPL.size()) ; ++ j) {
PtrOwner<ICurveComposite> pCompoLoop( CreateCurveComposite()) ;
if ( IsNull( pCompoLoop) || ! pCompoLoop->FromPolyLine( vPL[j]))
return false ;
if ( j == 0) {
if ( ! pSfrFace->AddExtLoop( Release( pCompoLoop)))
return false ;
}
else {
if ( ! pSfrFace->AddIntLoop( Release( pCompoLoop)))
return false ;
}
}
if ( ! pSfrFace->IsValid())
continue ;
// controllo se ho già trovato una faccia su un piano simile
bool bSamePlaneZ = false ;
for ( int j = 0 ; j < int( vPlaneZ.size()) && ! bSamePlaneZ ; ++ j) {
if ( abs( ptCen.z - vPlaneZ[j].second) < 2 * EPS_SMALL) {
bSamePlaneZ = true ;
vPlaneZ[j].first->Add( *pSfrFace) ;
}
}
if ( ! bSamePlaneZ) {
// definisco un nuovo Step di tipo PlaneZ
vPlaneZ.resize( vPlaneZ.size() + 1) ;
vPlaneZ.back().first.Set( pSfrFace) ;
vPlaneZ.back().second = ptCen.z ;
}
}
}
// ordino i piani per Z in ordine decrescente
sort( vPlaneZ.begin(), vPlaneZ.end(), []( const PLANEZFACE& a, const PLANEZFACE& b)
{ return a.second < b.second ; }) ;
return true ;
}
//----------------------------------------------------------------------------
ISurfTriMesh*
SurfRoughing::GetRaw( void) const
{
// controllo MachManager e database geometrico
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return nullptr ;
// creo Stm del grezzo
PtrOwner<ISurfTriMesh> pStmRaw( CreateSurfTriMesh()) ;
if ( IsNull( pStmRaw))
return nullptr ;
pStmRaw->AdjustTopology() ;
// Id prima RawPart
int nRawId = m_pMchMgr->GetFirstRawPart() ;
while ( nRawId != GDB_ID_NULL) {
// verifico che il grezzo compaia nella fase
if ( m_pMchMgr->VerifyRawPartPhase( nRawId, m_nPhase)) {
// recupero l'oggetto dal database con tale Id
int nRawSolidId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_SOLID) ;
const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( nRawSolidId) ;
if ( pGObj == nullptr)
return nullptr ;
// recupero il frame in cui si trova
Frame3d frRaw ;
m_pGeomDB->GetGlobFrame( nRawSolidId, frRaw) ;
// controllo che sia una Trimesh
if ( pGObj->GetType() == SRF_TRIMESH) {
SurfLocal StmRawPart( GetSurfTriMesh( pGObj), frRaw, GLOB_FRM) ;
// lo aggiungo alla Trimesh complessiva
pStmRaw->Add( *GetSurfTriMesh( StmRawPart)) ;
}
}
// passo al grezzo successivo
nRawId = m_pMchMgr->GetNextRawPart( nRawId) ;
}
return ( ( pStmRaw->IsValid() && pStmRaw->GetTriangleCount() > 0) ? Release( pStmRaw) : nullptr) ;
}
//----------------------------------------------------------------------------
ISurfTriMesh*
SurfRoughing::GetStmOutSideSfr( const ISurfFlatRegion* pSfr, double dDepth, const ISurfTriMesh* pStmRaw, const Vector3d& vtExtr) const
{
// controllo dei parametri
if ( pSfr == nullptr || ! pSfr->IsValid() ||
pStmRaw == nullptr || ! pStmRaw->IsValid())
return nullptr ;
double dTol = 100 * EPS_SMALL ;
// creo una copia della pSfr mediante un piccolo offset correttivo (per problemi con archi)
PtrOwner<ISurfFlatRegion> pSfrOffs( pSfr->CreateOffsetSurf( dTol, ICurve::OFF_FILLET)) ;
if ( IsNull( pSfrOffs) || ! pSfrOffs->IsValid())
return nullptr ;
pSfrOffs->Translate( dTol * pSfr->GetNormVersor()) ;
// definisco il vettore delle curve dei bordi della regione
CICURVEPVECTOR vpCrv ;
bool bOk = true ;
// per ogni Chunk
for ( int nC = 0 ; nC < pSfrOffs->GetChunkCount() && bOk ; ++ nC) {
// per ogni Loop
for ( int nL = 0 ; nL < pSfrOffs->GetLoopCount( nC) && bOk ; ++ nL) {
// recupero il Loop come curva composita
PtrOwner<ICurve> pLoop( pSfrOffs->GetLoop( nC, nL)) ;
bOk = ( ! IsNull( pLoop) && pLoop->IsValid()) ;
if ( bOk)
vpCrv.emplace_back( Release( pLoop)) ;
}
}
// definisco la TrimMesh limite ( inizialmente come copia del grezzo)
PtrOwner<ISurfTriMesh> pStmLimit( CloneSurfTriMesh( pStmRaw)) ;
bOk = bOk && ( ! IsNull( pStmLimit) && pStmLimit->IsValid()) ;
// tengo solo le parti di superficie che sono effettivamente vicine alla regione di sgrossatura
// box della superficie piana
BBox3d BBoxSfr ;
bOk = bOk && pSfrOffs->GetLocalBBox( BBoxSfr) ;
double dExtraX = abs( dDepth * ( pSfrOffs->GetNormVersor() * X_AX)) ;
double dExtraY = abs( dDepth * ( pSfrOffs->GetNormVersor() * Y_AX)) ;
double dExtraZ = abs( dDepth * ( pSfrOffs->GetNormVersor() * Z_AX)) ;
BBoxSfr.Expand( dExtraX, dExtraY, dExtraZ) ;
// scorro le parts
for ( int nPart = 0 ; nPart < pStmLimit->GetPartCount() && bOk ; ++ nPart) {
// calcolo il box della part corrente
BBox3d BBoxPart ;
bOk = bOk && pStmLimit->GetPartLocalBBox( nPart, BBoxPart) ;
// se non c'è intersezione con i Box, elimino la parte corrente
BBox3d BBoxInt ;
if ( ! BBoxSfr.FindIntersection( BBoxPart, BBoxInt)) {
bOk = pStmLimit->RemovePart( nPart) ;
-- nPart ;
}
}
// definisco la superficie di estrusione
if ( bOk) {
PtrOwner<ISurfTriMesh> pStmExtr( GetSurfTriMeshByRegionExtrusion( vpCrv, ( 1 + 2. * dTol) * vtExtr)) ;
bOk = ( ! IsNull( pStmExtr) && pStmExtr->IsValid()) ;
// la superficie deve definire un volume
double dVol = 0. ;
bOk = bOk && pStmExtr->GetVolume( dVol) ;
if ( dVol < EPS_ZERO)
bOk = bOk && pStmExtr->Invert() ;
// sottraggo al grezzo la regione di estrusione
bOk = bOk && pStmLimit->Subtract( *pStmExtr) ;
}
// rimozione del vettore di curve costanti
for ( int i = 0 ; i < int( vpCrv.size()) ; ++ i) {
delete( vpCrv[i]) ;
vpCrv[i] = nullptr ;
}
return ( bOk ? Release( pStmLimit) : nullptr) ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::GetToolCollisionRegion( const ISurfFlatRegion* pSfrSgro, double& dDepth,
ISurfFlatRegion* pSfrColl, ISurfFlatRegion* pSfrSearchCorners) const
{
// la collisione viene calcolata mediante tavola e ventose
// se la superficie di sgrossatura non è valida, non faccio nulla
if ( pSfrSgro == nullptr || ! pSfrSgro->IsValid())
return false ;
// le supercici risultante deve essere vuota
if ( pSfrColl == nullptr || pSfrSearchCorners == nullptr)
return false ;
pSfrColl->Clear() ;
pSfrSearchCorners->Clear() ;
// dalla superficie definisco il riferimento locale ( vista come ZTool)
Frame3d frLoc ;
Point3d ptCen ; pSfrSgro->GetCentroid( ptCen) ;
if ( ! frLoc.Set( ptCen, pSfrSgro->GetNormVersor()))
return false ;
// definisco la distanza di sicurezza
double const SAFE_TOL = 5. * EPS_SMALL ;
// Recupero la macchina corrente e gli oggetti di Collisione
Machine* pMch = m_pMchMgr->GetCurrMachine() ;
if ( pMch != nullptr) {
INTVECTOR vTabCollId ;
if ( pMch->GetCurrTableCollGroups( vTabCollId)) {
for ( const int& nCollId : vTabCollId) {
// recupero il Box dell'Oggetto
BBox3d BBoxTab ;
if ( ! m_pGeomDB->GetGlobalBBox( nCollId, BBoxTab) || BBoxTab.IsEmpty())
continue ;
// se sgrossatura orientata come la Tavola, quindi Z_AX
if ( AreSameVectorApprox( pSfrSgro->GetNormVersor(), Z_AX)) {
// controllo se limitare la Depth della tavola
double dTabDist = abs( ( ptCen - BBoxTab.GetMax()) * pSfrSgro->GetNormVersor()) ;
if ( dDepth > dTabDist - DIST_TABLE) {
dDepth = dTabDist - DIST_TABLE ;
string sWarn = "Warning in SurfRoughing : Depth reduced at " + ToString( dDepth, 3) ;
m_pMchMgr->SetWarning( 3057, sWarn) ;
}
}
// altrimenti
else {
// espando leggermente il Box per tolleranze
BBoxTab.Expand( SAFE_TOL) ;
// creo una TriMesh rappresentativa del Box
double dDimX = BBoxTab.GetDimX() ;
double dDimY = BBoxTab.GetDimY() ;
double dDimZ = BBoxTab.GetDimZ() ;
PtrOwner<ISurfTriMesh> pStmBox( GetSurfTriMeshBox( dDimX, dDimY, dDimZ, true)) ;
if ( IsNull( pStmBox) || ! pStmBox->IsValid())
continue ;
Point3d ptBoxC ; BBoxTab.GetCenter( ptBoxC) ;
Point3d ptStmC = Point3d( dDimX / 2., dDimY / 2., dDimZ / 2.) ;
pStmBox->Translate( ptStmC - ptBoxC) ;
// recupero la sua proiezione nel piano di sgrossatura come regione piana
// NB. Usando il piano, non considero la parte di superifie nel semipiano negativo
Plane3d plProj ;
if ( ! plProj.Set( frLoc.Orig() - dDepth * frLoc.VersZ(), frLoc.VersZ()))
return false ;
POLYLINEVECTOR vPL ;
if ( ! pStmBox->GetSilhouette( plProj, EPS_SMALL, vPL))
return false ;
// se esiste una proiezione nel semipiano positivo, ne recupero la regione piana
if ( ! vPL.empty()) {
SurfFlatRegionByContours SfrByC ;
for ( const PolyLine& PL : vPL) {
PtrOwner<ICurveComposite> pCompoLoop( CreateCurveComposite()) ;
if ( IsNull( pCompoLoop) || ! pCompoLoop->FromPolyLine( PL) ||
! SfrByC.AddCurve( Release( pCompoLoop)))
return false ;
}
PtrOwner<ISurfFlatRegion> pSfrTabColl( SfrByC.GetSurf()) ;
if ( IsNull( pSfrTabColl) || ! pSfrTabColl->IsValid())
return false ;
// aggiorno la regione di collissione per l'utensile
if ( ! pSfrColl->CopyFrom( pSfrTabColl))
return false ;
if ( AreOppositeVectorApprox( pSfrColl->GetNormVersor(), frLoc.VersZ()))
pSfrColl->Invert() ;
#if ENABLE_DEBUG_SFR_COLLISION
ISurfFlatRegion* _pSfrTab = CreateSurfFlatRegion() ;
_pSfrTab->CopyFrom( pSfrColl) ;
int _nSrfTbId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, _pSfrTab) ;
m_pGeomDB->SetMaterial( _nSrfTbId, Color( 255, 0, 0, 50)) ;
#endif
}
}
}
}
}
// --- ventose
INTVECTOR vFxtId ;
int nFxtId = m_pMchMgr->GetFirstFixture() ;
while ( nFxtId != GDB_ID_NULL) {
vFxtId.emplace_back( nFxtId) ;
nFxtId = m_pMchMgr->GetNextFixture( nFxtId) ;
}
for ( const int& nFxtId : vFxtId) {
// recupero il Box della ventosa
BBox3d bFxtBox ;
if ( m_pGeomDB->GetGlobalBBox( nFxtId, bFxtBox) && ! bFxtBox.IsEmpty()) {
// se sgrossatura orientata come come Z_AX
if ( AreSameVectorApprox( pSfrSgro->GetNormVersor(), Z_AX)) {
// controllo se limitare la Depth della tavola
double dTabDist = abs( ( ptCen - bFxtBox.GetMax()) * pSfrSgro->GetNormVersor()) ;
if ( dDepth > dTabDist - DIST_TABLE) {
dDepth = dTabDist - DIST_TABLE ;
string sWarn = "Warning in SurfRoughing : Depth reduced at " + ToString( dDepth, 3) ;
m_pMchMgr->SetWarning( 3057, sWarn) ;
}
}
else {
// espando il Box per evitare la collisione con l'utensile
bFxtBox.Expand( SAFE_TOL) ;
#if ENABLE_DEBUG_SFR_COLLISION
ICurveComposite* _pCompoFxt = CreateCurveComposite() ;
_pCompoFxt->AddPoint( bFxtBox.GetMin()) ;
_pCompoFxt->AddLine( bFxtBox.GetMin() + X_AX * bFxtBox.GetDimX()) ;
_pCompoFxt->AddLine( bFxtBox.GetMax() - Z_AX * bFxtBox.GetDimZ()) ;
_pCompoFxt->AddLine( bFxtBox.GetMin() + Y_AX * bFxtBox.GetDimY()) ;
_pCompoFxt->Close() ;
_pCompoFxt->SetExtrusion( Z_AX) ;
_pCompoFxt->SetThickness( bFxtBox.GetDimZ()) ;
int nFxtId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, _pCompoFxt) ;
m_pGeomDB->SetMaterial( nFxtId, YELLOW) ;
#endif
// recupero la TriMesh del Box
PtrOwner<ICurveComposite> pCompoFxt( CreateCurveComposite()) ;
if ( IsNull( pCompoFxt))
return false ;
pCompoFxt->AddPoint( bFxtBox.GetMin()) ;
pCompoFxt->AddLine( bFxtBox.GetMin() + X_AX * bFxtBox.GetDimX()) ;
pCompoFxt->AddLine( bFxtBox.GetMax() - Z_AX * bFxtBox.GetDimZ()) ;
pCompoFxt->AddLine( bFxtBox.GetMin() + Y_AX * bFxtBox.GetDimY()) ;
pCompoFxt->Close() ;
CICURVEPVECTOR vpCrvs ;
vpCrvs.emplace_back( pCompoFxt) ;
PtrOwner<ISurfTriMesh> pStmCollFxt( GetSurfTriMeshByRegionExtrusion( vpCrvs, Z_AX * bFxtBox.GetDimZ())) ;
if ( IsNull( pStmCollFxt) || ! pStmCollFxt->IsValid() || pStmCollFxt->GetTriangleCount() == 0)
return false ;
// recupero la sua proiezione nel piano di sgrossatura come regione piana
Plane3d plProj ;
if ( ! plProj.Set( frLoc.Orig() - dDepth * frLoc.VersZ(), frLoc.VersZ()))
return false ;
POLYLINEVECTOR vPL ;
if ( ! pStmCollFxt->GetSilhouette( plProj, EPS_SMALL, vPL)) // proiezione di 6 triangoli, veloce
return false ;
// se completamente dietro al piano, non influenza la sgrossatura attuale
if ( vPL.empty())
continue ;
SurfFlatRegionByContours SfrByC ;
for ( const PolyLine& PL : vPL) {
PtrOwner<ICurveComposite> pCompoLoop( CreateCurveComposite()) ;
if ( IsNull( pCompoLoop) || ! pCompoLoop->FromPolyLine( PL) ||
! SfrByC.AddCurve( Release( pCompoLoop)))
return false ;
}
PtrOwner<ISurfFlatRegion> pSfrFxtColl( SfrByC.GetSurf()) ;
if ( IsNull( pSfrFxtColl) || ! pSfrFxtColl->IsValid())
return false ;
if ( AreOppositeVectorApprox( pSfrFxtColl->GetNormVersor(), frLoc.VersZ()))
pSfrFxtColl->Invert() ;
// aggiorno la regione di collissione per l'utensile
if ( ! pSfrColl->IsValid()) {
if ( ! pSfrColl->CopyFrom( pSfrFxtColl))
return false ;
}
else {
if ( ! pSfrColl->Add( *pSfrFxtColl))
return false ;
}
#if ENABLE_DEBUG_SFR_COLLISION
ISurfFlatRegion* _pSfrFxt = CreateSurfFlatRegion() ;
_pSfrFxt->CopyFrom( pSfrFxtColl) ;
int _nSfrFxtId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, _pSfrFxt) ;
m_pGeomDB->SetMaterial( _nSfrFxtId, Color( 255, 255, 0, 50)) ;
#endif
}
}
}
// se ho una regione di collisione valida
if ( pSfrColl->IsValid()) {
PtrOwner<ISurfFlatRegion> pSfrBlock( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrBlock))
return false ;
// scorro le curve della regione di sgrossatura e definisco delle superfici di blocco
for ( int nC = 0 ; nC < pSfrSgro->GetChunkCount() ; ++ nC) {
for ( int nL = 0 ; nL < pSfrSgro->GetLoopCount( nC) ; ++ nL) {
PtrOwner<ICurveComposite> pCompoLoop( ConvertCurveToComposite( pSfrSgro->GetLoop( nC, nL))) ;
if ( ! IsNull( pCompoLoop) && pCompoLoop->IsValid()) {
pCompoLoop->Translate( - pSfrSgro->GetNormVersor() * dDepth) ;
for ( int nU = 0 ; nU < pCompoLoop->GetCurveCount() ; ++ nU) {
const ICurve* pSubCrvLoop = pCompoLoop->GetCurve( nU) ;
if ( pSubCrvLoop == nullptr || ! pSubCrvLoop->IsValid())
return false ;
CRVCVECTOR ccClass ;
if ( ! pSfrColl->GetCurveClassification( *pSubCrvLoop, EPS_SMALL, ccClass))
return false ;
bool bBlock = false ;
for ( int i = 0 ; ! bBlock && i < ssize( ccClass) ; ++ i) {
if ( ccClass[i].nClass == CRVC_OUT)
continue ;
PtrOwner<ICurve> pCrvColl( pSubCrvLoop->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE)) ;
if ( IsNull( pCrvColl) || ! pCrvColl->IsValid())
continue ;
double dLen = 0. ;
pCrvColl->GetLength( dLen) ;
bBlock = ( dLen > 2. * SAFE_TOL) ;
}
if ( bBlock) {
PtrOwner<ICurveComposite> pCompoBlock( CreateCurveComposite()) ;
if ( IsNull( pCompoBlock))
return false ;
pCompoBlock->AddCurve( pSubCrvLoop->Clone()) ;
pCompoBlock->SetExtrusion( pSfrSgro->GetNormVersor()) ;
OffsetCurve OffsCrv ; // ... rappresentativo
OffsCrv.Make( pCompoBlock, m_TParams.m_dDiam, ICurve::OFF_FILLET) ;
PtrOwner<ICurve> pCrvOffs( OffsCrv.GetLongerCurve()) ;
if ( IsNull( pCrvOffs) || ! pCrvOffs->IsValid())
return false ;
pCompoBlock->Invert() ;
Point3d ptA ; pCrvOffs->GetStartPoint( ptA) ;
Point3d ptC ; pCompoBlock->GetStartPoint( ptC) ;
pCompoBlock->AddLine( ptA) ;
pCompoBlock->AddCurve( Release( pCrvOffs)) ;
pCompoBlock->AddLine( ptC) ;
#if ENABLE_DEBUG_SFR_COLLISION
int _nCrvId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompoBlock->Clone()) ;
m_pGeomDB->SetMaterial( _nCrvId, PURPLE) ;
#endif
PtrOwner<ISurfFlatRegion> pSfrCurrBlock( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrCurrBlock))
return false ;
if ( ! pSfrCurrBlock->AddExtLoop( Release( pCompoBlock)))
return false ;
if ( ! pSfrBlock->IsValid()) {
if ( ! pSfrBlock.Set( Release( pSfrCurrBlock)))
return false ;
}
else {
if ( ! pSfrBlock->Add( *pSfrCurrBlock))
return false ;
}
}
}
}
}
}
// se non ho una superficie di Blocco, allora non devo fare nulla
if ( IsNull( pSfrBlock) || ! pSfrBlock->IsValid())
return true ;
// determino la superficie di collisione
pSfrColl->Clear() ;
pSfrColl->CopyFrom( pSfrBlock) ;
// per essere sufficientemente distanti
pSfrColl->Offset( 50. * EPS_SMALL, ICurve::OFF_FILLET) ;
// riporto la superficie alla stessa quota della regione di sgrossatura
pSfrColl->Translate( pSfrSgro->GetNormVersor() * dDepth) ;
// determino la superficie di ricerca per la pulizia dei corners
pSfrSearchCorners->Clear() ;
pSfrSearchCorners->CopyFrom( pSfrColl) ;
pSfrSearchCorners->Offset( 1.5 * m_TParams.m_dDiam + TOL_OFFS_CORNER_COLL, ICurve::OFF_FILLET) ;
if ( ! pSfrSearchCorners->Intersect( *pSfrSgro))
return false ;
}
#if ENABLE_DEBUG_SFR_COLLISION
int _nSfrId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrColl->Clone()) ;
m_pGeomDB->SetMaterial( _nSfrId, Color( 128, 0, 128, 50)) ;
_nSfrId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrSearchCorners->Clone()) ;
m_pGeomDB->SetMaterial( _nSfrId, Color( 128, 128, 0, 50)) ;
#endif
return true ;
}
//----------------------------------------------------------------------------
ISurfFlatRegion*
SurfRoughing::GetSfrByStmIntersection( const IntersParPlanesSurfTm& IPPStm, double dDist, double dSmallOffs) const
{
// interseco la superficie alla quota corrente
PNTVECTOR vPnt ;
BIPNTVECTOR vBpt ;
TRIA3DVECTOR vTria ;
if ( ! IPPStm.GetInters( dDist, vPnt, vBpt, vTria))
return nullptr ;
// se non c'è intersezione
if ( vBpt.empty())
return CreateSurfFlatRegion() ;
// definisco la tolleranza per i concatenamenti
double dToler = 10 * EPS_SMALL ;
// costruisco la FlatRegion da ritornare
SurfFlatRegionByContours SfrByC ;
// Considero l'intersezione solo con Curve ( escludo punti e superfici)
ChainCurves chainC ;
chainC.Init( false, dToler, int( vBpt.size())) ;
for ( int i = 0 ; i < int( vBpt.size()) ; ++ i) {
Vector3d vtDir = vBpt[i].second - vBpt[i].first ;
vtDir.Normalize() ;
if ( ! chainC.AddCurve( i + 1, vBpt[i].first, vtDir, vBpt[i].second, vtDir))
return nullptr ;
}
// recupero i percorsi concatenati
Point3d ptNear = ( vBpt.empty() ? ORIG : vBpt[0].first) ;
INTVECTOR vId ;
while ( chainC.GetChainFromNear( ptNear, false, vId)) {
// creo una curva composita
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
if ( IsNull( pCrvCompo))
return nullptr ;
// recupero gli estremi dei segmenti, creo le linee e le inserisco nella composita
bool bAdded = true ;
for ( int i = 0 ; i < int( vId.size()) ; ++ i) {
// creo un segmento di retta
PtrOwner<ICurveLine> pLine( CreateCurveLine()) ;
if ( IsNull( pLine))
return nullptr ;
// recupero gli estremi ( non vanno mai invertiti per opzione di concatenamento)
int nInd = abs( vId[i]) - 1 ;
Point3d ptStart = ( bAdded ? vBpt[nInd].first : ptNear) ;
Point3d ptEnd = vBpt[nInd].second ;
// provo ad accodarlo alla composita
bAdded = ( Dist( ptStart, ptEnd) > dToler / 2 &&
pLine->Set( ptStart, ptEnd) &&
pCrvCompo->AddCurve( Release( pLine), true, dToler)) ;
ptNear = ( bAdded ? ptEnd : ptStart) ;
}
// se lunghezza curva inferiore a 5 volte la tolleranza, la ignoro
double dCrvLen ;
if ( ! pCrvCompo->GetLength( dCrvLen) || dCrvLen < 5. * dToler)
continue ;
// se curva chiusa entro 5 volte la tolleranza ma considerata aperta, la chiudo bene
Point3d ptStart, ptEnd ;
if ( pCrvCompo->GetStartPoint( ptStart) && pCrvCompo->GetEndPoint( ptEnd) &&
AreSamePointEpsilon( ptStart, ptEnd, 5. * dToler) && ! AreSamePointApprox( ptStart, ptEnd)) {
// porto il punto finale a coincidere esattamente con l'inizio
pCrvCompo->ModifyEnd( ptStart) ;
}
// unisco segmenti allineati
pCrvCompo->MergeCurves( 0.5 * dToler, ANG_TOL_STD_DEG) ;
pCrvCompo->Close() ; // per sicurezza...
// inserisco la curva nella FlatRegion
SfrByC.AddCurve( Release( pCrvCompo)) ;
}
// recupero la regione da restituire
PtrOwner<ISurfFlatRegion> pSfrFromCrvs( SfrByC.GetSurf()) ;
return ( ( ! IsNull( pSfrFromCrvs) && pSfrFromCrvs->IsValid()) ? Release( pSfrFromCrvs) : nullptr) ;
}
//----------------------------------------------------------------------------
ISurfFlatRegion*
SurfRoughing::GetSfrSilhouette( ICAvParSilhouettesSurfTm* pCavParSilh, double dDepth, double Sil_tol,
bool& bOk) const
{
// controllo dei parametri
bOk = false ;
if ( pCavParSilh == nullptr)
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 = 0.1 * Sil_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) &&
pTempCrv->IsValid())
pSilCrv.Set( pTempCrv) ;
}
// aggiungo per regione
if ( ! SfrMaker.AddCurve( Release( pSilCrv)))
return nullptr ;
}
bOk = true ;
return ( SfrMaker.GetSurf()) ;
}
//----------------------------------------------------------------------------
ISurfFlatRegion*
SurfRoughing::GetSfrCornerColl( ISurfFlatRegion* pSfr, const ISurfFlatRegion* pSfrLimit,
const ISurfFlatRegion* pSfrColl, const ISurfFlatRegion* pSfrSearchCorners) const
{
/*
se ho la presenza di tavole o ventose, la superficie di collissione ricavata genera dei nuovi
lati chiusi nella geometria attuale ( pSfr deve già avere impostati i lati OPEN/CLOSE)
i nuovi lati chiusi possono generare regioni i cui spigoli non si possono svuotare ( nei punti
di unione dei lati aperti originali con i nuovi chiusi).
questa funzione aggiunge delle piccole parti di regione in questi punti, evitando quindi la presenza
di colonne di materiale non rimosso
NB. questa parti non riguardano nè le regioni non vuotate, nè le regioni di silhouette ipotetica
*/
// se la superficie di collissione non è valida non faccio nulla
if ( pSfrColl == nullptr || ! pSfrColl->IsValid() ||
pSfrSearchCorners == nullptr || ! pSfrSearchCorners->IsValid())
return nullptr ;
if ( pSfr == nullptr)
return nullptr ;
#if ENABLE_DEBUG_REMOVED_REGION
int _nIdSfrSearch = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrSearchCorners->Clone()) ;
m_pGeomDB->SetMaterial( _nIdSfrSearch, YELLOW) ;
int _nIdSfrLimit = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrLimit->Clone()) ;
m_pGeomDB->SetMaterial( _nIdSfrLimit, GRAY) ;
DrawLoopsSurf( pSfr, false, Color( 0., 1., 0.), false, "") ;
#endif
// recupero tutti i lati aperti della superficie attuale
ICURVEPOVECTOR vCrvOpenInSearch ;
for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) {
for ( int nL = 0 ; nL < pSfr->GetLoopCount( nC) ; ++ nL) {
PtrOwner<ICurveComposite> pCompoLoop( ConvertCurveToComposite( pSfr->GetLoop( nC, nL))) ;
if ( IsNull( pCompoLoop) || ! pCompoLoop->IsValid())
return nullptr ;
ICRVCOMPOPOVECTOR vpCrvs ;
GetHomogeneousParts( pCompoLoop, vpCrvs) ;
for ( int i = 0 ; i < ssize( vpCrvs) ; ++ i) {
if ( vpCrvs[i]->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) {
CRVCVECTOR ccClass ;
if ( ! pSfrSearchCorners->GetCurveClassification( *vpCrvs[i], EPS_SMALL, ccClass))
return nullptr ;
for ( int j = 0 ; j < ssize( ccClass) ; ++ j) {
if ( ccClass[j].nClass != CRVC_OUT) {
PtrOwner<ICurve> pCrvIn( vpCrvs[i]->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ;
if ( ! IsNull( pCrvIn) && pCrvIn->IsValid()) {
if ( ! vCrvOpenInSearch.emplace_back( Release( pCrvIn)))
return nullptr ;
}
}
}
}
}
}
}
#if ENABLE_DEBUG_REMOVED_REGION
for ( int _i = 0 ; _i < ssize( vCrvOpenInSearch) ; ++ _i) {
int _nIdCrvOpen = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vCrvOpenInSearch[_i]->Clone()) ;
m_pGeomDB->SetMaterial( _nIdCrvOpen, ORANGE) ;
}
#endif
// determino la regione complessiva di ricerca
PtrOwner<ISurfFlatRegion> pSfrExtra( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrExtra))
return nullptr ;
double dOffs = m_TParams.m_dDiam + 50. * EPS_SMALL ; // deve passare l'utensile per tale regione
for ( int i = 0 ; i < ssize( vCrvOpenInSearch) ; ++ i) {
// recupero la curva come composita
PtrOwner<ICurveComposite> pCrvCompo( ConvertCurveToComposite( vCrvOpenInSearch[i]->Clone())) ;
if ( IsNull( pCrvCompo) || ! pCrvCompo->IsValid())
return nullptr ;
// calcolo il semi-offset
pCrvCompo->SetExtrusion( pSfr->GetNormVersor()) ;
OffsetCurve OffsCrv ;
if ( ! OffsCrv.Make( pCrvCompo, dOffs / 2., ICurve::OFF_FILLET))
return nullptr ;
PtrOwner<ICurve> pCrvOffs( OffsCrv.GetLongerCurve()) ;
if ( IsNull( pCrvOffs) || ! pCrvOffs->IsValid())
return nullptr ;
// determino la regione da aggiungere
if ( IsNull( pSfrExtra) || ! pSfrExtra->IsValid())
pSfrExtra.Set( GetSurfFlatRegionFromFatCurve( pCrvOffs->Clone(), dOffs / 2. + 50. * EPS_SMALL, false, false)) ;
else {
PtrOwner<ISurfFlatRegion> pSfrToAdd( GetSurfFlatRegionFromFatCurve( pCrvOffs->Clone(), dOffs / 2 + 50. * EPS_SMALL, false, false)) ;
if ( IsNull( pSfrToAdd) || ! pSfrToAdd->IsValid())
return nullptr ;
pSfrExtra->Add( *pSfrToAdd) ;
}
if ( IsNull( pSfrExtra) || ! pSfrExtra->IsValid())
return nullptr ;
}
if ( IsNull( pSfrExtra) || ! pSfrExtra->IsValid())
return nullptr ;
if ( ! pSfrExtra->Intersect( *pSfrSearchCorners))
return nullptr ;
// rimuovo i Chunk che non sono attaccati alle curve aperte ricavate
for ( int nC = 0 ; nC < pSfrExtra->GetChunkCount() ; ++ nC) {
PtrOwner<ISurfFlatRegion> pSfrExtraChunk( pSfrExtra->CloneChunk( nC)) ;
if ( IsNull( pSfrExtraChunk) || ! pSfrExtraChunk->IsValid())
return nullptr ;
bool bSave = false ;
for ( int i = 0 ; ! bSave && i < ssize( vCrvOpenInSearch) ; ++ i) {
CRVCVECTOR ccClass ;
if ( pSfrExtraChunk->GetCurveClassification( *vCrvOpenInSearch[i], 10. * EPS_SMALL, ccClass)) {
for ( int j = 0 ; ! bSave && j < ssize( ccClass) ; ++ j)
bSave = ( ccClass[j].nClass != CRVC_OUT) ;
}
}
if ( ! bSave) {
pSfrExtra->EraseChunk( nC) ;
-- nC ;
}
}
// se superficie non valida, ho finito
if ( IsNull( pSfrExtra) || ! pSfrExtra->IsValid())
return nullptr ;
// rimuovo la regione da non rovinare, ho esteso i lati aperti mediante Offset semplice,
// devo controllare di non rovinare altre regioni
// regolarizzo la superficie
pSfrExtra->Offset( m_TParams.m_dDiam / 8., ICurve::OFF_FILLET) ;
pSfrExtra->Offset( - m_TParams.m_dDiam / 8., ICurve::OFF_FILLET) ;
if ( ! pSfrExtra->Subtract( *pSfrLimit))
return nullptr ;
#if ENABLE_DEBUG_REMOVED_REGION
int _nIdExtraSfr = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrExtra->Clone()) ;
m_pGeomDB->SetMaterial( _nIdExtraSfr, FUCHSIA) ;
#endif
return ( Release( pSfrExtra)) ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::GetActiveSurfaces( INTVECTOR& vSurfId, INTVECTOR& vSurfSuppId) const
{
// NB.
// - vSrufInd contiene gli Id delle superfici selezionate ( nel caso non ci siano superfici
// selezionate, allora vengono considerate tutte le superfici presenti nei grezzi attivi della fase)
// - vSurfSupp contiene gli Id delle superfici di supporto, quindi quelle superici da cui si vuole
// mantenere una certa distanza con l'utensile ( senza che siano selezionate)
// pulisco vettore superfici
vSurfId.clear() ;
vSurfSuppId.clear() ;
// verifiche
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// cerco tra gli oggetti selezionati ( superfici TriMesh o Bezier)
for ( const auto& Id : m_vId) {
int nEntId = Id.nId ;
int nType = m_pGeomDB->GetGeoType( nEntId) ;
if ( nType == SRF_TRIMESH || nType == SRF_BEZIER)
vSurfId.emplace_back( nEntId) ;
}
// controllo se sono state trovate delle superfici
bool bNoSurfId = ( vSurfId.empty()) ;
// scorro 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->GetGeoType( nEntId) == SRF_BEZIER) &&
m_pGeomDB->GetCalcStatus( nEntId, nStat) && nStat != GDB_ST_OFF) {
// se non sono state selezionate superfici precedentemente, memorizzo tale id
if ( bNoSurfId)
vSurfId.emplace_back( nEntId) ;
// verifico se è presente una superficie di controllo
string sLayIdName ;
if ( m_pGeomDB->GetName( nLayId, sLayIdName) && EqualNoCase( sLayIdName, SRF_SUPP_LAYER_NAME))
vSurfSuppId.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
SurfRoughing::CalcPaths( const INTINTVECTOR& vPocket, STEPINFOSRVECTOR& vStepInfo) const
{
// Funzione per calcolo dei percorsi di Pockets e delle loro proprietà
// inizializzo vettore dei percorsi
vStepInfo.resize( vPocket.size()) ;
// punto finale di riferimento per il percorso attuale ( serve per trovare il punto iniziale
// del percorso successivo)
Point3d ptEndLastPath = P_INVALID ;
// determino se Conventional Milling o Climb Milling per curve singole
bool bConventionalMilling = ( m_Params.m_nSubType == POCKET_ONEWAY || m_Params.m_nSubType == POCKET_CONFORMAL_ONEWAY) ;
// scorro gli indici delle superfici
int nInd = 0 ;
for ( auto& vId : vPocket) {
// --- recupero la superficie da lavorare
const ISurfFlatRegion* pSfrPock = GetSurfFlatRegion( m_pGeomDB->GetGeoObj( vId.first)) ;
if ( pSfrPock == nullptr || ! pSfrPock->IsValid())
continue ;
vStepInfo[nInd].pSfrPock.Set( CloneSurfFlatRegion( pSfrPock)) ;
// --- recupero Flag per step normale o extra ( SubStep/PlaneZ)
string sIsExtraStep = "" ;
bool bIsExtraStep = false ;
if ( ! m_pGeomDB->GetInfo( vId.first, KEY_SUBSTEP, sIsExtraStep) ||
! FromString( sIsExtraStep, bIsExtraStep)) {
m_pMchMgr->SetLastError( 3035, "Error in SurfRoughing : Entity without Info") ;
return false ;
}
vStepInfo[nInd].bIsExtraStep = bIsExtraStep ;
// --- recupero la Depth attuale
string sDepth = "" ;
double dDepth = 0. ;
if ( ! m_pGeomDB->GetInfo( vId.first, KEY_DEPTH, sDepth) ||
! FromString( sDepth, dDepth)) {
m_pMchMgr->SetLastError( 3035, "Error in SurfRoughing : Entity without Info") ;
return false ;
}
vStepInfo[nInd].dDepth = dDepth ;
// --- recupero la Depth relativa
string sRelativeDepth = "" ;
double dRelativeDepth = 0. ;
if ( ! m_pGeomDB->GetInfo( vId.first, KEY_RELATIVE_DEPTH, sRelativeDepth) ||
! FromString( sRelativeDepth, dRelativeDepth)) {
m_pMchMgr->SetLastError( 3035, "Error in SurfRoughing : Entity without Info") ;
return false ;
}
vStepInfo[nInd].dRelativeDepth = dRelativeDepth ;
// --- recupero il coefficiente di riduzione Feed locale
string sZlocCoeffFeed = "" ;
double dZlocCoeffFeed = 0. ;
if ( ! m_pGeomDB->GetInfo( vId.first, KEY_ZLOCFEEDCOEF, sZlocCoeffFeed) ||
! FromString( sZlocCoeffFeed, dZlocCoeffFeed)) {
m_pMchMgr->SetLastError( 3035, "Error in SurfRoughing : Entity without Info") ;
return false ;
}
vStepInfo[nInd].dZlocCoeffFeed = dZlocCoeffFeed ;
// --- recupero la superficie limite se presente
vStepInfo[nInd].pSfrLimit.Set( CreateSurfFlatRegion()) ;
if ( vId.second != GDB_ID_NULL) {
const ISurfFlatRegion* pSfrL = GetSurfFlatRegion( m_pGeomDB->GetGeoObj( vId.second)) ;
if ( pSfrL == nullptr)
return false ;
vStepInfo[nInd].pSfrLimit.Set( CloneSurfFlatRegion( pSfrL)) ;
}
// se il tipo è SPIRAL_OUT e sto gestendo uno step intermedio, lo lavoro come SPIRAL_IN invertito
int nSubType = m_Params.m_nSubType ;
bool bInvert = m_Params.m_bInvert ;
if ( nSubType == SURFROU_SUB_SPIRALOUT && vStepInfo[nInd].bIsExtraStep) {
nSubType = SURFROU_SUB_SPIRALIN ;
bInvert = ! bInvert ; // per lasciare invariato il senso di percorrenza
}
vStepInfo[nInd].nSubType = nSubType ;
vStepInfo[nInd].bInverted = bInvert ;
// calcolo i percorsi di Pocketing
ICRVCOMPOPOVECTOR vCrvPaths ;
if ( ! CalcPocketing( vStepInfo[nInd].pSfrPock, m_TParams.m_dDiam / 2, 0., m_Params.m_dSideStep,
m_Params.m_dSideAngle, 5., vStepInfo[nInd].nSubType, true, true, vStepInfo[nInd].bInverted,
false, bConventionalMilling, true, true, ptEndLastPath, vStepInfo[nInd].pSfrLimit, false, m_Params.m_dSideStep,
GetLeadInType(), m_Params.m_dLiTang, m_Params.m_dLiElev, GetLeadOutType(), m_Params.m_dLoTang,
false, 0., 0., vCrvPaths)) {
if ( vStepInfo[nInd].bIsExtraStep) {
string sWarn = "Warning in SurfRoughing : CalcPocketing failed with substep (" + ToString( vStepInfo[nInd].dDepth, 1) + ")" ;
m_pMchMgr->SetWarning( 3055, sWarn) ;
vCrvPaths.clear() ;
}
else {
m_pMchMgr->SetLastError( 3028, "Error in SurfRoughing : Error in CalcPocketing") ;
return false ;
}
}
// se non ho ottenuto percorsi, allora passo allo step successivo ( nInd non viene aggiornato!)
if ( vCrvPaths.empty())
continue ;
// sistemo gli archi per massimo angolo al centro
for ( int i = 0 ; i < int( vCrvPaths.size()) ; ++ i)
VerifyArcs( vCrvPaths[i]) ;
// recupero il punto finale del percorso per lo step successivo
vCrvPaths.back()->GetEndPoint( ptEndLastPath) ;
// aggiorno il vettore degli step e modifico eventuali percorsi per LeadIn/LeadOut
// --- Controllo se il tratto lineare di estensione per l'entrata da un lato aperto non rovina
// --- un tratto chiuso della curva di bordo selezionata per la sgrossatura;
// --- idem per il tratto in uscita.
vStepInfo[nInd].vPaths.resize( int( vCrvPaths.size())) ;
for ( int i = 0 ; i < int( vCrvPaths.size()) ; ++ i) {
// controllo se il percorso ha un ingresso presso un lato aperto
vStepInfo[nInd].vPaths[i].bOutStart = ( vCrvPaths[i]->GetCurveCount() > 0 &&
vCrvPaths[i]->GetFirstCurve()->GetTempProp( 0) == TEMP_PROP_OUT_START) ;
// se utensile che non lavora di testa e ingresso non fuori dal pezzo, errore
if ( m_TParams.m_nType == TT_MILL_NOTIP && ! vStepInfo[nInd].vPaths[i].bOutStart) {
if ( ! LeadInRawIsOk()) {
m_pMchMgr->SetLastError( 3031, "Error in SurfRoughing : LeadIn with Mill NoTip in material") ;
return false ;
}
}
// controllo se il percorso è formato da una singola curva seguente il lato chiuso
vStepInfo[nInd].vPaths[i].bSingleCrv = ( vCrvPaths[i]->GetCurveCount() > 0 &&
vCrvPaths[i]->GetTempProp( 0) == TEMP_PROP_SINGLE_CURVE) ;
// controllo se caso ottimizzato a trapezio
vStepInfo[nInd].vPaths[i].bOptTrap = ( vCrvPaths[i]->GetCurveCount() > 0 &&
vCrvPaths[i]->GetTempProp( 0) == TEMP_PROP_OPT_TRAPEZOID) ;
// controllo se è un percorso a ZigZag/OneWay ( non curva di bordo)
vStepInfo[nInd].vPaths[i].bIsZigZagOneWayBorder = ( vCrvPaths[i]->GetCurveCount() > 0 &&
( vStepInfo[nInd].nSubType == SURFROU_SUB_ONEWAY || vStepInfo[nInd].nSubType == SURFROU_SUB_ZIGZAG) &&
vCrvPaths[i]->GetTempProp( 0) == TEMP_PROP_BORDER_CURVE) ;
// se LeadIn o LeadOut a guida recupero la curva di ritorno se necessaria
if ( ( GetLeadInType() == SURFROU_LI_GLIDE || GetLeadOutType() == SURFROU_LO_GLIDE) &&
( vStepInfo[nInd].nSubType == SURFROU_SUB_SPIRALIN &&
! vStepInfo[nInd].vPaths[i].bSingleCrv && ! vStepInfo[nInd].vPaths[i].bOutStart))
{
if ( vStepInfo[nInd].vPaths[i].bOptTrap)
vStepInfo[nInd].vPaths[i].pCvrRet.Set( ConvertCurveToComposite( vCrvPaths[i]->GetFirstCurve()->Clone())) ;
else {
Point3d ptStart ; vCrvPaths[i]->GetFirstCurve()->GetStartPoint( ptStart) ;
vStepInfo[nInd].vPaths[i].pCvrRet.Set( CreateCurveComposite()) ;
for ( int j = 0 ; j < vCrvPaths[i]->GetCurveCount() ; ++ j) {
const ICurve* pCrv = vCrvPaths[i]->GetCurve( j) ;
Point3d ptEnd ;
if ( pCrv == nullptr ||
! vStepInfo[nInd].vPaths[i].pCvrRet->AddCurve( *pCrv) ||
! pCrv->GetEndPoint( ptEnd))
return false ;
if ( AreSamePointApprox( ptStart, ptEnd))
break ;
}
}
}
// assegno il percorso
vStepInfo[nInd].vPaths[i].pCrvPath.Set( vCrvPaths[i]) ;
}
++ nInd ;
// aggiorno la progressBar
ExeProcessEvents( 50 + nInd * 50 / int( vPocket.size()), 0) ;
}
vStepInfo.resize( nInd) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::GetLinkFromPaths( STEPINFOSRVECTOR& vStepInfo, int i, int j, const Point3d& ptStart,
const Vector3d& vtTool, double dSafeZ, double dExtraElev, double& dEndElev,
ICurveComposite* pCrvLink) const
{
// NB. Tutte le ipotesi descritte valgono globalmente per l'ordine di sgrossatura per piani;
// Nel caso di ordine ZChunk queste ipotesi valgono localmente.
// controllo dei parametri
if ( vStepInfo.empty())
return true ;
if ( pCrvLink == nullptr)
return false ;
// reset parametri restituiti
pCrvLink->Clear() ;
dEndElev = 0. ;
// verifico se lo step successivo si trova sopra, sotto o sullo stesso piano di quello corrente
// recupero anche il suo punto iniziale, ovvero il punto finale del Link
int nLinkType = -1 ;
Point3d ptEnd ;
if ( j < ssize( vStepInfo[i].vPaths) - 1) {
nLinkType = PLANAR ;
vStepInfo[i].vPaths[j+1].pCrvPath->GetStartPoint( ptEnd) ;
}
else {
// --- se non esiste lo Step i+1 errore
if ( i + 1 >= ssize( vStepInfo))
return false ;
vStepInfo[i+1].vPaths.front().pCrvPath->GetStartPoint( ptEnd) ;
nLinkType = ( ( ptEnd - ptStart) * vtTool < - 50 * EPS_SMALL ? DOWN : ABOVE) ;
}
// se estremi coincidenti, non faccio nulla
if ( AreSamePointApprox( ptStart, ptEnd))
return true ;
#if ENBALE_DEBUG_LINK
int nGrp = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ;
m_pGeomDB->SetName( nGrp, "Path Links") ;
int nLay = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrp, GLOB_FRM) ;
PtrOwner<IGeoPoint3d> pt( CreateGeoPoint3d()) ;
pt->Set( ptStart) ;
int nPt = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pt->Clone()) ;
m_pGeomDB->SetMaterial( nPt, RED) ;
pt->Set( ptEnd) ;
nPt = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pt->Clone()) ;
m_pGeomDB->SetMaterial( nPt, AQUA) ;
#endif
// calcolo l'elevazione sopra al collegamento lineare
double dElev = 0. ;
if ( ! GetElevation( m_nPhase, ptStart, ptEnd, vtTool, m_TParams.m_dDiam / 2., m_TParams.m_dLen, vtTool, dElev))
return false ;
// --- se l'elevazione è nulla, allora il collegamento è completamente fuori dal grezzo, quindi ho finito
if ( dElev < EPS_SMALL) {
pCrvLink->AddPoint( ptStart) ;
pCrvLink->AddLine( ptEnd) ;
#if ENBALE_DEBUG_LINK
int nCrv = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCrvLink->Clone()) ;
m_pGeomDB->SetMaterial( nCrv, LIME) ;
#endif
return true ;
}
// classifico a seconda del tipo di collegamento
switch ( nLinkType) {
case DOWN : {
// ---------- il percorso successivo si trova ad uno step più in basso ----------
// Controllo se sono fuori dalla regione limite allo step i-esimo
bool bSafe = false ;
if ( ! CheckSafetyLinearLink( ptStart, ptEnd, vStepInfo[i].pSfrLimit, vtTool, bSafe))
return false ;
// nel caso stessi ordinando per ZChunk, devo controllare di essere fuori dalla limite
// anche per lo Step i+1
// NB. Nel caso stessi ordinando per piani, vuol dire che ho già svuotato tutto il piano i-esimo
// Se Safe, allora definisco il collegamento
if ( bSafe) {
pCrvLink->AddPoint( ptStart) ;
dEndElev = abs( vStepInfo[i].dDepth - vStepInfo[i+1].dDepth) ;
pCrvLink->AddLine( ptEnd + dEndElev * vtTool) ;
#if ENBALE_DEBUG_LINK
int nCrv = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCrvLink->Clone()) ;
m_pGeomDB->SetMaterial( nCrv, LIME) ;
#endif
return true ;
}
// Se non Safe, allora cerco tra gli Step percorsi in precedenza quelli con cui il collegamento
// lineare non interferisce con la regione limite, tra tutti quelli validi cerco quello più vicino
// e al di sopra dello step corrente
double dCurrDepth = vStepInfo[i].dDepth ;
double dMinDepthAbove = INFINITO ;
bool bFound = false ;
for ( int nStep = i - 1 ; nStep >= 0 ; -- nStep) {
bSafe = false ;
if ( ! CheckSafetyLinearLink( ptStart, ptEnd, vStepInfo[nStep].pSfrLimit, vtTool, bSafe))
return false ;
if ( bSafe && vStepInfo[nStep].dDepth > dCurrDepth && vStepInfo[nStep].dDepth < dMinDepthAbove) {
dMinDepthAbove = vStepInfo[nStep].dDepth ;
bFound = true ;
}
}
// Se ho trovato un step più alto fatto in precedenza valido, allora l'elevazione iniziale è la
// differenza tra le profondità, altrimenti mi alzo dell'intera profondità dello step corrente
double dStartElev = ( bFound ? abs( dMinDepthAbove - dCurrDepth) + dSafeZ :
abs( dCurrDepth) + dSafeZ) ;
Point3d ptUp = ptStart + dStartElev * vtTool ;
dEndElev = abs( ( ptEnd - ptUp) * vtTool) ;
pCrvLink->AddPoint( ptStart) ;
pCrvLink->AddLine( ptUp) ;
pCrvLink->AddLine( ptEnd + dEndElev * vtTool) ;
#if ENBALE_DEBUG_LINK
int nCrv = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCrvLink->Clone()) ;
m_pGeomDB->SetMaterial( nCrv, LIME) ;
#endif
return true ;
}
break ;
case PLANAR : {
// ---------- il percorso successivo si trova allo stesso step del corrente ----------
// Devo controllare di essere fuori dalla limite corrente e fuori da tutti i Chunk di pocketing
// dello stesso piano non ancora rimossi
// Controllo di essere fuori dalla limite
bool bSafe = false ;
if ( ! CheckSafetyLinearLink( ptStart, ptEnd, vStepInfo[i].pSfrLimit, vtTool, bSafe))
return false ;
// --- Se fuori dalla Limite
if ( bSafe) {
// Scorro i percorsi successivi per individuare i Chunks
PtrOwner<ISurfFlatRegion> pSfrUncleared( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrUncleared))
return false ;
for ( int nPath = j + 1 ; nPath < int( vStepInfo[i].vPaths.size()) ; ++ nPath) {
Point3d ptMid ; vStepInfo[i].vPaths[nPath].pCrvPath->GetMidPoint( ptMid) ;
int nMinChunk = -1 ;
int nMinLoop = -1 ;
double dMinPar = 0. ;
DistPointSurfFr( ptMid, *vStepInfo[i].pSfrPock).GetParamAtMinDist( nMinChunk, nMinLoop, dMinPar) ;
pSfrUncleared->AddExtLoop( vStepInfo[i].pSfrPock->GetLoop( nMinChunk, 0)) ;
for ( int nL = 1 ; nL < vStepInfo[i].pSfrPock->GetLoopCount( nMinChunk) ; ++ nL)
pSfrUncleared->AddIntLoop( vStepInfo[i].pSfrPock->GetLoop( nMinChunk, nL)) ;
}
// Controllo di essere fuori dalla superficie creata
if ( ! CheckSafetyLinearLink( ptStart, ptEnd, pSfrUncleared, vtTool, bSafe))
return false ;
// --- Se sono al di fuori di tutto
if ( bSafe) {
pCrvLink->AddPoint( ptStart) ;
pCrvLink->AddLine( ptEnd) ;
dEndElev = 0. ;
#if ENBALE_DEBUG_LINK
int nCrv = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCrvLink->Clone()) ;
m_pGeomDB->SetMaterial( nCrv, LIME) ;
#endif
return true ;
}
}
// Se non Safe, allora cerco tra gli Step percorsi in precedenza quelli con cui il collegamento
// lineare non interferisce con la regione limite, tra tutti quelli validi cerco quello più vicino
// e al di sopra dello step corrente
double dCurrDepth = vStepInfo[i].dDepth ;
double dMinDepthAbove = INFINITO ;
bool bFound = false ;
for ( int nStep = i - 1 ; nStep >= 0 ; -- nStep) {
bSafe = false ;
if ( ! CheckSafetyLinearLink( ptStart, ptEnd, vStepInfo[nStep].pSfrLimit, vtTool, bSafe))
return false ;
if ( bSafe && vStepInfo[nStep].dDepth > dCurrDepth && vStepInfo[nStep].dDepth < dMinDepthAbove) {
dMinDepthAbove = vStepInfo[nStep].dDepth ;
bFound = true ;
}
}
// Se ho trovato un step più alto fatto in precedenza valido, allora l'elevazione iniziale è la
// differenza tra le profondità, altrimenti mi alzo dell'intera profondità dello step corrente
double dStartElev = ( bFound ? abs( dMinDepthAbove - dCurrDepth) + dSafeZ :
abs( dCurrDepth) + dSafeZ) ;
Point3d ptUp = ptStart + dStartElev * vtTool ;
dEndElev = abs( ( ptEnd - ptUp) * vtTool) ;
pCrvLink->AddPoint( ptStart) ;
pCrvLink->AddLine( ptUp) ;
pCrvLink->AddLine( ptEnd + dEndElev * vtTool) ;
#if ENBALE_DEBUG_LINK
int nCrv = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCrvLink->Clone()) ;
m_pGeomDB->SetMaterial( nCrv, LIME) ;
#endif
return true ;
}
break ;
case ABOVE : {
// ---------- il percorso successivo si trova al di sopra dello step del corrente ----------
// Significa che allo Step (i+1)-esimo non ho ancora rimosso nulla
double dStartElev = 0. ;
// Controllo di essere fuori dalla Limite e dalla regione di Pocketing allo step i+1
bool bSafe = false ;
if ( ! m_bOrderZ) {
// --- Se sto sgrossando per piani paralleli, allora le superficie allo step i+1 sono complessive
if ( ! CheckSafetyLinearLink( ptStart, ptEnd, vStepInfo[i+1].pSfrLimit, vtTool, bSafe))
return false ;
if ( bSafe) {
if ( ! CheckSafetyLinearLink( ptStart, ptEnd, vStepInfo[i+1].pSfrPock, vtTool, bSafe))
return false ;
}
}
else {
// --- Se sto sfrossando per ZChunks, allora devo recuperare tutti i chunk alla quota successiva
for ( int nStep = 0 ; nStep < int( vStepInfo.size()) && bSafe ; ++ nStep) {
if ( abs( vStepInfo[nStep].dDepth - vStepInfo[i+1].dDepth) < 50. * EPS_SMALL) {
if ( ! CheckSafetyLinearLink( ptStart, ptEnd, vStepInfo[i+1].pSfrLimit, vtTool, bSafe))
return false ;
if ( bSafe) {
if ( ! CheckSafetyLinearLink( ptStart, ptEnd, vStepInfo[i+1].pSfrPock, vtTool, bSafe))
return false ;
}
}
}
}
// --- Se Safe, allora definisco il collegamento
if ( bSafe) {
pCrvLink->AddPoint( ptStart) ;
dStartElev = abs( ( ptStart - ptEnd) * vtTool) ;
pCrvLink->AddLine( ptStart + dStartElev * vtTool) ;
pCrvLink->AddLine( ptEnd) ;
dEndElev = 0. ;
#if ENBALE_DEBUG_LINK
int nCrv = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCrvLink->Clone()) ;
m_pGeomDB->SetMaterial( nCrv, LIME) ;
#endif
}
else {
// Se non Safe, allora cerco tra gli Step percorsi in precedenza quelli con cui il collegamento
// lineare non interferisce con la regione limite, tra tutti quelli validi cerco quello più vicino
// e al di sopra dello step corrente
double dCurrDepth = vStepInfo[i].dDepth ;
double dMinDepthAbove = INFINITO ;
bool bFound = false ;
for ( int nStep = i - 1 ; nStep >= 0 ; -- nStep) {
bSafe = false ;
if ( ! CheckSafetyLinearLink( ptStart, ptEnd, vStepInfo[nStep].pSfrLimit, vtTool, bSafe))
return false ;
if ( bSafe && vStepInfo[nStep].dDepth > dCurrDepth && vStepInfo[nStep].dDepth < dMinDepthAbove) {
dMinDepthAbove = vStepInfo[nStep].dDepth ;
bFound = true ;
}
}
// Se ho trovato un step più alto fatto in precedenza valido, allora l'elevazione iniziale è la
// differenza tra le profondità, altrimenti mi alzo dell'intera profondità dello step corrente
dStartElev = ( bFound ? abs( dMinDepthAbove - dCurrDepth) + dSafeZ :
abs( dCurrDepth) + dSafeZ) ;
Point3d ptUp = ptStart + dStartElev * vtTool ;
dEndElev = abs( ( ptEnd - ptUp) * vtTool) ;
pCrvLink->AddPoint( ptStart) ;
pCrvLink->AddLine( ptUp) ;
pCrvLink->AddLine( ptEnd + dEndElev * vtTool) ;
#if ENBALE_DEBUG_LINK
int nCrv = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCrvLink->Clone()) ;
m_pGeomDB->SetMaterial( nCrv, LIME) ;
#endif
}
// se entrata da fuori...
if ( vStepInfo[i+1].vPaths.front().bOutStart) {
// --- controllo che il punto elevato sopra a ptEnd non sia già sulla curva di entrata da fuori
// del percorso successivo ( evito di creare entrate a ZigZag con overlap)
if ( vStepInfo[i+1].vPaths.front().pCrvPath->GetFirstCurve()->IsPointOn( ptStart + vtTool * dStartElev)) {
double dUStartTrim = 0. ;
vStepInfo[i+1].vPaths.front().pCrvPath->GetFirstCurve()->GetParamAtPoint( ptStart + vtTool * dStartElev, dUStartTrim) ;
if ( dUStartTrim > EPS_PARAM) {
delete( pCrvLink->RemoveFirstOrLastCurve( true)) ;
#if ENBALE_DEBUG_LINK
PtrOwner<ICurve> pCrvTrim( vStepInfo[i+1].vPaths.front().pCrvPath->GetFirstCurve()->CopyParamRange( 0., dUStartTrim)) ;
if ( ! IsNull( pCrvTrim)) {
int nCrv = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCrvTrim->Clone()) ;
m_pGeomDB->SetMaterial( nCrv, OLIVE) ;
}
#endif
vStepInfo[i+1].vPaths.front().pCrvPath->TrimStartAtParam( dUStartTrim) ;
}
}
}
}
break ;
default :
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::OrderZChunkSteps( STEPDATAMATRIX& vvDataSteps, STEPDATAMATRIX& vIndepChunkGroup,
INTDBLDBLVECTOR& vMapGrpZLoc) const
{
vIndepChunkGroup.clear() ;
vMapGrpZLoc.clear() ;
// se non ho Steps non faccio nulla
if ( vvDataSteps.empty())
return true ;
// ordino le righe della matrice ( i piani) per Z decrescente ( Z è negativa rispetto al piano { ORIG, Z_AX})
sort( vvDataSteps.begin(), vvDataSteps.end(), []( const STEPDATAVECTOR& vSDA, const STEPDATAVECTOR& vSDB) {
if ( ! vSDA.empty() && ! vSDB.empty())
return ( vSDA[0].dDepth > vSDB[0].dDepth) ;
return false ;
}) ;
// definisco le relazioni delle superfici
int nRowSize = int( vvDataSteps.size()) ;
int nColSize = 0 ;
for ( int i = 0 ; i < nRowSize ; ++ i)
nColSize = max( nColSize, int( vvDataSteps[i].size())) ;
unordered_map<int, INTINTVECTOR> MapLock ;
unordered_map<int, INTINTVECTOR> MapUnlock ;
for ( int nR = int( vvDataSteps.size()) - 1 ; nR >= 1 ; -- nR) {
for ( int nC = 0 ; nC < int( vvDataSteps[nR].size()) ; ++ nC) {
for ( int nRow = nR - 1 ; nRow >= 0 ; -- nRow) {
bool bRowFound = false ;
for ( int nCol = 0 ; nCol < int( vvDataSteps[nRow].size()) ; ++ nCol) {
PtrOwner<ISurfFlatRegion> pSfrA( nullptr) ;
if ( vvDataSteps[nR][nC].bIsSubStep || vvDataSteps[nRow][nCol].bIsSubStep)
pSfrA.Set( vvDataSteps[nR][nC].pSfrChunk->CreateOffsetSurf( m_dSubStepToler + 50 * EPS_SMALL, ICurve::OFF_FILLET)) ;
else
pSfrA.Set( CloneSurfFlatRegion( vvDataSteps[nR][nC].pSfrChunk)) ;
const ISurfFlatRegion* pSfrB = vvDataSteps[nRow][nCol].pSfrChunk ;
if ( ! IsNull( pSfrA) && pSfrB != nullptr) {
if ( ! pSfrA->Intersect( *pSfrB)) {
// provo con una tolleranza leggermente più grande
pSfrA->Offset( 25. * EPS_SMALL, ICurve::OFF_FILLET) ;
pSfrA->Intersect( *pSfrB) ;
}
if ( pSfrA->IsValid() && pSfrA->GetChunkCount() > 0) {
bRowFound = true ;
// Il Chunk di Key nKeyLock è bloccato dal Chunk ( nR - 1, nCol)
// Il Chunk di Key nKeyUnlock blocca il Chunk ( nR, nC)
int nKeyLock = nR * nColSize + nC ;
int nKeyUnlock = ( nRow) * nColSize + nCol ;
MapLock[nKeyLock].emplace_back( make_pair( nRow, nCol)) ;
MapUnlock[nKeyUnlock].emplace_back( make_pair( nR, nC)) ;
}
}
}
if ( bRowFound || ! vvDataSteps[nRow].back().bIsSubStep)
break ;
}
}
}
// definisco i gruppi di Chunk indipendenti; Un insieme di Chunk risulta indipendente da un altro
// insieme se l'ordine di esecuzione di essi è indifferente ;
// [non esiste alcun Chunk nel gruppo A che interferisce con un Chunk del gruppo B]
bool bGroup = true ;
int nCont = 0 ;
while ( bGroup && nCont < nRowSize * nColSize) {
++ nCont ;
bGroup = false ;
// cerco il primo Chunk non ancora inserito nel gruppo
for ( int nR = int( vvDataSteps.size()) - 1 ; nR >= 0 && ! bGroup ; -- nR) {
// scorro le colonne ( dalla prima all'ultima) [ordine casuale]
for ( int nC = 0 ; nC < int( vvDataSteps[nR].size()) && ! bGroup ; ++ nC) {
// se il Chunk è già in un gruppo ( quindi nullptr), passo al successivo
if ( vvDataSteps[nR][nC].pSfrChunk == nullptr)
continue ;
// se Chunk trovato, allora ho un nuovo gruppo da analizzare
bGroup = true ;
// creazione dello spazio per un nuovo gruppo
vIndepChunkGroup.resize( vIndepChunkGroup.size() + 1) ;
INTINTVECTOR vMapIndCheck = { make_pair( nR, nC)} ;
// finchè ho indici di riga-colonna da verificare
while ( ! vMapIndCheck.empty()) {
// memorizzo gli indici correnti
int nCurrRow = vMapIndCheck.back().first ;
int nCurrCol = vMapIndCheck.back().second ;
// tolgo l'elemento ( non devo ricontrollarlo all'iterazione successiva)
vMapIndCheck.pop_back() ;
// controllo se è già stato inserito
if ( vvDataSteps[nCurrRow][nCurrCol].pSfrChunk == nullptr) // (*)
continue ; // [ho rimosso l'elemento ( nCurrRow, nCurrCol)]
// alloco spazio di memoria
vIndepChunkGroup.back().resize( vIndepChunkGroup.back().size() + 1) ;
// --- Flag per Step base
vIndepChunkGroup.back().back().bIsSubStep = vvDataSteps[nCurrRow][nCurrCol].bIsSubStep ;
// --- Depth
vIndepChunkGroup.back().back().dDepth = vvDataSteps[nCurrRow][nCurrCol].dDepth ;
// --- Depth relativa
vIndepChunkGroup.back().back().dRelativeDepth = vvDataSteps[nCurrRow][nCurrCol].dRelativeDepth ;
// --- Coefficiente di riduzione della Feed in locale
vIndepChunkGroup.back().back().dZLocCoeffFeed = vvDataSteps[nCurrRow][nCurrCol].dZLocCoeffFeed ;
// --- regione di sgrossatura
vIndepChunkGroup.back().back().pSfrChunk.Set( Release( vvDataSteps[nCurrRow][nCurrCol].pSfrChunk)) ;
// --- regione limite
vIndepChunkGroup.back().back().pSfrLimit.Set( nullptr) ;
if ( ! IsNull( vvDataSteps[nCurrRow][nCurrCol].pSfrLimit) && vvDataSteps[nCurrRow][nCurrCol].pSfrLimit->IsValid())
vIndepChunkGroup.back().back().pSfrLimit.Set( Release( vvDataSteps[nCurrRow][nCurrCol].pSfrLimit)) ;
// --- regione rimossa
vIndepChunkGroup.back().back().pSfrRemoved.Set( nullptr) ;
if ( ! IsNull( vvDataSteps[nCurrRow][nCurrCol].pSfrRemoved) && vvDataSteps[nCurrRow][nCurrCol].pSfrRemoved->IsValid())
vIndepChunkGroup.back().back().pSfrRemoved.Set( Release( vvDataSteps[nCurrRow][nCurrCol].pSfrRemoved)) ;
// --- se il Chunk non è bloccato da nessun altro
auto itLock = MapLock.find( nCurrRow * nColSize + nCurrCol) ;
if ( itLock == MapLock.end())
; // non faccio nulla
// --- altrimenti
else {
// --- scorro i chunk che bloccano quello corrente
for ( int i = 0 ; i < int( itLock->second.size()) ; ++ i) {
int nBR = itLock->second[i].first ;
int nBC = itLock->second[i].second ;
INTINT Key = make_pair( nBR, nBC) ;
auto itUnLock = MapUnlock.find( nBR * nColSize + nBC) ;
// verifico che non ci siano altri Chunk bloccanti
bool bInsert = true ;
for ( int j = 0 ; j < int( itUnLock->second.size()) ; ++ j) {
if ( vvDataSteps[itUnLock->second[j].first][itUnLock->second[j].second].pSfrChunk != nullptr) {
INTINTVECTOR vInd = { make_pair( itUnLock->second[j].first, itUnLock->second[j].second)} ;
while ( ! vInd.empty()) {
int nMyCurrRow = vInd.back().first ;
int nMyCurrCol = vInd.back().second ;
vInd.pop_back() ;
auto itUnlock = MapUnlock.find( nMyCurrRow * nColSize + nMyCurrCol) ;
if ( itUnlock == MapUnlock.end())
vMapIndCheck.emplace_back( make_pair( nMyCurrRow, nMyCurrCol)) ;
// --- altrimenti
else {
for ( int k = 0 ; k < int( itUnlock->second.size()) ; ++ k) {
int nMyBR = itUnlock->second[k].first ;
int nMyBC = itUnlock->second[k].second ;
if ( vvDataSteps[nMyBR][nMyBC].pSfrChunk != nullptr)
vInd.emplace_back( make_pair( nMyBR, nMyBC)) ;
}
}
}
bInsert = false ;
// [ metto dentro alcuni valori ( nR, nC) doppi...], però ho il controllo sopra (*)
}
}
if ( bInsert)
vMapIndCheck.emplace_back( Key) ;
}
}
}
}
}
}
// ordino i gruppi di Chunk indipendenti
vMapGrpZLoc.reserve( vIndepChunkGroup.size()) ;
for ( int i = 0 ; i < int( vIndepChunkGroup.size()) ; ++ i) {
// scorro le curve del gruppo cercando quella più in alto ( rispetto alla Zlocale di frXY)
double dZMax = - INFINITO ;
double dZMin = INFINITO ;
for ( StepData& myStepData : vIndepChunkGroup[i]) {
Point3d ptCen ; myStepData.pSfrChunk->GetCentroid( ptCen) ;
double dCurrZ = ptCen.z ; // negativa ( < 0)
dZMax = max( dZMax, dCurrZ) ; // più vicina al piano { ORIG, Z_AX}
dZMin = min( dZMin, dCurrZ) ; // più lontana al paino { ORIG, Z_AX}
}
vMapGrpZLoc.emplace_back( make_pair( i, make_pair( dZMax, dZMin))) ;
}
// ordino
sort( vMapGrpZLoc.begin(), vMapGrpZLoc.end(), []( const INTDBLDBL& GrpA, const INTDBLDBL& GrpB) {
// Se ZMax coincidenti, viene prima quello con ZMin superiore
if ( abs( GrpA.second.first - GrpB.second.first) < 10. * EPS_SMALL)
return ( GrpA.second.second > GrpB.second.second) ;
// Se differenti, viene prima quello con ZMax superiore
return ( GrpA.second > GrpB.second) ;
}) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::OrderByZChunk( SFRGEODBINFOVECTOR& vInfoSfrGeomDB, int nTempId, const ISurfFlatRegion* pSfrSgro) const
{
// definisco un Frame intrinseco alla regione di sgrossatura
Frame3d frXY ;
Point3d ptCenter ; pSfrSgro->GetCentroid( ptCenter) ;
if ( ! frXY.Set( ptCenter, pSfrSgro->GetNormVersor()))
return false ;
// definisco una matrice di Chunk associati ai vari piani
STEPDATAMATRIX vvChunksStep ;
for ( int i = 0 ; i < int( vInfoSfrGeomDB.size()) ; ++ i) {
// recupero la superficie piana di lavoro [sempre valida] e la porto in locale
PtrOwner<ISurfFlatRegion> pSfr( Release( vInfoSfrGeomDB[i].pSfr)) ;
if ( IsNull( pSfr) || ! pSfr->IsValid() || ! pSfr->ToLoc( frXY))
return false ;
// recupero la superficie limite corrente e la porto in locale
PtrOwner<ISurfFlatRegion> pSfrLimit( nullptr) ;
if ( ! IsNull( vInfoSfrGeomDB[i].pSfrLimit) && vInfoSfrGeomDB[i].pSfrLimit->IsValid()) {
pSfrLimit.Set( Release( vInfoSfrGeomDB[i].pSfrLimit)) ;
pSfrLimit->ToLoc( frXY) ;
}
// recupero la superficie rimossa corrente e la porto in locale
PtrOwner<ISurfFlatRegion> pSfrRemoved( nullptr) ;
if ( ! IsNull( vInfoSfrGeomDB[i].pSfrRemoved) && vInfoSfrGeomDB[i].pSfrRemoved->IsValid()) {
pSfrRemoved.Set( Release( vInfoSfrGeomDB[i].pSfrRemoved)) ;
pSfrRemoved->ToLoc( frXY) ;
}
// scorro i Chunks della regione piana di lavoro
for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) {
// recupero il Chunk corrente
PtrOwner<ISurfFlatRegion> pSfrChunk( pSfr->CloneChunk( nC)) ;
if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid())
return false ;
// trasferisco i parametri e le proprietà della regione al Chunk corrente
pSfrChunk->SetTempProp( pSfr->GetTempProp( 0), 0) ;
pSfrChunk->SetTempProp( pSfr->GetTempProp( 1), 1) ;
pSfrChunk->SetTempParam( pSfr->GetTempParam( 0), 0) ;
pSfrChunk->SetTempParam( pSfr->GetTempParam( 1), 1) ;
// determino il rispettivo Chunk della regione limite
PtrOwner<ISurfFlatRegion> pSfrRemovedChunk( nullptr) ;
if ( ! IsNull( pSfrRemoved) && pSfrRemoved->IsValid()) {
if ( pSfrRemoved->GetChunkCount() == 1)
pSfrRemovedChunk.Set( CloneSurfFlatRegion( pSfrRemoved)) ; // anche pSfr ha 1 Chunk ( ???)
else {
PtrOwner<ISurfFlatRegion> pSfrChunkCL( CloneSurfFlatRegion( pSfrChunk)) ;
if ( IsNull( pSfrChunkCL) || ! pSfrChunkCL->IsValid())
return false ;
for ( int nCC = 0 ; nCC < pSfrRemoved->GetChunkCount() ; ++ nCC) {
PtrOwner<ISurfFlatRegion> pSfrB( pSfrRemoved->CloneChunk( nCC)) ;
if ( IsNull( pSfrB) || ! pSfrB->IsValid())
return false ;
if ( ! pSfrB->Intersect( *pSfrChunkCL)) {
// provo estendendo leggermente la regione
pSfrB->Offset( 25. * EPS_SMALL, ICurve::OFF_FILLET) ;
pSfrB->Intersect( *pSfrChunkCL) ;
}
if ( pSfrB->IsValid() && pSfrB->GetChunkCount() > 0) {
pSfrRemovedChunk.Set( pSfrRemoved->CloneChunk( nCC)) ;
break ;
}
}
}
}
// memorizzo le superfici
if ( nC == 0)
vvChunksStep.resize( vvChunksStep.size() + 1) ;
vvChunksStep.back().resize( vvChunksStep.back().size() + 1) ;
vvChunksStep.back().back().bIsSubStep = vInfoSfrGeomDB[i].bSubStep ;
vvChunksStep.back().back().dDepth = vInfoSfrGeomDB[i].dDepth ;
vvChunksStep.back().back().dRelativeDepth = vInfoSfrGeomDB[i].dRelativeDepth ;
vvChunksStep.back().back().dZLocCoeffFeed = vInfoSfrGeomDB[i].dZLocCoefFeed ;
vvChunksStep.back().back().pSfrChunk.Set( Release( pSfrChunk)) ;
vvChunksStep.back().back().pSfrLimit.Set( CloneSurfFlatRegion( pSfrLimit)) ;
vvChunksStep.back().back().pSfrRemoved.Set( Release( pSfrRemovedChunk)) ;
}
}
// definisco la mappa per l'ordine dei gruppi indipendenti di Chunks
STEPDATAMATRIX vvIndepChunkGroup ;
INTDBLDBLVECTOR vMapGrpZLoc ;
if ( ! OrderZChunkSteps( vvChunksStep, vvIndepChunkGroup, vMapGrpZLoc))
return false ;
#if ENABLE_DEBUG_ORDER_ZCHUNK
int nGrp = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ;
for ( int i = 0 ; i < int( vMapGrpZLoc.size()) ; ++ i) {
Color myCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, .5) ;
int nLay = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrp, GLOB_FRM) ;
for ( int j = 0 ; j < int( vvIndepChunkGroup[vMapGrpZLoc[i].first].size()) ; ++ j) {
int a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, CloneSurfFlatRegion( vvIndepChunkGroup[vMapGrpZLoc[i].first][j].pSfrChunk)) ;
m_pGeomDB->SetMaterial( a, myCol) ;
m_pGeomDB->SetName( a, ( "(" + to_string( vMapGrpZLoc[i].first) + ", " + to_string( j) + ")").c_str()) ;
}
}
#endif
vInfoSfrGeomDB.clear() ;
// scorro i gruppi ordinati
for ( int i = 0 ; i < int( vMapGrpZLoc.size()) ; ++ i) {
// recupero l'indice del gruppo
int nGroup = vMapGrpZLoc[i].first ;
// --- inserisco gli Steps
for ( int j = int( vvIndepChunkGroup[nGroup].size()) - 1 ; j >= 0 ; -- j) {
if ( ! vvIndepChunkGroup[nGroup][j].bIsSubStep) {
vInfoSfrGeomDB.resize( vInfoSfrGeomDB.size() + 1) ;
// --- regione di sgrossatura
vvIndepChunkGroup[nGroup][j].pSfrChunk->ToGlob( frXY) ;
vInfoSfrGeomDB.back().pSfr.Set( Release( vvIndepChunkGroup[nGroup][j].pSfrChunk)) ;
// --- regione limite
vInfoSfrGeomDB.back().pSfrLimit.Set( nullptr) ;
if ( ! IsNull( vvIndepChunkGroup[nGroup][j].pSfrLimit) && vvIndepChunkGroup[nGroup][j].pSfrLimit->IsValid()) {
vvIndepChunkGroup[nGroup][j].pSfrLimit->ToGlob( frXY) ;
vInfoSfrGeomDB.back().pSfrLimit.Set( Release( vvIndepChunkGroup[nGroup][j].pSfrLimit)) ;
}
// --- regione rimossa
vInfoSfrGeomDB.back().pSfrRemoved.Set( nullptr) ;
if ( ! IsNull( vvIndepChunkGroup[nGroup][j].pSfrRemoved) && vvIndepChunkGroup[nGroup][j].pSfrRemoved->IsValid()) {
vvIndepChunkGroup[nGroup][j].pSfrRemoved->ToGlob( frXY) ;
vInfoSfrGeomDB.back().pSfrRemoved.Set( Release( vvIndepChunkGroup[nGroup][j].pSfrRemoved)) ;
}
// --- Flag per Step base
vInfoSfrGeomDB.back().bSubStep = vvIndepChunkGroup[nGroup][j].bIsSubStep ;
// --- Depth
vInfoSfrGeomDB.back().dDepth = vvIndepChunkGroup[nGroup][j].dDepth ;
// --- Depth relativa
vInfoSfrGeomDB.back().dRelativeDepth = vvIndepChunkGroup[nGroup][j].dRelativeDepth ;
// --- Coefficiente di riduzione della Feed in locale
vInfoSfrGeomDB.back().dZLocCoefFeed = vvIndepChunkGroup[nGroup][j].dZLocCoeffFeed ;
}
}
// --- inserisco i SubSteps ---
INTVECTOR vSubStepInd ;
for ( int j = int( vvIndepChunkGroup[nGroup].size()) - 1 ; j >= 0 ; -- j) {
bool bNewGap = ( ! vSubStepInd.empty() &&
vvIndepChunkGroup[nGroup][j].dDepth > vvIndepChunkGroup[nGroup][vSubStepInd.back()].dDepth) ;
if ( vvIndepChunkGroup[nGroup][j].bIsSubStep && ! bNewGap)
vSubStepInd.emplace_back( j) ;
if ( ! vvIndepChunkGroup[nGroup][j].bIsSubStep || bNewGap || j == 0) {
for ( int k = int( vSubStepInd.size()) - 1 ; k >= 0 ; -- k) {
// recupero l'indice del SubStep
int nInd = vSubStepInd[k] ;
vInfoSfrGeomDB.resize( vInfoSfrGeomDB.size() + 1) ;
// --- regione di sgrossatura
vvIndepChunkGroup[nGroup][nInd].pSfrChunk->ToGlob( frXY) ;
vInfoSfrGeomDB.back().pSfr.Set( Release( vvIndepChunkGroup[nGroup][nInd].pSfrChunk)) ;
// --- regione limite
vInfoSfrGeomDB.back().pSfrLimit.Set( nullptr) ;
if ( ! IsNull( vvIndepChunkGroup[nGroup][nInd].pSfrLimit) && vvIndepChunkGroup[nGroup][nInd].pSfrLimit->IsValid()) {
vvIndepChunkGroup[nGroup][nInd].pSfrLimit->ToGlob( frXY) ;
vInfoSfrGeomDB.back().pSfrLimit.Set( Release( vvIndepChunkGroup[nGroup][nInd].pSfrLimit)) ;
}
// --- regione rimossa
vInfoSfrGeomDB.back().pSfrRemoved.Set( nullptr) ;
if ( ! IsNull( vvIndepChunkGroup[nGroup][nInd].pSfrRemoved) && vvIndepChunkGroup[nGroup][nInd].pSfrRemoved->IsValid()) {
vvIndepChunkGroup[nGroup][nInd].pSfrRemoved->ToGlob( frXY) ;
vInfoSfrGeomDB.back().pSfrRemoved.Set( Release( vvIndepChunkGroup[nGroup][nInd].pSfrRemoved)) ;
}
// --- Flag per Step base
vInfoSfrGeomDB.back().bSubStep = vvIndepChunkGroup[nGroup][nInd].bIsSubStep ;
// --- Depth
vInfoSfrGeomDB.back().dDepth = vvIndepChunkGroup[nGroup][nInd].dDepth ;
// --- Depth relativa
vInfoSfrGeomDB.back().dRelativeDepth = vvIndepChunkGroup[nGroup][nInd].dRelativeDepth ;
// --- Coefficiente di riduzione della Feed in locale
vInfoSfrGeomDB.back().dZLocCoefFeed = vvIndepChunkGroup[nGroup][nInd].dZLocCoeffFeed ;
}
vSubStepInd.clear() ;
if ( bNewGap && vvIndepChunkGroup[nGroup][j].bIsSubStep)
vSubStepInd = { j} ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::AddRoughing( const INTINTVECTOR& vPocket, const Vector3d& vtTool, double dDepth, double dStep,
double dSubStep, bool bSplitArcs)
{
// controllo dei parametri
if ( vPocket.empty())
return true ;
// calcolo i percorsi di svuotatura per ogni Step/SubStep
STEPINFOSRVECTOR vStepInfo ;
if ( ! CalcPaths( vPocket, vStepInfo))
return false ;
#if ENABLE_DEBUG_FEEDS
nGrpDebugFeed = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ;
nLayDebugFeed = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrpDebugFeed, GLOB_FRM) ;
m_pGeomDB->SetName( nGrpDebugFeed, "Feed") ;
#endif
// recupero distanze di sicurezza
double dSafeZ = GetSafeZ() ;
// lunghezza di approccio/retrazione
double dAppr = m_Params.m_dStartPos ;
// elevazione sopra al punto attuale
double dCurrElev ;
// punto finale del percorso precedente al corrente
Point3d ptEnd = P_INVALID ;
// recupero parametro di Feed minima
double dMinFeed = GetFeed() / FEED_MAX_REDUCE ;
if ( GetValInNotes( m_Params.m_sUserNotes, UN_MINFEED, dMinFeed))
dMinFeed = Clamp( dMinFeed, GetFeed() / FEED_MAX_REDUCE, GetFeed()) ;
// scorro il vettore dei piani di pocketing
for ( int i = 0 ; i < ssize( vStepInfo) ; ++ i) {
// riferimento alle informazioni relative allo step i-esimo
StepInfoSR& currStep = vStepInfo[i] ;
// scorro i percorsi calcolati per il piano di pocketing i-esimo
for ( int j = 0 ; j < ssize( currStep.vPaths) ; ++ j) {
// riferimento alle informazioni relative al percorso j-esimo del piano di pocketing i-esimo
PathInfoSR& currPath = currStep.vPaths[j] ;
// ciclo sulle curve elementari del percorso attuale
int nMaxInd = currPath.pCrvPath->GetCurveCount() - 1 ;
for ( int k = 0 ; k <= nMaxInd ; ++ k) {
// curva corrente
const ICurve* pCrvC = currPath.pCrvPath->GetCurve( k) ;
// copio la curva
PtrOwner<ICurve> pCurve( pCrvC->Clone()) ;
if ( IsNull( pCurve))
return false ;
// coefficiente feed ( riduzione di feed per sezione di taglio superiore al previsto )
double dTempParam ; currPath.pCrvPath->GetCurveTempParam( k, dTempParam) ;
double dCoeffFeed = min( 1., ( dTempParam > EPS_SMALL ? dTempParam /= 1000 : 1) * currStep.dZlocCoeffFeed) ;
// se prima entità
if ( k == 0) {
// dati inizio entità
Point3d ptStart ; pCurve->GetStartPoint( ptStart) ;
Vector3d vtStart ; pCurve->GetStartDir( vtStart) ;
// flag approccio libero in aria
if ( currPath.bOutStart)
dCoeffFeed = ( dTempParam > EPS_SMALL ? dTempParam : 1) ;
// calcolo ptP1 per LeadIn iniziale
Point3d ptP1 ;
if ( ! CalcLeadInStart( ptStart, vtTool, currPath.pCvrRet, ptP1)) {
m_pMchMgr->SetLastError( 3013, "Error in SurfRoughing : LeadIn not computable") ;
return false ;
}
// determino l'elevazione sull'inizio dell'attacco della prima curva globale
bool bAbsFirst = ( i == 0 && j == 0) ;
if ( bAbsFirst)
dCurrElev = - currStep.dDepth ;
dCurrElev -= ( ptP1 - ptStart) * vtTool ;
// se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco
if ( GetLeadInType() != POCKET_LI_NONE) {
double dMyLIO_ELEV_TOL = min( LIO_ELEV_TOL, dSafeZ) ;
// se prima entità in assoluto
if ( bAbsFirst) {
ptP1 += vtTool * ( dCurrElev + dMyLIO_ELEV_TOL) ;
dCurrElev = - min( LIO_ELEV_TOL, dSafeZ) ;
}
// altrimenti...
else if ( ! currPath.bOutStart)
ptP1 += vtTool * ( - currStep.dRelativeDepth + dMyLIO_ELEV_TOL) ;
}
// approccio al punto iniziale
double dMySafeZ = ( bAbsFirst ? dSafeZ : 0.) ;
Point3d ptMyPos ; GetCurrPos( ptMyPos) ;
double dMyElev = ( bAbsFirst ? dCurrElev : ( ptMyPos - ptP1) * vtTool) ;
double dMyAppr = ( bAbsFirst ? dAppr : 0.) ;
if ( ! AddApproach( ptP1, vtTool, dMySafeZ, dMyElev, dMyAppr, currPath.bOutStart, bAbsFirst)) {
m_pMchMgr->SetLastError( 3011, "Error in SurfRoughing : Approach not computable") ;
return false ;
}
// aggiungo attacco
SetFeed( GetStartFeed()) ;
bool bNoneForced = ( currPath.bOutStart || currPath.bSingleCrv ||
( currStep.nSubType == SURFROU_SUB_ZIGZAG && ! currPath.bIsZigZagOneWayBorder) ||
( currStep.nSubType == SURFROU_SUB_ONEWAY && ! currPath.bIsZigZagOneWayBorder)) ;
if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtTool, currStep.pSfrPock,
( ( currStep.nSubType == SURFROU_SUB_SPIRALIN || currStep.nSubType == SURFROU_SUB_SPIRALOUT)) ? Get( currPath.pCvrRet) : nullptr,
( currStep.nSubType == SURFROU_SUB_SPIRALOUT) ? currStep.bInverted : ! currStep.bInverted,
bSplitArcs, bNoneForced, false)) {
m_pMchMgr->SetLastError( 3013, "Error in SurfRoughing : 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( Clamp( dCoeffFeed * GetFeed(), dMinFeed, GetFeed())) ;
#if ENABLE_DEBUG_FEEDS
DrawFeed( pCurve->Clone(), dCoeffFeed * GetFeed(), nLayDebugFeed) ;
#endif
if ( AddLinearMove( ptP3, bSplitArcs) == GDB_ID_NULL)
return false ;
}
else if ( pCurve->GetType() == CRV_ARC) {
ICurveArc* pArc = GetCurveArc( pCurve) ;
SetFeed( Clamp( dCoeffFeed * GetFeed(), dMinFeed, GetFeed())) ;
#if ENABLE_DEBUG_FEEDS
DrawFeed( pCurve->Clone(), dCoeffFeed * GetFeed(), nLayDebugFeed) ;
#endif
SetFeed( dCoeffFeed * GetFeed()) ;
if ( AddCurveMove( pArc, bSplitArcs) == GDB_ID_NULL)
return false ;
}
// se ultima entità
if ( k == nMaxInd) {
// dati fine entità
pCurve->GetEndPoint( ptEnd) ;
Vector3d vtEnd ; pCurve->GetEndDir( vtEnd) ;
// se sono l'ultima entità globale del percorso
if ( i == ssize( vStepInfo) - 1 && j == ssize( currStep.vPaths) - 1) {
// aggiungo LeadOut
Point3d ptP1 ;
SetFeed( GetEndFeed()) ;
if ( ! AddLeadOut( ptEnd, vtEnd, vtTool,
( ( currStep.nSubType == SURFROU_SUB_SPIRALIN || currStep.nSubType == SURFROU_SUB_SPIRALOUT)) ? Get( currPath.pCvrRet) : nullptr,
bSplitArcs, false, ptP1)) {
m_pMchMgr->SetLastError( 3014, "Error in SurfRoughing : LeadOut not computable") ;
return false ;
}
// aggiungo retroazione finale
if ( ! AddRetract( ptP1, vtTool, dSafeZ, - currStep.dDepth, dAppr)) {
m_pMchMgr->SetLastError( 3015, "Error in SurfRoughing : Retract not computable") ;
return false ;
}
}
// se ho un percorso successivo
else {
// definisco e creo il link
PtrOwner<ICurveComposite> pCrvLink( CreateCurveComposite()) ;
if ( IsNull( pCrvLink) ||
! GetLinkFromPaths( vStepInfo, i, j, ptEnd, vtTool, dSafeZ, 0., dCurrElev, pCrvLink)) {
m_pMchMgr->SetLastError( 3034, "Error in SurfRoughing : Linking paths failed") ;
return false ;
}
// imposto EndFeed e aggiungo il Link
SetFeed( GetEndFeed()) ;
#if ENABLE_DEBUG_FEEDS
DrawFeed( pCrvLink->Clone(), GetEndFeed(), nLayDebugFeed) ;
#endif
AddCurveMove( pCrvLink, bSplitArcs) ;
}
}
}
}
}
// aggiorno per sicurezza la ProgressBar nel caso di Step vuoti
ExeProcessEvents( 100, 0) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::AddApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev,
double dAppr, bool bOutStart, bool bAbsFirst)
{
if ( bAbsFirst)
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 ( bAbsFirst && 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 ( bAbsFirst && 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) ;
bool bStartFeed = ( bOutStart || m_TParams.m_nType == TT_MILL_NOTIP) ;
SetFeed( bStartFeed ? GetStartFeed() : GetTipFeed()) ;
if ( AddLinearMove( ptP) == GDB_ID_NULL)
return false ;
}
else {
// affondo diretto al punto iniziale
SetFlag( 0) ;
if ( bAbsFirst && AddRapidStart( ptP) == GDB_ID_NULL)
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::AddLinkApproach(const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr, bool bOutMove)
{
// 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( bOutMove ? GetStartFeed() : 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
SurfRoughing::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
SurfRoughing::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 ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::CalcLeadInStart( const Point3d& ptStart, const Vector3d& vtTool,
const ICurveComposite* pRCrv, Point3d& ptP1) const
{
// Assegno tipo e parametri
int nType = GetLeadInType() ;
if ( nType == SURFROU_LI_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0))
nType = SURFROU_LI_NONE ;
// Calcolo punto iniziale
switch ( nType) {
case SURFROU_LI_NONE :
case SURFROU_LI_ZIGZAG :
case SURFROU_LI_HELIX :
ptP1 = ptStart ;
return true ;
case SURFROU_LI_GLIDE :
{
double dLen, dU ;
if ( ! pRCrv->GetLength( dLen) || ! pRCrv->GetParamAtLength( dLen - m_Params.m_dLiTang, dU) ||
! pRCrv->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP1)) {
if ( ! pRCrv->GetStartPoint( ptP1))
return false ;
}
ptP1 += vtTool * ( vtTool * ( ptStart - ptP1)) ;
return true ;
}
default :
return false ;
}
}
//----------------------------------------------------------------------------
bool
SurfRoughing::AddLeadIn( const Point3d& ptP1, const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtN,
const ISurfFlatRegion* pSfr, const ICurveComposite* pRCrv, bool bAtLeft, bool bSplitArcs,
bool bNoneForced, bool bSkipControl)
{
// Assegno il tipo
int nType = GetLeadInType() ;
if ( bNoneForced ||
AreSamePointEpsilon( ptP1, ptStart, 10 * EPS_SMALL) ||
( nType == SURFROU_LI_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0)))
nType = SURFROU_LI_NONE ;
// Se elica e fattibile lo creo
if ( nType == SURFROU_LI_HELIX) {
// vettore dal punto al centro elica
Vector3d vtCen = vtStart ;
vtCen.Rotate( vtN, 0, ( bAtLeft ? 1 : - 1)) ;
// dati dell'elica
double dRad = min( 0.5 * min( m_Params.m_dLiTang, m_TParams.m_dDiam), m_dMaxHelixRad) ;
Point3d ptCen = ptP1 + vtCen * dRad ;
double dDeltaN = ( ptStart - ptP1) * vtN ;
double dAngCen = ceil( - dDeltaN / ( m_Params.m_dLiElev + 20 * EPS_SMALL)) * ( bAtLeft ? ANG_FULL : - ANG_FULL) ;
// verifico se fattibile
if ( bSkipControl || VerifyLeadInHelix( pSfr, ptStart, ptCen, dRad)) {
// creo l'elica
PtrOwner<ICurveArc> pArc( CreateCurveArc()) ;
if ( IsNull( pArc) || ! pArc->Set( ptCen, vtN, dRad, - vtCen, dAngCen, dDeltaN))
return false ;
// dovendo creare l'elica, sono nel materiale, quindi regolo la Feed
Vector3d vtTanHelix ; pArc->GetStartDir( vtTanHelix) ;
SetFeed( GetRightStartFeed( vtTanHelix, vtN)) ;
#if ENABLE_DEBUG_FEEDS
DrawFeed( pArc->Clone(), GetRightStartFeed( vtTanHelix, vtN), nLayDebugFeed) ;
#endif
// emetto l'elica (con eventuale spezzatura)
return ( AddCurveMove( pArc, bSplitArcs, MCH_CL_LEADIN) != GDB_ID_NULL) ;
}
// altrimenti zigzag
else
nType = SURFROU_LI_ZIGZAG ;
}
// Se zigzag e fattibile lo creo
if ( nType == SURFROU_LI_ZIGZAG) {
// dati dello zigzag
double dDeltaN = ( ptStart - ptP1) * vtN ;
int nStep = int( ceil( - dDeltaN / ( m_Params.m_dLiElev + 20 * EPS_SMALL))) ;
double dStep = - dDeltaN / nStep ;
Point3d ptPa = ptP1 + vtStart * 0.5 * min( m_Params.m_dLiTang, m_TParams.m_dDiam) ;
Point3d ptPb = ptP1 - vtStart * 0.5 * min( m_Params.m_dLiTang, m_TParams.m_dDiam) ;
Vector3d vtTanZigZag = ( ptPa - vtN * 0.25 * dStep) - ptP1 ;
SetFeed( GetRightStartFeed( vtTanZigZag, vtN)) ;
// verifico se fattibile
if ( bSkipControl || VerifyLeadInZigZag( pSfr, ptStart, ptPa, ptPb)) {
for ( int i = 1 ; i <= nStep ; ++ i) {
#if ENABLE_DEBUG_FEEDS
PtrOwner<ICurveLine> pLine( CreateCurveLine()) ;
Point3d ptCurr ; GetCurrPos( ptCurr) ; pLine->Set( ptCurr, ptPa - vtN * ( i - 0.75) * dStep) ;
DrawFeed( pLine->Clone(), GetRightStartFeed( vtTanZigZag, vtN), nLayDebugFeed) ;
#endif
if ( AddLinearMove( ptPa - vtN * ( i - 0.75) * dStep, bSplitArcs, MCH_CL_LEADIN) == GDB_ID_NULL)
return false ;
#if ENABLE_DEBUG_FEEDS
GetCurrPos( ptCurr) ; pLine->Set( ptCurr, ptPb - vtN * ( i - 0.25) * dStep) ;
DrawFeed( pLine->Clone(), GetRightStartFeed( vtTanZigZag, vtN), nLayDebugFeed) ;
#endif
if ( AddLinearMove( ptPb - vtN * ( i - 0.25) * dStep, bSplitArcs, MCH_CL_LEADIN) == GDB_ID_NULL)
return false ;
}
#if ENABLE_DEBUG_FEEDS
PtrOwner<ICurveLine> pLine( CreateCurveLine()) ;
Point3d ptCurr ; GetCurrPos( ptCurr) ; pLine->Set( ptCurr, ptStart) ;
DrawFeed( pLine->Clone(), GetRightStartFeed( vtTanZigZag, vtN), nLayDebugFeed) ;
#endif
return ( AddLinearMove( ptStart, bSplitArcs, MCH_CL_LEADIN) != GDB_ID_NULL) ;
}
// altrimenti diretto
else {
nType = SURFROU_LI_NONE ;
if ( m_TParams.m_nType == TT_MILL_NOTIP)
return false ;
}
}
// Se a scivolo e fattibile
if ( nType == SURFROU_LI_GLIDE) {
if ( pRCrv != nullptr) {
// recupero la parte richiesta della curva di ritorno
PtrOwner<ICurveComposite> pCrv ;
double dLen, dU ;
if ( pRCrv->GetLength( dLen) && pRCrv->GetParamAtLength( dLen - m_Params.m_dLiTang, dU)) {
double dParS, dParE ;
pRCrv->GetDomain( dParS, dParE) ;
if ( ! pCrv.Set( ConvertCurveToComposite( pRCrv->CopyParamRange( dU, dParE))))
return false ;
}
else {
if ( ! pCrv.Set( pRCrv->Clone()))
return false ;
}
pCrv->SetExtrusion( vtN) ;
// la porto alla giusta quota
Point3d ptFin ; pCrv->GetEndPoint( ptFin) ;
Vector3d vtMove = ptStart - ptFin ;
pCrv->Translate( vtMove) ;
// assegno la corretta pendenza
double dNini = ( ptP1 - ORIG) * vtN ;
double dNfin = ( ptStart - ORIG) * vtN ;
AdjustCurveSlope( pCrv, dNini, dNfin) ;
// assegno le Feed
Point3d ptS ; pCrv->GetStartPoint( ptS) ;
Point3d ptE ; pCrv->GetEndPoint( ptE) ;
Vector3d vtFeedMove = ptE - ptS ;
SetFeed( GetRightStartFeed( vtFeedMove, vtN)) ;
#if ENABLE_DEBUG_FEEDS
DrawFeed( pCrv->Clone(), GetRightStartFeed( vtFeedMove, vtN), nLayDebugFeed) ;
#endif
// emetto (con eventuale spezzatura)
return ( AddCurveMove( pCrv, bSplitArcs, MCH_CL_LEADIN) != GDB_ID_NULL) ;
}
// altrimenti diretto
else
nType = SURFROU_LI_NONE ;
}
// Se diretto
if ( nType == SURFROU_LI_NONE) {
Point3d ptCurr = ptP1 ;
GetCurrPos( ptCurr) ;
if ( ! AreSamePointApprox( ptCurr, ptStart)) {
Vector3d vtMove = ptStart - ptCurr ; vtMove.Normalize() ;
double dElev = 0. ;
bool bInMaterial = true ;
if ( GetElevation( m_nPhase, ptCurr, ptStart, vtN, GetRadiusForStartEndElevation(), m_TParams.m_dLen, vtN, dElev) && dElev < 10. * EPS_SMALL)
bInMaterial = false ;
// Feed di Testa
SetFeed( bInMaterial ? GetTipFeed() : GetStartFeed()) ;
#if ENABLE_DEBUG_FEEDS
PtrOwner<ICurveLine> pLine( CreateCurveLine()) ; pLine->Set( ptCurr, ptStart) ;
DrawFeed( pLine->Clone(), bInMaterial ? GetTipFeed() : GetStartFeed(), nLayDebugFeed) ;
#endif
if ( AddLinearMove( ptStart, bSplitArcs, MCH_CL_LEADIN) == GDB_ID_NULL)
return false ;
}
return true ;
}
// Altrimenti errore
return false ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::AddLeadOut( const Point3d& ptEnd, const Vector3d& vtEnd, const Vector3d& vtN,
const ICurveComposite* pRCrv, bool bSplitArcs, bool bNoneForced,
Point3d& ptP1)
{
// assegno i parametri
int nType = GetLeadOutType() ;
if ( bNoneForced ||
( nType == SURFROU_LO_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0)))
nType = SURFROU_LO_NONE ;
// eseguo a seconda del tipo
switch ( nType) {
case SURFROU_LO_NONE :
{
// nessuna uscita
ptP1 = ptEnd ;
return true ;
}
case SURFROU_LO_GLIDE :
{
// recupero la parte richiesta della curva di ritorno
PtrOwner<ICurveComposite> pCrv ;
double dU ;
if ( pRCrv->GetParamAtLength( m_Params.m_dLoTang, dU)) {
if ( ! pCrv.Set( ConvertCurveToComposite( pRCrv->CopyParamRange( 0, dU))))
return false ;
}
else {
if ( ! pCrv.Set( pRCrv->Clone()))
return false ;
}
// la porto alla giusta quota
Point3d ptIni ; pCrv->GetStartPoint( ptIni) ;
Vector3d vtMove = ptEnd - ptIni ;
pCrv->Translate( vtMove) ;
Point3d ptFin ; pCrv->GetEndPoint( ptFin) ;
ptFin += vtN * 1.0 ;
pCrv->ModifyEnd( ptFin) ;
// emetto (con eventuale spezzatura)
AddCurveMove( pCrv, bSplitArcs, MCH_CL_LEADOUT) ;
// determino elevazione su fine uscita
ptP1 = ptFin ;
return true ;
}
default :
return false ;
}
}
//----------------------------------------------------------------------------
double
SurfRoughing::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
SurfRoughing::GetRightStartFeed( 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 GetStartFeed() ;
// Altrimenti non si deve superare la massima velocità di punta prevista
return min( GetStartFeed(), GetTipFeed() / abs( dCosMove)) ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::ResetCurveAllTempProp( ICurve* pCurve) const
{
// controllo validità della curva
if ( pCurve == nullptr)
return false ;
// metto a 0 le tmpProps della curva
pCurve->SetTempProp( 0, 0) ;
pCurve->SetTempProp( 0, 1) ;
// ricavo la composita associata
ICurveComposite* pCC = GetCurveComposite( pCurve) ;
if ( pCC != nullptr)
for ( int i = 0 ; i < pCC->GetCurveCount() ; ++ i) {
// per ogni sottcurva metto a 0 le temProps
pCC->SetCurveTempProp( i, 0, 0) ;
pCC->SetCurveTempProp( i, 0, 1) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::SimplifyCurve( ICurveComposite* pCompo, const ICRVCOMPOPOVECTOR& vCrvCheck, const Frame3d& frLocXY) const
{
// controllo dei parametri
if ( pCompo == nullptr || ! pCompo->IsValid())
return false ;
// eseguo le modifiche su una copia della curva originale in locale al frameXY
PtrOwner<ICurveComposite> pCompoLoc( CloneCurveComposite( pCompo)) ;
if ( IsNull( pCompoLoc))
return false ;
pCompoLoc->ToLoc( frLocXY) ;
// ricavo il punto iniziale e finale
Point3d ptStart ; pCompoLoc->GetStartPoint( ptStart) ;
Point3d ptEnd ; pCompoLoc->GetEndPoint( ptEnd) ;
// merge per uniformità
bool bOk = pCompoLoc->MergeCurves( 200. * EPS_SMALL, 200. * EPS_ANG_SMALL, false) ;
// rimozione Spikes o Curve Z
bOk = bOk && pCompoLoc->RemoveSmallDefects( 150. * EPS_SMALL, 2. * ANG_TOL_STD_DEG, true) ;
// interpolazione mediante linee ed archi
PolyArc PA ;
bOk = bOk && pCompoLoc->ApproxWithArcsEx( 50. * EPS_SMALL, ANG_TOL_STD_DEG, LIN_FEA_STD, PA) &&
pCompoLoc->Clear() && pCompoLoc->FromPolyArc( PA) ;
// controllo aggiuntivo sui punti iniziali e finali che siano gli stessi
Point3d ptNewStart, ptNewEnd ;
bOk = bOk && pCompoLoc->GetStartPoint( ptNewStart) && pCompoLoc->GetEndPoint( ptNewEnd) &&
AreSamePointApprox( ptNewStart, ptStart) && AreSamePointApprox( ptNewEnd, ptEnd) ;
// controllo che non si siano create auto-intersezioni
SelfIntersCurve SIC( *pCompoLoc) ;
bOk = bOk && ( SIC.GetCrossIntersCount() == 0) ;
// controllo che non si siano create intersezioni con le altre curve in punti interni
for ( int i = 0 ; i < ssize( vCrvCheck) && bOk ; ++ i) {
PtrOwner<ICurveComposite> pCrvCheckLocXY( CloneCurveComposite( vCrvCheck[i])) ;
bOk = bOk && ( ! IsNull( pCrvCheckLocXY)) && pCrvCheckLocXY->IsValid() ;
if ( bOk) {
pCrvCheckLocXY->ToLoc( frLocXY) ;
IntersCurveCurve ICC( *pCrvCheckLocXY, *pCompoLoc) ;
for ( int j = 0 ; j < ICC.GetIntersCount() && bOk ; ++ j) {
IntCrvCrvInfo aInfo ;
bOk = ICC.GetIntCrvCrvInfo( j, aInfo) ;
bOk = bOk && ( AreSamePointApprox( ptStart, aInfo.IciA[0].ptI) ||
AreSamePointApprox( ptEnd, aInfo.IciA[0].ptI)) ;
}
}
}
// se tutto bene, sostiuisco la curva originale con la modificata
if ( bOk) {
pCompoLoc->ToGlob( frLocXY) ;
pCompo->CopyFrom( pCompoLoc) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::SimplyfySfr( ISurfFlatRegion* pSfr) const
{
// controllo dei parametri
if ( pSfr == nullptr || ! pSfr->IsValid())
return false ;
// creo una superficie vuota; inserirò i Loop di pSfr semplificati
PtrOwner<ISurfFlatRegion> pSfrSimple( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrSimple))
return false ;
ICRVCOMPOPOVECTOR vCrvEmpty ;
// recupero il frame localeXY della regione piana
Frame3d frLoc ;
Point3d ptC ; pSfr->GetCentroid( ptC) ;
frLoc.Set( ptC, pSfr->GetNormVersor()) ;
// scorro tutti i loops di tutte le parti
for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) {
for ( int nL = 0 ; nL < pSfr->GetLoopCount( nC) ; ++ nL) {
// recupero la curva di Loop e la semplifico
PtrOwner<ICurveComposite> pCompoLoop( ConvertCurveToComposite( pSfr->GetLoop( nC, nL))) ;
if ( IsNull( pCompoLoop) || ! SimplifyCurve( pCompoLoop, vCrvEmpty, frLoc))
return false ;
// inserisco le curve nella nuova regione (il primo loop di ogni parte è esterno)
if ( nL == 0) {
if ( ! pSfrSimple->AddExtLoop( Release( pCompoLoop)))
return false ;
}
else {
if ( ! pSfrSimple->AddIntLoop( Release( pCompoLoop)))
return false ;
}
}
}
// se superficie semplificata valida, la sostituisco
if ( pSfrSimple->IsValid())
return ( pSfr->CopyFrom( pSfrSimple)) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::RemoveChunksUnderTolerance( ISurfFlatRegion* pSfr, double dTol,
ISurfFlatRegion* pSfrLimit, ISurfFlatRegion* pSfrToUpdate) const
{
/*
quando si lavorano dei SubSteps, può capitare che la superfice da rimuovere sia molto snella;
questo succede quando lo step eseguito in precedenza rimuove gran parte del materiale utile per il
piano di lavoro attuale. Si creano dunque delle regioni formate da più Chunk molto sottili che
creano sia problemi di distinzione dei lati aperti che problemi poi ad essere svuotate ( si pensi
all'estensione dei lati aperti e al loro raccordo con i chiusi, oltre al fatto che i chunk in
questa operazione potrebbero mergiarsi tra loro creando ambiguità.
Data la superficie *pSfr, vengono rimossi tutti i Chunks che si annullano mediante il contro-Offset
definito dalla tolleranza
NB. Il Contro-Offset è possibile farlo solo sul Loop esterno, non c'è bisogno di
fare conti aggiuntivi per le isole interne
*/
// controllo dei parametri
if ( pSfr == nullptr || ! pSfr->IsValid())
return false ;
if ( dTol < EPS_SMALL) // se tolleranza non presente, non faccio nulla
return true ;
// se non ho superfici da non rovinare, allora non devo fare nulla (sarà tutto aperto)
if ( pSfrLimit == nullptr || ! pSfrLimit->IsValid() || pSfrLimit->GetChunkCount() == 0)
return true ;
// scorro tutti i chunk della superficie
for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) {
// verifico se l'Offset massimo del chunk è sopra alla tolleranza
double dMaxOffs = EPS_SMALL ;
pSfr->GetChunkMaxOffset( nC, dMaxOffs) ;
// rimuovo il Chunk c-esimo se l'Offset massimo è minore della tolleranza
if ( dMaxOffs < dTol) {
// devo evitare di rimuovere le isole aperte (queste, se rimosse, lasciano delle
// punte di materiale che non vengono rimosse in quanto sempre scartate)
// piccolo Offset alla regione limite
double dOffs = m_TParams.m_dDiam / 2. + GetOffsR() + 30 * EPS_SMALL ;
PtrOwner<ISurfFlatRegion> pSfrLimitOffs( pSfrLimit->CreateOffsetSurf( dOffs, ICurve::OFF_FILLET)) ;
if ( IsNull( pSfrLimitOffs) || ! pSfrLimitOffs->IsValid())
return false ;
// se il Chunk non tocca tale regione, allora lo conservo
PtrOwner<ISurfFlatRegion> pSfrChunk( pSfr->CloneChunk( nC)) ;
if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid())
return false ;
pSfrChunk->Intersect( *pSfrLimitOffs) ;
if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid() || pSfrChunk->GetChunkCount() == 0)
continue ;
// se ho una regione da aggiornare
if ( pSfrToUpdate != nullptr && pSfrToUpdate->IsValid()) {
PtrOwner<ISurfFlatRegion> pSfrChunk( pSfr->CloneChunk( nC)) ;
if ( ! IsNull( pSfrChunk) || pSfrChunk->IsValid()) {
pSfrChunk->Offset( 50. * EPS_SMALL, ICurve::OFF_FILLET) ; // si prova...
pSfrToUpdate->Subtract( *pSfrChunk) ; // si prova...
}
}
pSfr->EraseChunk( nC) ;
-- nC ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::CloseOpenEdgesUnderTolerance( ISurfFlatRegion* pSfr, double dToler)
{
/*
Nei SubSteps capita spesso che ci siano dei lati aperti molto piccoli o delle sequenze di lati
Aperti-Chiusi alternati tutti molto corti ( es. Laurana50K).
Chiudo tutti i tratti aperti piccoli
*/
// controllo dei parametri
if ( pSfr == nullptr || ! pSfr->IsValid())
return false ;
if ( dToler < 10 * EPS_SMALL) // se tolleranza non presente, non faccio nulla
return true ;
// inizializzo la superficie da restituire
PtrOwner<ISurfFlatRegion> pSfrRegular( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrRegular))
return false ;
// recupero il frame locale XY della superficie
Frame3d frLoc ;
Point3d ptC ; pSfr->GetCentroid( ptC) ;
frLoc.Set( ptC, pSfr->GetNormVersor()) ;
// scorro tutti i chunk della superficie
for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) {
// creo una superficie di test
PtrOwner<ISurfFlatRegion> pSfrTest( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrTest))
return false ;
// scorro tutti i loop
bool bOk = true ;
for ( int nL = 0 ; bOk && nL < pSfr->GetLoopCount( nC) ; ++ nL) {
// recupero il loop come curva composita
PtrOwner<ICurveComposite> pCrvLoop( ConvertCurveToComposite( pSfr->GetLoop( nC, nL))) ;
if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid())
return false ;
// ricavo tratti di proprietà uniformi -------------
ICRVCOMPOPOVECTOR vpCrvs ;
GetHomogeneousParts( pCrvLoop, vpCrvs) ;
// memorizzo i tratti Closed
ICRVCOMPOPOVECTOR vCrvClose ;
for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) {
if ( vpCrvs[i]->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE)
vCrvClose.emplace_back( CloneCurveComposite( vpCrvs[i])) ;
}
// scorro tutti i tratti aperti e riconcateno il loop
PtrOwner<ICurveComposite> pCrvNewLoop( CreateCurveComposite()) ;
if ( IsNull( pCrvNewLoop))
return false ;
for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) {
// se tratto aperto e non coincidente con tutta la curva
if ( vpCrvs[i]->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE && int( vpCrvs.size()) != 1) {
// semplifico il loop per avere curve più uniformi
SimplifyCurve( vpCrvs[i], vCrvClose, frLoc) ;
// riporto le proprietà
vpCrvs[i]->SetTempProp( TEMP_PROP_OPEN_EDGE) ;
for ( int j = 0 ; j < vpCrvs[i]->GetCurveCount() ; ++ j)
vpCrvs[i]->SetCurveTempProp( j, TEMP_PROP_OPEN_EDGE, 0) ;
// controllo la lunghezza delle curve
double dLen = EPS_SMALL ;
vpCrvs[i]->GetLength( dLen) ;
// se più corto della tolleranza
if ( dLen < dToler) {
vpCrvs[i]->SetTempProp( TEMP_PROP_CLOSE_EDGE, 0) ;
for ( int j = 0 ; j < vpCrvs[i]->GetCurveCount() ; ++ j)
vpCrvs[i]->SetCurveTempProp( j, TEMP_PROP_CLOSE_EDGE, 0) ;
}
}
pCrvNewLoop->AddCurve( Release( vpCrvs[i])) ;
}
// inserisco i nuovi loop nella superficie regolare
if ( nL == 0)
bOk = bOk && pSfrTest->AddExtLoop( Release( pCrvNewLoop)) ;
else
bOk = bOk && pSfrTest->AddIntLoop( Release( pCrvNewLoop)) ;
}
// se il chunk è stato creato correttamente, allora lo aggiungo
if ( bOk && pSfrTest->IsValid()) {
if ( pSfrRegular->IsValid() && pSfrRegular->GetChunkCount() > 0) {
if ( ! pSfrRegular->Add( *pSfrTest)) {
PtrOwner<ISurfFlatRegion> pSfrChunkCL( CloneSurfFlatRegion( pSfr->CloneChunk( nC))) ;
if ( IsNull( pSfrChunkCL) || ! pSfrChunkCL->IsValid())
return false ;
if ( ! pSfrRegular->Add( *pSfrChunkCL))
return false ;
}
}
else {
if ( ! pSfrRegular.Set( pSfrTest))
return false ;
}
}
// se errore nella creazione del Chunk, clono l'originale
else {
PtrOwner<ISurfFlatRegion> pSfrChunkCL( CloneSurfFlatRegion( pSfr->CloneChunk( nC))) ;
if ( IsNull( pSfrChunkCL) || ! pSfrChunkCL->IsValid())
return false ;
if ( pSfrRegular->IsValid() && pSfrRegular->GetChunkCount() > 0) {
if ( ! pSfrRegular->Add( *pSfrChunkCL))
return false ;
}
else {
if ( ! pSfrRegular.Set( pSfrChunkCL))
return false ;
}
}
}
// resituisco la superficie
pSfr->CopyFrom( pSfrRegular) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::ModifySurfForOpenCloseEdges( ISurfFlatRegion* pSfr, const Vector3d& vtTool,
const ICurveComposite* pCrvCompo) const
{
// controllo dei parametri
if ( pSfr == nullptr || pCrvCompo == nullptr || ! pCrvCompo->IsValid())
return false ;
if ( ! pSfr->IsValid())
return true ;
/*
NB. Questa funzione è richiamata per i sub steps.
Alcuni subStep potrebbero avere dei lati aperti molto vicini ai lati chiusi della curva
scelta per la sgrossatura; modifico la superficie di riferimento per la scelta dei lati
Aperti/Chiusi estendendola con le regione generate dalle FatCurve dei tratti chiusi
*/
// ricavo i tratti chiusi della curva di sgrossatura
ICRVCOMPOPOVECTOR vpCrvs ;
if ( ! GetHomogeneousParts( pCrvCompo, vpCrvs))
return false ;
// scorro tutti i tratti chiusi e li aggiungo alla superficie da non rovinare
for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) {
if ( vpCrvs[i]->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) {
vpCrvs[i]->SetExtrusion( vtTool) ;
PtrOwner<ISurfFlatRegion> pSfrFat( GetSurfFlatRegionFromFatCurve( vpCrvs[i]->Clone(), m_TParams.m_dDiam / 2, false, false)) ;
if ( ! IsNull( pSfrFat) && pSfrFat->IsValid()) {
if ( pSfr->IsValid()) {
pSfr->Subtract( *pSfrFat) ;
if ( ! pSfr->IsValid())
return true ;
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::ChooseCloseOrOpenEdge( ISurfFlatRegion* pSfr, const ISurfFlatRegion* pSfrRef) const
{
// controllo parametri :
if ( pSfr == nullptr || ! pSfr->IsValid())
return true ; // <- se superficie non valida, allora non ho niente da impostare sui suoi lati
if ( pSfrRef == nullptr || ! pSfrRef->IsValid())
return false ;
// recupero la regione di riferimento ( effettuerò un piccolo Offset per tolleranza)
PtrOwner<ISurfFlatRegion> pSfrRef_Offs( CloneSurfFlatRegion( pSfrRef)) ;
if ( IsNull( pSfrRef_Offs))
return false ;
pSfrRef_Offs->Offset( - 50 * EPS_SMALL, ICurve::OFF_FILLET) ;
// salvo le informazioni del loop relativi alla flatRegion di classificazione
struct SurfRef_Info {
bool bIsExternal = true ;
int nInternalLoops = 0 ;
BBox3d bBox ;
PolyLine PL_Loop ;
} ;
vector<SurfRef_Info> vSfrRef_info ;
// assegno le info dei Loop della superficie di riferimento
for ( int nC = 0 ; nC < pSfrRef_Offs->GetChunkCount() ; ++ nC) {
for ( int nL = 0 ; nL < pSfrRef_Offs->GetLoopCount( nC) ; ++ nL) {
SurfRef_Info mySurfRef_Info ;
mySurfRef_Info.bIsExternal = ( nL == 0) ;
if ( mySurfRef_Info.bIsExternal)
mySurfRef_Info.nInternalLoops = pSfrRef_Offs->GetLoopCount( nC) - 1 ;
PtrOwner<ICurve> pCrv( pSfrRef_Offs->GetLoop( nC, nL)) ;
pCrv->ApproxWithLines( 10 * EPS_SMALL, 15, ICurve::APL_STD, mySurfRef_Info.PL_Loop) ;
if ( ! mySurfRef_Info.bIsExternal)
mySurfRef_Info.PL_Loop.Invert() ;
mySurfRef_Info.PL_Loop.GetLocalBBox( mySurfRef_Info.bBox) ;
vSfrRef_info.emplace_back( mySurfRef_Info) ;
}
}
// per ogni curva dei Loop della FlatRegion vengono presi 4 punti di controllo equidistanti.
// " IL LATO E' APERTO <=> TUTTI I PUNTI DI CONTROLLO NON SONO DENTRO A pSfrRef "
/*
Invece di classificare i punti con la FlatRegion stessa è stata creata una struttura
che contiene le PolyLine dei singoli loop. Quando io classifico un punto rispetto ad una
regione piana, vengono presi tutti i loops e, una volta trasformati in PolyLine, viene
classificato il punto rispetto ad esse. Invece di approssimare tutti i Loop da curve
composite e Polyline per ogni punto ( per classificarlo), vengono direttamente salvate
le PolyLine, in modo che questo passaggio sia fatto solo una volta all'inizio
*/
const int NUM_POINTS = 4 ;
// scorro tutti i loop
for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) {
for ( int nL = 0 ; nL < pSfr->GetLoopCount( nC) ; ++ nL) {
// recupero la curva composita del Loop
PtrOwner<ICurveComposite> pCrvCompoLoop( ConvertCurveToComposite( pSfr->GetLoop( nC, nL))) ;
if ( IsNull( pCrvCompoLoop) || ! pCrvCompoLoop->IsValid())
return false ;
// scorro ogni sua sottocurva
for ( int nU = 0 ; nU < pCrvCompoLoop->GetCurveCount() ; ++ nU) {
// metto a 1 la TmpProp della sottocurva corrente della superficie
pSfr->SetCurveTempProp( nC, nL, nU, TEMP_PROP_OPEN_EDGE, 0) ;
// recupero la sottocurva
const ICurve* pCrv = pCrvCompoLoop->GetCurve( nU) ;
if ( pCrv == nullptr)
return false ;
// recupero i NUM_POINTS punti
bool bIsOut = true ;
for ( int nP = 0 ; nP < NUM_POINTS + 1 ; ++ nP) {
double dPar = ( 1. / ( 1. * NUM_POINTS)) * nP ;
Point3d ptPar ;
if ( ! pCrv->GetPointD1D2( dPar, ICurve::FROM_PLUS, ptPar))
return false ;
// scorro il vettore relativo alla regione di riferimento
bIsOut = true ;
for ( int nI = 0 ; nI < int( vSfrRef_info.size()) ; ++ nI) {
if ( vSfrRef_info[nI].bIsExternal) { // se loop esterno
if ( vSfrRef_info[nI].bBox.Encloses( ptPar)) { // interno al box del loop
if ( IsPointInsidePolyLine( ptPar, vSfrRef_info[nI].PL_Loop, EPS_SMALL)) { // interno al loop vero e proprio
bool bInsideHole = false ;
// verifico se contenuto in un loop interno al loop esterno corrente
int nIntLoops = vSfrRef_info[nI].nInternalLoops ;
for ( int nJ = 0 ; nJ < nIntLoops ; ++ nJ) {
++ nI ;
if ( vSfrRef_info[nI].bBox.Encloses( ptPar)) {
if ( IsPointInsidePolyLine( ptPar, vSfrRef_info[nI].PL_Loop, EPS_SMALL))
bInsideHole = true ;
}
}
// se è contenuto nel loop esterno ma non è contenuto in nessuno dei loop interni allora il punto è interno
if ( ! bInsideHole)
bIsOut = false ;
}
}
}
}
if ( ! bIsOut) {
pSfr->SetCurveTempProp( nC, nL, nU, TEMP_PROP_CLOSE_EDGE, 0) ;
break ;
}
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
double
SurfRoughing::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) ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::CheckSafetyLinearLink( const Point3d& ptCurr, const Point3d& ptDest, const ISurfFlatRegion* pSfrCheck, const Vector3d& vtTool,
bool& bSafe) const
{
// controllo dei parametri
if ( ! ptCurr.IsValid() || ! ptDest.IsValid() || ! vtTool.IsValid())
return false ;
bSafe = true ;
// porto ptDest alla stessa quota di ptCurr secondo vtTool
Plane3d plProj ;
if ( ! plProj.Set( ptCurr, vtTool))
return false ;
Point3d ptDestProj = ProjectPointOnPlane( ptDest, plProj) ;
if ( AreSamePointApprox( ptDestProj, ptCurr)) {
bSafe = true ;
return true ;
}
// controllo se la retta che collega ptCurr a ptDesProj è interna o esterna alla regione limite
// devo prima creare un frame Locale XY
if ( pSfrCheck != nullptr && pSfrCheck->IsValid()) {
PtrOwner<ISurfFlatRegion> pSfrCheckLoc( CloneSurfFlatRegion( pSfrCheck)) ;
PtrOwner<ICurveLine> pLineLoc( CreateCurveLine()) ;
Frame3d frLoc ;
if ( IsNull( pSfrCheckLoc) || ! frLoc.Set( ptCurr, vtTool) ||
! ptDestProj.ToLoc( frLoc) || ! pSfrCheckLoc->ToLoc( frLoc) ||
! pSfrCheckLoc->Offset( m_TParams.m_dDiam / 2. - 10. * EPS_SMALL, ICurve::OFF_FILLET) ||
! pLineLoc->Set( ORIG, ptDestProj))
return false ;
for ( int nC = 0 ; nC < pSfrCheckLoc->GetChunkCount() && bSafe ; ++ nC) {
CRVCVECTOR ccClass ;
bSafe = ( pSfrCheckLoc->GetCurveClassification( *pLineLoc, EPS_SMALL, ccClass) &&
int( ccClass.size()) == 1 && ccClass[0].nClass == CRVC_OUT) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::VerifyLeadInHelix( const ISurfFlatRegion* pSfr, const Point3d& ptStart, const Point3d& ptCen,
double dHelixRad) const
{
// controllo validità dei parametri
if ( pSfr == nullptr || ! pSfr->IsValid())
return false ;
Vector3d vtN = pSfr->GetNormVersor() ;
// porto il centro sullo stesso piano del contorno
Point3d ptCenL = ptCen - ( ptCen - ptStart) * vtN * vtN ;
// Offset della regione
PtrOwner<ISurfFlatRegion> pSfrOffs( pSfr->CreateOffsetSurf( - m_TParams.m_dDiam / 2 - dHelixRad + 10 * EPS_SMALL, ICurve::OFF_FILLET)) ;
if ( IsNull( pSfrOffs) || ! pSfrOffs->IsValid())
return false ;
// controllo se l'elica è valida
bool bIsInside ;
return ( IsPointInsideSurfFr( ptCenL, pSfrOffs, 0., bIsInside) && bIsInside) ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::VerifyLeadInZigZag( const ISurfFlatRegion* pSfr, const Point3d& ptStart, const Point3d& ptPa,
const Point3d& ptPb) const
{
// controllo validità dei parametri
if ( pSfr == nullptr || ! pSfr->IsValid())
return false ;
Vector3d vtN = pSfr->GetNormVersor() ;
// porto i punti sullo stesso piano del contorno
Point3d ptPaL = ptPa - ( ptPa - ptStart) * vtN * vtN ;
Point3d ptPbL = ptPb - ( ptPb - ptStart) * vtN * vtN ;
// Offset della regione
PtrOwner<ISurfFlatRegion> pSfrOffs( pSfr->CreateOffsetSurf( - m_TParams.m_dDiam / 2 + 10 * EPS_SMALL, ICurve::OFF_FILLET)) ;
if ( IsNull( pSfrOffs) || ! pSfrOffs->IsValid())
return false ;
// controllo se i due punti sono validi
bool bIsInside ;
return ( IsPointInsideSurfFr( ptPaL, pSfrOffs, 0., bIsInside) && bIsInside &&
IsPointInsideSurfFr( ptPbL, pSfrOffs, 0., bIsInside) && bIsInside) ;
}
//----------------------------------------------------------------------------
bool
SurfRoughing::GetHomogeneousParts( const ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vpCrvs) const
{
// controllo dei parametri
if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid())
return false ;
vpCrvs.clear() ;
// scorro tutte le curve semplici nella composita
int nCurrTempProp ;
int nParStart = 0 ;
for ( int i = 0 ; i < pCrvCompo->GetCurveCount() ; ++ i) {
// ricavo la TmpProp
int nTempProp ;
pCrvCompo->GetCurveTempProp( i, nTempProp) ;
if ( i == 0) {
nCurrTempProp = nTempProp ;
nParStart = i ;
}
// se TmpProp differiscono, ricavo il tratto di curva omogeneo
else if ( nCurrTempProp != nTempProp) {
PtrOwner<ICurveComposite> pCrv( ConvertCurveToComposite( pCrvCompo->CopyParamRange( nParStart, i))) ;
if ( IsNull( pCrv))
return false ;
pCrv->SetTempProp( nCurrTempProp) ; // globale, al tratto di curva nel vettore
vpCrvs.emplace_back( Release( pCrv)) ;
nCurrTempProp = nTempProp ;
nParStart = i ;
}
}
// ultima curva...
PtrOwner<ICurveComposite> pCrvLast( ConvertCurveToComposite( pCrvCompo->CopyParamRange( nParStart, pCrvCompo->GetCurveCount()))) ;
if ( ! IsNull( pCrvLast)) {
pCrvLast->SetTempProp( nCurrTempProp) ;
vpCrvs.emplace_back( Release( pCrvLast)) ;
}
if ( vpCrvs.size() > 1) { // unisco il primo e l'ultimo se estremi compatibili
Point3d ptE ; vpCrvs.back()->GetEndPoint( ptE) ;
Point3d ptS ; vpCrvs[0]->GetStartPoint( ptS) ;
if ( AreSamePointApprox( ptS, ptE) && vpCrvs[0]->GetTempProp() == vpCrvs.back()->GetTempProp()) {
vpCrvs[0]->AddCurve( Release( vpCrvs.back()), false) ;
vpCrvs.erase( vpCrvs.end() - 1) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
// Debug Functions
//----------------------------------------------------------------------------
void
SurfRoughing::DrawLoopsSurf( const ISurfFlatRegion* pSfr, bool bUniform, Color Col, bool bAlphaCoverage,
string sName) const
{
if ( pSfr == nullptr || ! pSfr->IsValid())
return ;
int nIdGroup = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ;
m_pGeomDB->SetName( nIdGroup, sName) ;
int nIdLayer = m_pGeomDB->AddGroup( GDB_ID_NULL, nIdGroup, GLOB_FRM) ;
m_pGeomDB->SetName( nIdLayer, sName) ;
int nInd = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nIdLayer, pSfr->Clone()) ;
Color myColor = Col ;
if ( bAlphaCoverage)
myColor.Set( myColor.GetRed() / 2., myColor.GetGreen() / 2., myColor.GetBlue() / 2., myColor.GetAlpha() / 2.) ;
m_pGeomDB->SetMaterial( nInd, myColor) ;
for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) {
for ( int nL = 0 ; nL < pSfr->GetLoopCount( nC) ; ++ nL) {
PtrOwner<ICurveComposite> pCrvCompo( ConvertCurveToComposite( pSfr->GetLoop( nC, nL))) ;
for ( int nU = 0 ; nU < pCrvCompo->GetCurveCount() ; ++ nU) {
int nProp0 ; pCrvCompo->GetCurveTempProp( nU, nProp0, 0) ;
int nProp1 ; pCrvCompo->GetCurveTempProp( nU, nProp1, 1) ;
int nInd = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nIdLayer, pCrvCompo->GetCurve( nU)->Clone()) ;
m_pGeomDB->SetMaterial( nInd, bUniform ? WHITE : ( nProp0 == 0 ? ( bAlphaCoverage ? AQUA : BLUE) : ( bAlphaCoverage ? ORANGE : RED))) ;
}
}
}
return ;
}
//----------------------------------------------------------------------------
void
SurfRoughing::DrawFeed( const ICurve* pCrv, double dFeed, int nLay) const
{
if ( pCrv == nullptr)
return ;
// recupero parametro di Feed minima
double dMinFeed = GetFeed() / FEED_MAX_REDUCE ;
if ( GetValInNotes( m_Params.m_sUserNotes, UN_MINFEED, dMinFeed))
dMinFeed = Clamp( dMinFeed, GetFeed() / FEED_MAX_REDUCE, GetFeed()) ;
double myAngle = 120 * ( ( ( dFeed - dMinFeed) / ( GetFeed() - dMinFeed))) ;
int nInd = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCrv->Clone()) ;
m_pGeomDB->SetMaterial( nInd, GetColorFromHSV( HSV( myAngle, 1., 1.))) ;
return ;
return ;
}
//----------------------------------------------------------------------------
void
SurfRoughing::DrawNormalShaderSurfTm( const ISurfTriMesh* pStm, string sName) const
{
if ( pStm == nullptr || ! pStm->IsValid())
return ;
int nIdGroup = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ;
m_pGeomDB->SetName( nIdGroup, "ShaderStm") ;
int nIdLayer = m_pGeomDB->AddGroup( GDB_ID_NULL, nIdGroup, GLOB_FRM) ;
m_pGeomDB->SetName( nIdLayer, sName) ;
for ( int nT = 0 ; nT < pStm->GetTriangleCount() ; ++ nT) {
PtrOwner<ISurfTriMesh> pStmTria( pStm->CloneTriangle( nT)) ;
int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nIdLayer, pStmTria->Clone()) ;
Vector3d vtN ; pStmTria->GetFacetNormal( 0, vtN) ;
m_pGeomDB->SetMaterial( nId, Color( abs( vtN.x), abs( vtN.y), abs( vtN.z))) ;
}
return ;
}