Files
EgtMachKernel/Pocketing.cpp
T
Riccardo Elitropi 4d02f573d2 EgtMachKernel :
- codice di test migliorato per casi ottimizzati a spirale.
2023-11-06 18:34:10 +01:00

15382 lines
658 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2017-2022
//----------------------------------------------------------------------------
// File : Pocketing.cpp Data : 24.08.22 Versione : 2.4h2
// Contenuto : Implementazione gestione svuotature.
//
//
//
// Modifiche : 04.02.17 DS Creazione modulo.
// 24.02.22 DS Corretta ed estesa VerifyPathFromBottom.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "MachMgr.h"
#include "DllMain.h"
#include "Pocketing.h"
#include "OperationConst.h"
#include "MachiningConst.h"
#include "GeoConst.h"
#include "/EgtDev/Include/EGkCurveLine.h"
#include "/EgtDev/Include/EGkCurveArc.h"
#include "/EgtDev/Include/EGkBiArcs.h"
#include "/EgtDev/Include/EGkArcSpecial.h"
#include "/EgtDev/Include/EGkChainCurves.h"
#include "/EgtDev/Include/EGkOffsetCurve.h"
#include "/EgtDev/Include/EGkCurveAux.h"
#include "/EgtDev/Include/EGkSfrCreate.h"
#include "/EgtDev/Include/EGkSurfTriMesh.h"
#include "/EgtDev/Include/EGkExtText.h"
#include "/EgtDev/Include/EGkCurveLocal.h"
#include "/EgtDev/Include/EGkDistPointCurve.h"
#include "/EgtDev/Include/EGkUserObjFactory.h"
#include "/EgtDev/Include/EGkIntervals.h"
#include "/EgtDev/Include/EGkStringUtils3d.h"
#include "/EgtDev/Include/EGnStringKeyVal.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
#include "/EgtDev/Include/EgtNumUtils.h"
#include "/EgtDev/Include/EGkLinePntMinDistCurve.h"
#include "/EgtDev/Include/EGkDistPointCurve.h"
#include "/EgtDev/Include/EGkMedialAxis.h"
#include "/EgtDev/Include/EGkFilletChamfer.h"
#include "/EgtDev/Include/EGkCurveBezier.h"
#include "/EgtDev/Include/EGkGeoPoint3d.h"
#include "/EgtDev/Include/EGkIntersCurves.h"
#include "/EgtDev/Include/EGkLinePntTgCurve.h"
#include "/EgtDev/Include/EGkSfrCreate.h"
#include "/EgtDev/Include/EGkStmStandard.h"
#include "/EgtDev/Include/EGkIntersPlaneSurfTm.h"
#include "/EgtDev/Include/EGkDistPointSurfTm.h"
#include "/EgtDev/Include/EGkStmFromCurves.h"
#include "/EgtDev/Include/EGkStmFromTriangleSoup.h"
#include <algorithm>
using namespace std ;
//------------------------------ Errors --------------------------------------
// 2401 = "Error in Pocketing : UpdateToolData failed"
// 2402 = "Error in Pocketing : Open Contour"
// 2403 = "Error in Pocketing : Contour Not Flat"
// 2404 = "Error in Pocketing : Tool Not Perpendicular to Flat Area"
// 2405 = "Error in Pocketing : Empty RawBox"
// 2406 = "Error in Pocketing : Depth not computable"
// 2408 = "Error in Pocketing : Entity GetElevation"
// 2409 = "Error in Pocketing : missing aggregate from bottom"
// 2410 = "Error in Pocketing : path too far from part sides"
// 2411 = "Error in Pocketing : toolpath allocation failed"
// 2412 = "Error in Pocketing : Offset not computable"
// 2413 = "Error in Pocketing : Toolpath not computable"
// 2414 = "Error in Pocketing : Approach not computable"
// 2415 = "Error in Pocketing : LeadIn not computable"
// 2416 = "Error in Pocketing : LeadOut not computable"
// 2417 = "Error in Pocketing : Retract not computable"
// 2418 = "Error in Pocketing : Link not computable"
// 2419 = "Error in Pocketing : Linear Approx not computable"
// 2420 = "Error in Pocketing : Return toolpath not computable"
// 2421 = "Error in Pocketing : Chaining failed"
// 2422 = "Error in Pocketing : Tool MaxMaterial too small (xxx)"
// 2423 = "Error in Pocketing : axes values not calculable"
// 2424 = "Error in Pocketing : outstroke xxx"
// 2425 = "Error in Pocketing : link movements not calculable"
// 2426 = "Error in Pocketing : link outstroke xxx"
// 2427 = "Error in Pocketing : post apply not calculable"
// 2428 = "Error in Pocketing : Tool loading failed"
// 2429 = "Error in Pocketing : machining depth (xxx) bigger than MaxDepth (yyy)"
// 2430 = "Error in Pocketing : adjust open edges failed"
// 2431 = "Error in Pocketing : LeadIn with Mill NoTip in material"
// 2432 = "Error in Pocketing : Mirror for Double calculation failed"
// 2451 = "Warning in Pocketing : Skipped entity (xx)"
// 2452 = "Warning in Pocketing : No machinable pocket"
// 2453 = "Warning in Pocketing : Tool name changed (xx)"
// 2454 = "Warning in Pocketing : Tool data changed (xx)"
// 2455 = "Warning in Pocketing : skipped Path too short"
// 2456 = "Warning in Pocketing : machining step too small (xx)"
// 2457 = "Warning in Pocketing : machining step (xxx) bigger than MaxMaterial (yyy)"
// 2458 = "Warning in Pocketing : machining depth (xxx) bigger than MaxMaterial (yyy)"
//----------------------------------------------------------------------------
static string KEY_OPEN = "OPEN" ;
static const std::string BOX_NAME = "Box" ;
static int LINK_CURVE_PROP = -3 ;
static double FEED_DIVISOR = 1000.0 ;
static double TOLL_TRAPEZOID = 50 * EPS_SMALL ;
//----------------------------------------------------------------------------
USEROBJ_REGISTER( GetOperationClass( OPER_POCKETING), Pocketing) ;
//----------------------------------------------------------------------------
const string&
Pocketing::GetClassName( void) const
{
return USEROBJ_GETNAME( Pocketing) ;
}
//----------------------------------------------------------------------------
Pocketing*
Pocketing::Clone( void) const
{
// alloco oggetto
Pocketing* pPock = new(nothrow) Pocketing ;
// eseguo copia dei dati
if ( pPock != nullptr) {
try {
pPock->m_vId = m_vId ;
pPock->m_pMchMgr = m_pMchMgr ;
pPock->m_nPhase = m_nPhase ;
pPock->m_Params = m_Params ;
pPock->m_TParams = m_TParams ;
pPock->m_dTHoldBase = m_dTHoldBase ;
pPock->m_dTHoldLen = m_dTHoldLen ;
pPock->m_dTHoldDiam = m_dTHoldDiam ;
pPock->m_nStatus = m_nStatus ;
pPock->m_nPockets = m_nPockets ;
pPock->m_bTiltingTab = m_bTiltingTab ;
pPock->m_vtTiltingAx = m_vtTiltingAx ;
pPock->m_bAboveHead = m_bAboveHead ;
pPock->m_bAggrBottom = m_bAggrBottom ;
pPock->m_bOpenOutRaw = m_bOpenOutRaw ;
pPock->m_dOpenMinSafe = m_dOpenMinSafe ;
}
catch( ...) {
delete pPock ;
return nullptr ;
}
}
// ritorno l'oggetto
return pPock ;
}
//----------------------------------------------------------------------------
bool
Pocketing::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_nPockets) + szNewLine ;
sOut += KEY_STAT + EQUAL + ToString( m_nStatus) + szNewLine ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::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) {
string sParam = m_Params.ToString( i) ;
if ( ! sParam.empty())
vString[++k] = sParam ;
}
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_nPockets, vString[++k]))
return false ;
if ( ! SetVal( KEY_STAT, m_nStatus, vString[++k]))
return false ;
vString.resize( k + 1) ;
}
catch( ...) {
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::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_nPockets))
return false ;
}
else if ( sKey == KEY_STAT) {
if ( ! FromString( sVal, m_nStatus))
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
Pocketing::Pocketing( 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_dMaxHelixRad = INFINITO ;
m_nStatus = MCH_ST_TO_VERIFY ;
m_nPockets = 0 ;
m_bTiltingTab = false ;
m_bAboveHead = true ;
m_bAggrBottom = false ;
m_bOpenOutRaw = false ;
m_dOpenMinSafe = 0 ;
}
//----------------------------------------------------------------------------
bool
Pocketing::Prepare( const string& sMillName)
{
// 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 PocketingData* pDdata = GetPocketingData( pMMgr->GetMachining( sMillName)) ;
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
Pocketing::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 ;
case MPA_TOOLINVERT :
if ( bVal != m_Params.m_bToolInvert)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_bToolInvert = bVal ;
return true ;
}
return false ;
}
//----------------------------------------------------------------------------
bool
Pocketing::SetParam( int nType, int nVal)
{
switch ( nType) {
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 ;
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 ;
}
return false ;
}
//----------------------------------------------------------------------------
bool
Pocketing::SetParam( int nType, double dVal)
{
switch ( nType) {
case MPA_SPEED :
if ( ! m_TParams.VerifySpeed( dVal))
return false ;
if ( abs( m_TParams.m_dSpeed - dVal) < EPS_MACH_ANG_PAR)
dVal = 0 ;
if ( abs( dVal - m_Params.m_dSpeed) > EPS_MACH_ANG_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dSpeed = dVal ;
return true ;
case MPA_FEED :
if ( abs( m_TParams.m_dFeed - dVal) < EPS_MACH_LEN_PAR)
dVal = 0 ;
if ( abs( dVal - m_Params.m_dFeed) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dFeed = dVal ;
return true ;
case MPA_STARTFEED :
if ( abs( m_TParams.m_dStartFeed - dVal) < EPS_MACH_LEN_PAR)
dVal = 0 ;
if ( abs( dVal - m_Params.m_dStartFeed) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dStartFeed = dVal ;
return true ;
case MPA_ENDFEED :
if ( abs( m_TParams.m_dEndFeed - dVal) < EPS_MACH_LEN_PAR)
dVal = 0 ;
if ( abs( dVal - m_Params.m_dEndFeed) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dEndFeed = dVal ;
return true ;
case MPA_TIPFEED :
if ( abs( m_TParams.m_dTipFeed - dVal) < EPS_MACH_LEN_PAR)
dVal = 0 ;
if ( abs( dVal - m_Params.m_dTipFeed) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dTipFeed = dVal ;
return true ;
case MPA_OFFSR :
if ( abs( m_TParams.m_dOffsR - dVal) < EPS_MACH_LEN_PAR)
dVal = UNKNOWN_PAR ;
if ( abs( dVal - m_Params.m_dOffsR) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dOffsR = dVal ;
return true ;
case MPA_OFFSL :
if ( abs( m_TParams.m_dOffsL - dVal) < EPS_MACH_LEN_PAR)
dVal = UNKNOWN_PAR ;
if ( abs( dVal - m_Params.m_dOffsL) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dOffsL = 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 ( abs( dVal - m_Params.m_dStartPos) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dStartPos = dVal ;
return true ;
case MPA_STEP :
if ( abs( dVal - m_Params.m_dStep) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dStep = dVal ;
return true ;
case MPA_SIDESTEP :
if ( abs( dVal - m_Params.m_dSideStep) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dSideStep = dVal ;
return true ;
case MPA_SIDEANGLE :
if ( abs( dVal - m_Params.m_dSideAngle) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dSideAngle = dVal ;
return true ;
case MPA_LITANG :
if ( abs( dVal - m_Params.m_dLiTang) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dLiTang = dVal ;
return true ;
case MPA_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_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_EPICYCLESRAD :
if ( abs( dVal - m_Params.m_dEpicyclesRad) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dEpicyclesRad = dVal ;
return true ;
case MPA_EPICYCLESDIST :
if ( abs( dVal - m_Params.m_dEpicyclesDist) > EPS_MACH_LEN_PAR)
m_nStatus |= MCH_ST_PARAM_MODIF ;
m_Params.m_dEpicyclesDist = dVal ;
return true ;
}
return false ;
}
//----------------------------------------------------------------------------
bool
Pocketing::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
Pocketing::SetGeometry( const SELVECTOR& vIds)
{
// verifico validità gestore DB geometrico
if ( m_pGeomDB == nullptr)
return false ;
// reset della geometria corrente
m_vId.clear() ;
// verifico che gli identificativi rappresentino delle entità ammissibili (tutte curve o tutte facce)
int nType = GEO_NONE ;
for ( const auto& Id : vIds) {
// test sull'entità
int nSubs ;
if ( ! VerifyGeometry( Id, nSubs, nType)) {
string sInfo = "Warning in Pocketing : Skipped entity " + ToString( Id) ;
m_pMchMgr->SetWarning( 2451, sInfo) ;
continue ;
}
// posso aggiungere alla lista
m_vId.emplace_back( Id) ;
}
// aggiorno lo stato
m_nStatus |= MCH_ST_GEO_MODIF ;
// restituisco presenza geometria da lavorare
return ( ! m_vId.empty() || vIds.empty()) ;
}
//----------------------------------------------------------------------------
bool
Pocketing::Preview( bool bRecalc)
{
// reset numero percorsi di svuotatura generati
m_nPockets = 0 ;
// verifico validità gestore DB geometrico e Id del gruppo
if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId))
return false ;
// 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 ;
}
// aggiorno dati geometrici dell'utensile
if ( ! UpdateToolData()) {
m_pMchMgr->SetLastError( 2401, "Error in Pocketing : UpdateToolData failed") ;
return false ;
}
// 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( 2428, "Error in Pocketing : Tool loading failed") ;
return false ;
}
// recupero i dati del portautensile
int nToolId = m_pMchMgr->GetCalcTool() ;
m_dTHoldBase = 0 ;
m_pGeomDB->GetInfo( nToolId, TTH_BASE, m_dTHoldBase) ;
m_dTHoldLen = 0 ;
m_pGeomDB->GetInfo( nToolId, TTH_LEN, m_dTHoldLen) ;
m_dTHoldDiam = 0 ;
m_pGeomDB->GetInfo( nToolId, TTH_DIAM, m_dTHoldDiam) ;
// se necessario, eseguo concatenamento ed inserisco i percorsi sotto la geometria ausiliaria
if ( bChain && ! Chain( nAuxId)) {
m_pMchMgr->SetLastError( 2421, "Error in Pocketing : Chaining failed") ;
return false ;
}
// recupero gruppo per geometria di Preview
int nPvId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_PV) ;
// se non c'è, lo aggiungo
if ( nPvId == GDB_ID_NULL) {
nPvId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ;
if ( nPvId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nPvId, MCH_PV) ;
}
// altrimenti lo svuoto
else
m_pGeomDB->EmptyGroup( nPvId) ;
// lavoro ogni singola catena
int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ;
while ( nPathId != GDB_ID_NULL) {
if ( ! ProcessPath( nPathId, nPvId, GDB_ID_NULL))
return false ;
nPathId = m_pGeomDB->GetNextGroup( nPathId) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::Apply( bool bRecalc, bool bPostApply)
{
// reset numero percorsi di svuotatura generati
int nCurrPockets = m_nPockets ;
m_nPockets = 0 ;
// reset raggio massimo attacco ad elica nel caso di cerchi
m_dMaxHelixRad = INFINITO ;
// verifico validità gestore DB geometrico e Id del gruppo
if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId))
return false ;
// aggiorno dati geometrici dell'utensile
bool bToolChanged = true ;
if ( ! UpdateToolData( &bToolChanged)) {
m_pMchMgr->SetLastError( 2401, "Error in Pocketing : UpdateToolData failed") ;
return false ;
}
// verifico se necessario continuare nell'aggiornamento
if ( !bRecalc && !bToolChanged &&
( m_nStatus == MCH_ST_OK || ( !bPostApply && m_nStatus == MCH_ST_NO_POSTAPPL))) {
// confermo i percorsi di lavorazione
m_nPockets = nCurrPockets ;
LOG_DBG_INFO( GetEMkLogger(), "Pocketing apply skipped : status already ok") ;
// eseguo aggiornamento assi macchina e collegamento con operazione precedente
if ( ! Update( bPostApply))
return false ;
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( 2428, "Error in Pocketing : 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( 2421, "Error in Pocketing : Chaining failed") ;
return false ;
}
// lavoro ogni singola catena
bool bOk = true ;
if ( ! ProcessPath( nAuxId, GDB_ID_NULL, nClId))
bOk = false ;
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 ;
// se lavorazione in doppio, aggiungo geometria della parte simmetrica
if ( ! CalcMirrorByDouble( nClId, m_Params.m_sUserNotes)) {
m_pMchMgr->SetLastError( 2432, "Error in Pocketing : Mirror for Double calculation failed") ;
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(), "Pocketing apply done") ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::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_nPockets == 0) {
m_pMchMgr->SetWarning( 2452, "Warning in Pocketing : No machinable pocket") ;
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( 2423, "Error in Pocketing : axes values not calculable") ;
else
m_pMchMgr->SetLastError( 2424, "Error in Pocketing : outstroke ") ;
return false ;
}
// gestione movimenti all'inizio di ogni singolo percorso di lavorazione e alla fine della lavorazione
if ( ! AdjustStartEndMovements()) {
string sInfo = m_pMchMgr->GetOutstrokeInfo() ;
if ( sInfo.empty())
m_pMchMgr->SetLastError( 2425, "Error in Pocketing : link movements not calculable") ;
else
m_pMchMgr->SetLastError( 2426, "Error in Pocketing : link outstroke ") ;
return false ;
}
// assegno estremi degli assi dei vari percorsi di lavorazione e della lavorazione nel suo complesso
CalcAndSetAxesBBox() ;
// esecuzione eventuali personalizzazioni
string sErr ;
if ( bPostApply && ! PostApply( sErr)) {
if ( ! IsEmptyOrSpaces( sErr))
m_pMchMgr->SetLastError( 2427, sErr) ;
else
m_pMchMgr->SetLastError( 2427, "Error in Pocketing : post apply not calculable") ;
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetParam( int nType, bool& bVal) const
{
switch ( nType) {
case MPA_INVERT :
bVal = m_Params.m_bInvert ;
return true ;
case MPA_TOOLINVERT :
bVal = m_Params.m_bToolInvert ;
return true ;
}
bVal = false ;
return false ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetParam( int nType, int& nVal) const
{
switch ( nType) {
case MPA_TYPE :
nVal = MT_POCKETING ;
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 ;
case MPA_SUBTYPE :
nVal = m_Params.m_nSubType ;
return true ;
}
nVal = 0 ;
return false ;
}
//----------------------------------------------------------------------------
bool
Pocketing::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_STEP :
dVal = m_Params.m_dStep ;
return true ;
case MPA_SIDESTEP :
dVal = m_Params.m_dSideStep ;
return true ;
case MPA_SIDEANGLE :
dVal = m_Params.m_dSideAngle ;
return true ;
case MPA_LITANG :
dVal = m_Params.m_dLiTang ;
return true ;
case MPA_LIELEV :
dVal = m_Params.m_dLiElev ;
return true ;
case MPA_LOTANG :
dVal = m_Params.m_dLoTang ;
return true ;
case MPA_EPICYCLESRAD :
dVal = m_Params.m_dEpicyclesRad ;
return true ;
case MPA_EPICYCLESDIST :
dVal = m_Params.m_dEpicyclesDist ;
return true ;
}
dVal = 0 ;
return false ;
}
//----------------------------------------------------------------------------
bool
Pocketing::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&
Pocketing::GetToolData( void) const
{
return m_TParams ;
}
//----------------------------------------------------------------------------
bool
Pocketing::UpdateToolData( bool* pbChanged)
{
// recupero il gestore DB utensili della macchina corrente
ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ;
if ( pTMgr == nullptr)
return false ;
// recupero l'utensile nel DB utensili
const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ;
if ( pTdata == nullptr)
return false ;
// 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 Pocketing : tool name changed (" +
m_Params.m_sToolName + "->" + m_TParams.m_sName + ")" ;
m_pMchMgr->SetWarning( 2453, sInfo) ;
m_Params.m_sToolName = m_TParams.m_sName ;
}
if ( bChanged) {
string sInfo = "Warning in Pocketing : tool data changed (" +
m_Params.m_sToolName + ")" ;
m_pMchMgr->SetWarning( 2454, sInfo) ;
}
// se definito parametro di ritorno, lo assegno
if ( pbChanged != nullptr)
*pbChanged = bChanged ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetGeometry( SELVECTOR& vIds) const
{
// restituisco l'elenco delle entità
vIds = m_vId ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::VerifyGeometry( SelData Id, int& nSubs, int& nType)
{
// ammessi : curve, testi, facce di trimesh o regioni
const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ;
if ( pGObj == nullptr)
return false ;
// se ammesse curve ed è tale
if ( ( nType == GEO_NONE || nType == GEO_CURVE) && ( pGObj->GetType() & GEO_CURVE) != 0) {
nType = GEO_CURVE ;
const ICurve* pCurve = nullptr ;
// se direttamente la curva
if ( Id.nSub == SEL_SUB_ALL) {
pCurve = ::GetCurve( pGObj) ;
if ( pCurve == nullptr)
return false ;
if ( pCurve->GetType() == CRV_COMPO)
nSubs = ::GetCurveComposite( pCurve)->GetCurveCount() ;
else
nSubs = 0 ;
}
// altrimenti sottocurva di composita
else {
const ICurveComposite* pCompo = GetCurveComposite( pGObj) ;
pCurve = ( pCompo != nullptr ? pCompo->GetCurve( Id.nSub) : nullptr) ;
if ( pCurve == nullptr)
return false ;
nSubs = 0 ;
}
return true ;
}
// se altrimenti ammessi testi ed è tale
else if ( ( nType == GEO_NONE || nType == EXT_TEXT) && pGObj->GetType() == EXT_TEXT) {
nType = EXT_TEXT ;
const IExtText* pText = ::GetExtText( pGObj) ;
if ( pText == nullptr)
return false ;
nSubs = 0 ;
return true ;
}
// se altrimenti ammesse superfici trimesh ed è tale
else if ( ( nType == GEO_NONE || nType == SRF_TRIMESH) && pGObj->GetType() == SRF_TRIMESH) {
nType = SRF_TRIMESH ;
const ISurfTriMesh* pSurf = ::GetSurfTriMesh( pGObj) ;
if ( pSurf == nullptr)
return false ;
// se direttamente la superficie
if ( Id.nSub == SEL_SUB_ALL) {
// deve avere una sola faccia
if ( pSurf->GetFacetCount() != 1)
return false ;
nSubs = 1 ;
}
// altrimenti faccia di superficie trimesh
else {
// se faccia non esistente
if ( Id.nSub >= pSurf->GetFacetCount())
return false ;
nSubs = 0 ;
}
return true ;
}
// se altrimenti ammesse regioni ed è tale
else if ( ( nType == GEO_NONE || nType == SRF_FLATRGN) && pGObj->GetType() == SRF_FLATRGN) {
nType = SRF_FLATRGN ;
const ISurfFlatRegion* pReg = ::GetSurfFlatRegion( pGObj) ;
if ( pReg == nullptr)
return false ;
// se direttamente la regione
if ( Id.nSub == SEL_SUB_ALL) {
nSubs = pReg->GetChunkCount() ;
}
// altrimenti chunk di regione
else {
// se chunk non esistente
if ( Id.nSub >= pReg->GetChunkCount())
return false ;
// tutto bene
nSubs = 0 ;
}
return true ;
}
// altrimenti errore
else
return false ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetCurves( SelData Id, ICURVEPLIST& lstPC)
{
// ammessi : curve, testi, facce di trimesh o regioni
const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ;
if ( pGObj == nullptr)
return false ;
// ne recupero il riferimento globale
Frame3d frGlob ;
if ( ! m_pGeomDB->GetGlobFrame( Id.nId, frGlob))
return false ;
// se curva
if (( pGObj->GetType() & GEO_CURVE) != 0) {
PtrOwner<ICurve> pCurve ;
// se direttamente curva
if ( Id.nSub == SEL_SUB_ALL) {
// recupero la curva
const ICurve* pOriCurve = ::GetCurve( pGObj) ;
if ( pOriCurve == nullptr)
return false ;
PtrOwner<ICurveComposite> pOriCurveCompo( CreateCurveComposite()) ;
pOriCurveCompo->AddCurve( pOriCurve->Clone()) ;
double dThick ; pOriCurve->GetThickness( dThick) ;
Vector3d vtExtr ; pOriCurve->GetExtrusion( vtExtr) ;
pOriCurveCompo->SetExtrusion( vtExtr) ;
pOriCurveCompo->SetThickness( dThick) ;
pCurve.Set( pOriCurveCompo) ;
// recupero eventuali informazioni per lati aperti
SetCurveAllTempProp( Id.nId, false, pCurve) ;
// se estrusione mancante, imposto default
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()) ;
// reset proprietà temporanee
ResetCurveAllTempProp( pCurve) ;
// 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) ;
// salvo come TmpProp0 -> l'id della curva
pCurve->SetTempProp( Id.nId, 0) ;
// salvo come TmpProp0 -> -1 ( non ho lati adiacenti)
pCurve->SetTempProp( 1, -1) ;
// la restituisco
lstPC.emplace_back( Release( pCurve)) ;
return true ;
}
// se altrimenti testo
else if ( pGObj->GetType() == EXT_TEXT) {
// recupero il testo
const IExtText* pText = ::GetExtText( pGObj) ;
if ( pText == nullptr)
return false ;
// recupero l'outline del testo
if ( ! pText->GetOutline( lstPC))
return false ;
// reset proprietà temporanee ( nProp0 = 0, nProp1 = -1)
for ( auto pCrv : lstPC)
ResetCurveAllTempProp( pCrv) ;
// porto le curve in globale
for ( auto pCrv : lstPC)
pCrv->ToGlob( frGlob) ;
// salvo come TmpProp0 -> l'id della superificie ( per ogni loop )
// salvo come TmpProp1 -> -1 ( non ho lati adiacenti)
for ( auto pCrv : lstPC) {
pCrv->SetTempProp( Id.nId, 0) ;
pCrv->SetTempProp( -1, 1) ;
}
// ritorno
return true ;
}
// se altrimenti superficie
else if ( pGObj->GetType() == SRF_TRIMESH) {
// recupero la trimesh
const ISurfTriMesh* pSurf = ::GetSurfTriMesh( pGObj) ;
if ( pSurf == nullptr)
return false ;
// recupero l'indice della faccia
int nFacet = ( ( Id.nSub == SEL_SUB_ALL) ? 0 : Id.nSub) ;
// recupero i contorni della faccia
POLYLINEVECTOR vPL ;
pSurf->GetFacetLoops( nFacet, vPL) ;
if ( vPL.empty())
return false ;
// recupero la normale esterna della faccia
Vector3d vtN ;
if ( ! pSurf->GetFacetNormal( nFacet, vtN))
return false ;
// creo la curva a partire dei loop
for ( int i = 0 ; i < int( vPL.size()) ; i++) {
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
pCrvCompo->FromPolyLine( vPL[i]) ;
if ( ! pCrvCompo->IsValid())
return false ;
// reset delle proprietà temporanee
ResetCurveAllTempProp( pCrvCompo) ;
// determino eventuali lati aperti e aggiorno proprietà del contorno
int nInd = 0 ;
double dPar ;
bool bFound = vPL[i].GetFirstU( dPar, true) ;
while ( bFound) {
// recupero il flag
int nFlag = int( dPar) ;
// se non c'è nulla di adiacente, lato aperto
if ( nFlag == SVT_NULL) {
pCrvCompo->SetCurveTempProp( nInd, 1, 0) ; // --> lato aperto
pCrvCompo->SetCurveTempProp( nInd, -1, 1) ; // --> nessuna faccia adiacente
}
// altrimenti verifico se la faccia adiacente forma diedro convesso o concavo
else {
bool bAdjac ;
Point3d ptP1, ptP2 ;
double dAng ;
if ( ! pSurf->GetFacetsContact( nFacet, nFlag, bAdjac, ptP1, ptP2, dAng))
dAng = - ANG_RIGHT ;
if ( dAng > - EPS_ANG_SMALL) {
pCrvCompo->SetCurveTempProp( nInd, 1, 0) ; // --> lato aperto
pCrvCompo->SetCurveTempProp( nInd, -1, 1) ; // --> nessuna faccia adiacente
}
else
// salvo come prop 1 la faccia adiacente
pCrvCompo->SetCurveTempProp( nInd, nFlag, 1) ; // --> il lato chiuso è 0 per default
}
// passo al successivo
++nInd ;
bFound = vPL[i].GetNextU( dPar, true) ;
}
// assegno l'estrusione dalla normale alla faccia
pCrvCompo->SetExtrusion( vtN) ;
// porto la curva nel sistema di riferimento globale
pCrvCompo->ToGlob( frGlob) ;
// unisco le eventuali parti allineate ( mantenendo le proprietà )
pCrvCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ;
// sistemazioni varie
AdjustCurveFromSurf( pCrvCompo, TOOL_ORTHO, FACE_CONT, 0) ;
// salvo come TmpProp0 -> l'id della superificie
pCrvCompo->SetTempProp( Id.nId, 0) ;
// salvo come TmpProp1 -> il numero della faccia selezionata
pCrvCompo->SetTempProp( nFacet, 1) ;
// la restituisco
lstPC.emplace_back( Release( pCrvCompo)) ;
}
return true ;
}
// se altrimenti regione
else if ( pGObj->GetType() == SRF_FLATRGN) {
// recupero la regione
const ISurfFlatRegion* pReg = ::GetSurfFlatRegion( pGObj) ;
if ( pReg == nullptr)
return false ;
// recupero la normale della regione
Vector3d vtN = pReg->GetNormVersor() ;
if ( vtN.IsSmall())
return false ;
// determino intervallo di chunk
int nCstart = 0 ;
int nCend = pReg->GetChunkCount() ;
if ( Id.nSub != SEL_SUB_ALL) {
nCstart = Id.nSub ;
nCend = nCstart + 1 ;
}
// ciclo sui chunk
for ( int nC = nCstart ; nC < nCend ; ++ nC) {
// recupero i contorni del chunk
for ( int nL = 0 ; nL < pReg->GetLoopCount( nC) ; ++ nL) {
PtrOwner<ICurveComposite> pCrvCompo ;
if ( ! pCrvCompo.Set( ConvertCurveToComposite( pReg->GetLoop( nC, nL))))
return false ;
// reset proprietà temporanee ( per ogni sottocurva -> nProp0 = 0, nProp1 = -1)
ResetCurveAllTempProp( pCrvCompo) ;
// assegno l'estrusione dalla normale alla regione
pCrvCompo->SetExtrusion( vtN) ;
// unisco le eventuali parti allineate
pCrvCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ;
// la porto in globale
pCrvCompo->ToGlob( frGlob) ;
// imposto come TmpProp0 -> l'id della superificie
pCrvCompo->SetTempProp( Id.nId, 0) ;
//imposto come TmpProp1 -> -1 ( non ho facce adiancenti)
pCrvCompo->SetTempProp( -1, 1) ;
// sistemazioni varie
AdjustCurveFromSurf( pCrvCompo, TOOL_ORTHO, FACE_CONT, 0) ;
// la restituisco
lstPC.emplace_back( Release( pCrvCompo)) ;
}
}
return true ;
}
// altrimenti errore
else
return false ;
}
//----------------------------------------------------------------------------
bool
Pocketing::SetCurveAllTempProp( int nCrvId, bool bForcedClose, ICurve* pCurve, bool* pbSomeOpen)
{
if ( pCurve == nullptr)
return false ;
if ( pbSomeOpen != nullptr)
*pbSomeOpen = false ;
// reset proprietà temporanee
ResetCurveAllTempProp( pCurve) ;
// se forzato chiuso o non presenti info per lati aperti, esco
if ( bForcedClose || ! m_pGeomDB->ExistsInfo( nCrvId, KEY_OPEN))
return true ;
// recupero info sui lati aperti
INTVECTOR vOpen ;
m_pGeomDB->GetInfo( nCrvId, KEY_OPEN, vOpen) ;
// se curva composita
ICurveComposite* pCC = GetCurveComposite( pCurve) ;
if ( pCC != nullptr) {
for ( int j : vOpen) {
if ( pCC->SetCurveTempProp( j, 1)) {
if ( pbSomeOpen != nullptr)
*pbSomeOpen = true ;
}
}
}
// altrimenti
else {
if ( ! vOpen.empty() && vOpen[0] == 0) {
pCurve->SetTempProp( 1) ;
if ( pbSomeOpen != nullptr)
*pbSomeOpen = true ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetForcedClosed( void)
{
int nOpen ;
if ( FromString( ExtractInfo( m_Params.m_sUserNotes, "Open="), nOpen) && nOpen == 0)
return true ;
else
return false ;
}
//----------------------------------------------------------------------------
bool
Pocketing::ResetCurveAllTempProp( ICurve* pCurve)
{
if ( pCurve == nullptr)
return false ;
pCurve->SetTempProp( 0) ;
ICurveComposite* pCC = GetCurveComposite( pCurve) ;
if ( pCC != nullptr) {
for ( int i = 0 ; i < pCC->GetCurveCount() ; ++ i) {
pCC->SetCurveTempProp( i, 0, 0) ;
//int nTmpProp1 ; pCC->GetCurveTempProp( i, nTmpProp1, 1) ;
//if ( nTmpProp1 != -2)
// pCC->SetCurveTempProp( i, -1, 1) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::Chain( int nGrpDestId)
{
// controllo quanti elementi ho nel vettore degli indici selezionati
int nSelId = ( int)m_vId.size() ;
if ( nSelId > 1 && ! CheckSelectedId())
return false ;
// 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 Pocketing : Skipped entity " + ToString( Id) ;
m_pMchMgr->SetWarning( 2451, sInfo) ;
}
for ( auto pCrv : lstPC) {
vpCrvs.emplace_back( pCrv) ;
vInds.emplace_back( Id) ;
}
}
// preparo i dati per il concatenamento
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) {
ptNear = ptStart + 10 * EPS_SMALL * vtStart ;
bFirst = false ;
}
}
// recupero i percorsi concatenati
int nCount = 0 ;
INTVECTOR vnId2 ;
while ( chainC.GetChainFromNear( ptNear, false, vnId2)) {
// creo una curva composita
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
if ( IsNull( pCrvCompo))
return false ;
// estrusione e spessore
Vector3d vtExtr = Z_AX ;
double dThick = 0 ;
// vettore Id originali
SELVECTOR vId2 ;
vId2.reserve( vnId2.size()) ;
// recupero le curve semplici e le inserisco nella curva composita
for ( size_t i = 0 ; i < vnId2.size() ; ++ i) {
int nId = abs( vnId2[i]) - 1 ;
bool bInvert = ( vnId2[i] < 0) ;
vId2.emplace_back( vInds[nId]) ;
// recupero la curva
ICurve* pCrv = vpCrvs[nId] ;
// se necessario, la inverto
if ( bInvert)
pCrv->Invert() ;
// recupero eventuali estrusione e spessore
Vector3d vtTemp ;
if ( pCrv->GetExtrusion( vtTemp)) {
vtExtr = vtTemp ;
double dTemp ;
if ( pCrv->GetThickness( dTemp) && abs( dTemp) > abs( dThick))
dThick = dTemp ;
}
// riporto le proprietà temporanee
pCrvCompo->SetTempProp( vpCrvs[nId]->GetTempProp( 0), 0) ;
pCrvCompo->SetTempProp( vpCrvs[nId]->GetTempProp( 1), 1) ;
// la aggiungo alla curva composta
if ( ! pCrvCompo->AddCurve( ::Release( vpCrvs[nId]), true, dToler))
return false ;
}
// se non sono state inserite curve, vado oltre
if ( pCrvCompo->GetCurveCount() == 0)
continue ;
// imposto estrusione e spessore
pCrvCompo->SetExtrusion( vtExtr) ;
pCrvCompo->SetThickness( dThick) ;
// aggiorno il nuovo punto vicino
pCrvCompo->GetEndPoint( ptNear) ;
// se utile, approssimo con archi
//if ( ! ApproxWithArcsIfUseful( pCrvCompo, true))
// return false ;
// recupero eventuali lati aperti
INTVECTOR vOpen ;
for ( int i = 0 ; i < int( pCrvCompo->GetCurveCount()) ; ++ i) {
int nProp = 0 ;
if ( pCrvCompo->GetCurveTempProp( i, nProp) && nProp == 1)
vOpen.emplace_back( i) ;
}
// creo nuovo gruppo
int nPathId = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrpDestId, Frame3d()) ;
if ( nPathId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nPathId, MCH_PATH + ToString( ++ nCount)) ;
m_pGeomDB->SetInfo( nPathId, KEY_IDS, ToString( vId2)) ;
// inserisco la curva composita nel gruppo destinazione
int nNewId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, ::Release( pCrvCompo)) ;
if ( nNewId == GDB_ID_NULL)
return false ;
// salvo info con eventuali lati aperti
if ( ! vOpen.empty())
m_pGeomDB->SetInfo( nNewId, KEY_OPEN, vOpen) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::ProcessPath( int nAuxId, int nPvId, int nClId)
{
// ========= GRUPPO TMP ===================
// recupero gruppo per geometria temporanea ( Gruppo TMP )
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 eventuale flag di lato aperto forzato fuori dal grezzo
int nOpenOutRaw ;
m_bOpenOutRaw = ( FromString( ExtractInfo(m_Params.m_sUserNotes, "OpenOutRaw="), nOpenOutRaw) && nOpenOutRaw != 0) ;
// creo una superificie temporanea generata da tutte le curve ( curve modificate se valide )
SurfFlatRegionByContours SrfByC ; // superificie totale generata da tutte le curve concatenate
Plane3d plAux ; bool bFirstPlane = true ; // piano Ausiliario per verificare che le curve siano complanari
Vector3d vtExtr ;
double dThick = -INFINITO ; // spessore più grande tra le curve
int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ;
// indici da associare alla SurfFlatRegion da svuotare :
// Ogni curva che definirà un loop nella flat Region avrà la seguente struttura :
// { nProp0, nProp1 } = { Id elemento selezionato, id faccia adiacente (solo per Trimesh) }
// Per ogni curva di questi loop avrò :
// { nProp0, nProp1 } = { (0 -> chiuso, 1 -> aperto) , id faccia adiacente ( solo per Trimesh )}
int nProp0 = -1 ;
int nProp1 = -1 ;
while ( nPathId != GDB_ID_NULL) { // Scorro tutte le curve concatenate per creare la superficie da lavorare
int nPi = m_pGeomDB->GetFirstInGroup( nPathId) ; //nCrvId
if ( m_pGeomDB->GetGeoType( nPi) != CRV_COMPO)
return false ;
const ICurve* pOriCurve = ::GetCurve( m_pGeomDB->GetGeoObj( nPi)) ;
if ( pOriCurve == nullptr)
return false ;
PtrOwner<ICurveComposite> pCompoOriCrv( GetCurveComposite( pOriCurve->Clone())) ;
if ( IsNull( pCompoOriCrv))
return false ;
// ricavo le proprietà della curva
nProp0 = pCompoOriCrv->GetTempProp( 0) ; // id selezionato
nProp1 = pCompoOriCrv->GetTempProp( 1) ; // lato adiancente per Trimesh
// annullo i flag di tratto aperto
for ( int i = 0 ; i < int( pCompoOriCrv->GetCurveCount()) ; ++i)
pCompoOriCrv->SetCurveTempProp( i, 0, 0) ; // alla sottocurva
bool bSomeOpen ; // = m_pGeomDB->ExistsInfo( nPi, KEY_OPEN) ;
SetCurveAllTempProp( nPi, GetForcedClosed(), pCompoOriCrv, &bSomeOpen) ;
// unisco le parti allineate (tranne inizio-fine se chiusa)
if ( ! pCompoOriCrv->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, false, true))
return false ;
// recupero estrusione e spessore
Vector3d vtExtr_p = Z_AX ;
pCompoOriCrv->GetExtrusion( vtExtr_p) ;
double dThick_p ;
pCompoOriCrv->GetThickness( dThick_p) ;
// verifico sia piana e se necessario la appiattisco
PtrOwner<ICurve> pFlatCrv( FlattenCurve( *pCompoOriCrv, 50 * EPS_SMALL, 50 * EPS_ANG_SMALL, FLTCRV_USE_EXTR)) ;
if ( IsNull( pFlatCrv)) {
Plane3d plPlane ;
if ( ! pCompoOriCrv->IsFlat( plPlane, true, 50 * EPS_SMALL))
m_pMchMgr->SetLastError( 2403, "Error in Pocketing : Contour Not Flat") ;
else
m_pMchMgr->SetLastError( 2404, "Error in Pocketing : Tool Not Perpendicular to Flat Area") ;
return false;
}
pFlatCrv->GetExtrusion( vtExtr_p) ;
pCompoOriCrv->Clear() ;
pCompoOriCrv->AddCurve( Release( pFlatCrv)) ;
pCompoOriCrv->SetExtrusion( vtExtr_p) ;
pCompoOriCrv->SetThickness( dThick_p) ;
// setto come proprietà temperanea il suo Id
pCompoOriCrv->SetTempProp( nProp0, 0) ; // a tutta la curva ( id selezionato )
pCompoOriCrv->SetTempProp( nProp1, 1) ; // a tutta la curva ( se Trimesh, faccia adiacente )
// controllo che le curve siano complanari e con stessa estrusione (la prima come riferimento)
Plane3d plAct ;
pCompoOriCrv->IsFlat( plAct) ;
if ( bFirstPlane) {
plAux = plAct ;
bFirstPlane = false ;
pCompoOriCrv->GetThickness( dThick_p) ;
dThick = dThick_p ; // prima come riferimento
vtExtr = vtExtr_p ; // prima come riferimento
SrfByC.AddCurve( pCompoOriCrv->Clone()) ;
}
else {
Vector3d vtN1, vtN2 ;
if ( abs( plAct.GetDist() - plAux.GetDist()) < 5 * EPS_SMALL
&& AreSameOrOppositeVectorApprox( plAct.GetVersN(), plAux.GetVersN()) // se stessa normale
&& AreSameVectorApprox( vtExtr, vtExtr_p)) { // se stessa estrusione
PtrOwner<ICurve> pCrvProjected( ProjectCurveOnPlane( *pCompoOriCrv, plAux)) ;
pCrvProjected->SetExtrusion( vtExtr) ;
// prendo Thickness Massima tra tutte le curve dei chunks
double dCurrThick ;
pCompoOriCrv->GetThickness( dCurrThick) ;
if ( dCurrThick > dThick)
dThick = dCurrThick ;
pCrvProjected->SetThickness( dCurrThick) ;
SrfByC.AddCurve( pCrvProjected->Clone()) ;
}
}
nPathId = m_pGeomDB->GetNextGroup( nPathId) ; // aggiorno il PathId con il successivo nel gruppo
}
// creazione della superficie da lavorare completa ( dall'unione di tutte le curve concatenate)
PtrOwner<ISurfFlatRegion> pSrfPock( SrfByC.GetSurf()) ;
if ( IsNull( pSrfPock) || pSrfPock->GetChunkCount() == 0)
return false ;
// normale della superifice finale || extrusione prima curva selezionata
if ( AreOppositeVectorApprox( vtExtr, pSrfPock->GetNormVersor()))
pSrfPock->Invert() ;
if ( m_Params.m_bToolInvert) {
// eventuale inversione direzione utensile
vtExtr.Invert() ;
pSrfPock->Invert() ;
dThick = -dThick ;
}
// controllo se la superificie contiene lati aperti interno al grezzo
// 1) recupero la Trimesh del grezzo
PtrOwner<ISurfTriMesh> pStmRaw( CreateSurfTriMesh()) ;
if ( IsNull( pStmRaw))
return false ;
pStmRaw->DoCompacting() ;
if ( ! GetStmRawPart( nProp0, pStmRaw))
return false ;
// 2) Imposto TmpProp1 = -2 a tutti i lati aperti ( TmpProp0 = 1 ) interno al grezzo
if ( ! DetectOpenEdgeInsideRaw ( pSrfPock, pStmRaw))
return false ;
// recupero il box del grezzo in globale
BBox3d b3Raw ;
BBox3d b3Chunk ; pSrfPock->GetBBox( GLOB_FRM, b3Chunk) ;
if ( ! GetRawGlobBox( m_nPhase, b3Chunk, 0.5 * m_TParams.m_dTDiam, b3Raw) || b3Raw.IsEmpty()) {
m_pMchMgr->SetLastError( 2405, "Error in Pocketing : Empty RawBox") ;
return false ;
}
// recupero distanza da fondo dei grezzi interessati dal percorso
double dRbDist = 0 ; double dAllRbDist = 0 ;
if ( AreSameVectorApprox( vtExtr, Z_AX)) {
if ( ! GetDistanceFromRawBottom( m_nPhase, b3Chunk, m_TParams.m_dTDiam, dRbDist, dAllRbDist))
return false ;
}
// valuto l'espressione dell'affondamento
ExeLuaSetGlobNumVar( "TH", abs( dThick)) ;
ExeLuaSetGlobNumVar( "RB", dRbDist) ;
double dDepth ;
string sMyDepth = m_Params.m_sDepth ;
if ( ! ExeLuaEvalNumExpr( ToUpper( sMyDepth), &dDepth)) {
m_pMchMgr->SetLastError( 2406, "Error in Pocketing : Depth not computable") ;
return false ;
}
// se spessore positivo, lo sottraggo dal risultato
if ( dThick > 0)
dDepth -= dThick ;
// sottraggo eventuale offset longitudinale
dDepth -= GetOffsL() ;
// assegno il versore fresa
Vector3d vtTool = vtExtr ;
m_bAggrBottom = false ;
// calcolo l'elevazione massima
double dElev = -INFINITO ;
for ( int c = 0; c < pSrfPock->GetChunkCount() ; c++) {
double dCurrElev ;
PtrOwner<ICurveComposite> pCvrCompo( GetCurveComposite( pSrfPock->GetLoop( c,0))) ;
if ( CalcRegionElevation( pCvrCompo, vtTool, dDepth, 0.5 * m_TParams.m_dDiam, dCurrElev)) {
if ( dCurrElev < EPS_SMALL && AreSameVectorApprox( vtExtr, Z_AX)) {
BBox3d b3Crv ;
pSrfPock->GetLoop( c, 0)->GetLocalBBox( b3Crv) ;
dCurrElev = max( 0., b3Raw.GetMax().z - b3Crv.GetMin().z + min(0., dThick) + dDepth) ;
}
if ( dCurrElev > dElev)
dElev = dCurrElev ;
}
else
return false ;
}
// eventuale imposizione massima elevazione da note utente
double dMaxElev ;
if ( FromString( ExtractInfo( m_Params.m_sUserNotes, "MaxElev="), dMaxElev) && dElev > dMaxElev)
dElev = dMaxElev ;
// verifico che lo step dell'utensile sia sensato
double dOkStep = ( m_Params.m_dStep > EPS_SMALL ? m_Params.m_dStep + EPS_SMALL : 0) ;
const double MIN_ZSTEP = 1.0 ;
if ( dOkStep >= EPS_SMALL && dOkStep < MIN_ZSTEP) {
dOkStep = MIN_ZSTEP + EPS_SMALL ;
string sInfo = "Warning in Pocketing : machining step too small (" + ToString( m_Params.m_dStep, 2) + ")" ;
m_pMchMgr->SetWarning( 2456, sInfo) ;
}
// verifico che il massimo materiale dell'utensile sia sensato
const double MIN_MAXMAT = 1.0 ;
if ( m_TParams.m_dMaxMat < dElev && m_TParams.m_dMaxMat < MIN_MAXMAT) {
string sInfo = "Error in Pocketing : Tool MaxMaterial too small (" + ToString(m_TParams.m_dMaxMat, 2) + ")" ;
m_pMchMgr->SetLastError( 2422, sInfo) ;
return false ;
}
// verifico di non superare il massimo materiale
// se lo step supera la capacità dell'utensile
if ( m_Params.m_dStep > m_TParams.m_dMaxMat + EPS_SMALL) {
dOkStep = m_TParams.m_dMaxMat + EPS_SMALL ;
string sInfo = "Warning in Pocketing : machining step (" + ToString( m_Params.m_dStep, 1) + ") bigger than MaxMaterial ("
+ ToString( m_TParams.m_dMaxMat, 1) + ")" ;
m_pMchMgr->SetWarning( 2457, sInfo) ;
}
// se lavorazione singola
if ( dOkStep < EPS_SMALL || dOkStep > dElev) {
// se l'elevazione supera la capacità dell'utensile
if ( dElev > m_TParams.m_dMaxMat + EPS_SMALL ) {
string sInfo = "Warning in Pocketing : machining depth (" + ToString(dElev, 1) +
") bigger than MaxMaterial (" + ToString( m_TParams.m_dMaxMat, 1) + ")" ;
m_pMchMgr->SetWarning( 2458, sInfo) ;
dDepth -= dElev - m_TParams.m_dMaxMat ;
dElev = m_TParams.m_dMaxMat ;
}
}
// altrimenti lavorazione a step
else {
// se l'elevazione supera il massimo affondamento dell'utensile
double dSafe = m_pMchMgr->GetCurrMachiningsMgr()->GetMaxDepthSafe() ;
double dMaxDepth = m_TParams.m_dLen - ( m_TParams.m_dDiam > m_dTHoldDiam ? m_dTHoldBase : m_dTHoldLen) - dSafe ;
if ( dElev > dMaxDepth + EPS_SMALL) {
// segnalo, riduco e continuo
string sInfo = "Warning in Pocketing : machining depth (" + ToString( dElev, 1) +
") bigger than MaxDepth (" + ToString( dMaxDepth, 1) + ")" ;
m_pMchMgr->SetWarning( 2458, sInfo) ;
dDepth -= dElev - dMaxDepth ;
dElev = dMaxDepth ;
}
}
// verifico se tavola basculante
bool bTiltTab = false ;
m_bTiltingTab = ( m_pMchMgr->GetCurrMachine()->GetCurrTableIsTilting( bTiltTab, m_vtTiltingAx) && bTiltTab) ;
// verifico se testa da sopra (Z+)
m_bAboveHead = m_pMchMgr->GetHeadAbove( m_TParams.m_sHead) ;
// verifiche per svuotature dal basso
m_bAggrBottom = false ;
if ( ! VerifyPathFromBottom( pSrfPock, vtTool))
return false ;
// recupero nome del path
string sPathName = "P1" ;
// recupero eventuale minima lunghezza di attacco su lato aperto
FromString( ExtractInfo( m_Params.m_sUserNotes, "OpenMinSafe="), m_dOpenMinSafe) ;
// se richiesta anteprima
if ( nPvId != GDB_ID_NULL) {
// creo gruppo per geometria di lavorazione del percorso
int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nPvId, Frame3d()) ;
if ( nPxId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nPxId, sPathName) ;
m_pGeomDB->SetMaterial( nPxId, GREEN) ;
// creo l'anteprima del percorso
if ( ! GeneratePocketingPv( nPxId, pSrfPock))
return false ;
}
// 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
int nSplitArcs = m_pMchMgr->GetCurrMachiningsMgr()->GetSplitArcs() ;
bool bSplitArcs = ( nSplitArcs == SPLAR_ALWAYS ||
( nSplitArcs == SPLAR_NO_XY_PLANE && !vtExtr.IsZplus()) ||
( nSplitArcs == SPLAR_GEN_PLANE && vtExtr.IsGeneric())) ;
// assegno il vettore estrazione al gruppo del percorso
m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ;
// assegno l'elevazione massima
m_pGeomDB->SetInfo( nPxId, KEY_ELEV, dElev) ;
// Imposto dati comuni
SetPathId( nPxId) ;
SetToolDir( vtTool) ;
// Eseguo la lavorazione della superificie finale
switch ( m_Params.m_nSubType) {
case POCKET_SUB_ZIGZAG:
if ( ! AddZigZag( pSrfPock, vtTool, vtExtr, dDepth, dMaxElev, dElev, dOkStep, bSplitArcs))
return false ;
break ;
case POCKET_SUB_ONEWAY:
if ( ! AddOneWay( pSrfPock, vtTool, vtExtr, dDepth, dElev, dOkStep, bSplitArcs))
return false ;
break ;
case POCKET_SUB_SPIRALIN:
if ( ! AddSpiralIn( pSrfPock, vtTool, vtExtr, dDepth, dElev, dMaxElev, dOkStep, bSplitArcs))
return false ;
break ;
case POCKET_SUB_SPIRALOUT:
if ( ! AddSpiralOut( pSrfPock, vtTool, vtExtr, dDepth, dElev, dMaxElev, dOkStep, bSplitArcs))
return false ;
break ;
}
}
m_nPockets++ ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::DetectOpenEdgeInsideRaw ( ISurfFlatRegion* pSfr, const ISurfTriMesh* pStmRaw) {
return true ;
// controllo dei parametri
if ( pSfr == nullptr || ! pSfr->IsValid() || pSfr->GetChunkCount() == 0 ||
pStmRaw == nullptr || ! pStmRaw->IsValid() || pStmRaw->GetTriangleCount() == 0)
return false ;
// ricavo il piano della svuotatura
Vector3d vtN = pSfr->GetNormVersor() ;
Point3d ptC ;
if ( ! pSfr->GetCentroid( ptC)) {
PtrOwner<ICurveComposite> pCrvCompo( ConvertCurveToComposite( pSfr->GetLoop( 0, 0))) ;
if ( IsNull( pCrvCompo) ||
! pCrvCompo->IsValid() ||
! pCrvCompo->GetStartPoint( ptC))
return false ;
}
Plane3d plPock ; plPock.Set( ptC, vtN) ;
if ( ! plPock.IsValid())
return false ;
// taglio il grezzo con il piano di svuotatura
PtrOwner<ISurfTriMesh> pStmRaw_Clone( CloneSurfTriMesh( pStmRaw)) ;
if ( IsNull( pStmRaw_Clone) || ! pStmRaw_Clone->IsValid() ||
! pStmRaw_Clone->Cut( plPock, true) ||
IsNull( pStmRaw_Clone) || ! pStmRaw_Clone->IsValid())
return false ;
if ( pStmRaw_Clone->GetTriangleCount() == 0)
return true ;
// estraggo i bordi liberi, così facendo posso ricavare una Flat Region nel piano di svuotatura.
// Userò questa FlatRegion come insieme per confrontare i lati aperti interni ad essa
PtrOwner<ISurfFlatRegion> pSfrRawCheck( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrRawCheck))
return false ;
SurfFlatRegionByContours SrfBC ;
// 1) estraggo i Loop del grezzo tagliato
POLYLINEVECTOR vPL ;
pStmRaw_Clone->GetLoops( vPL) ;
for ( int i = 0 ; i < ( int)vPL.size() ; ++ i) {
PtrOwner<ICurveComposite> pCrvLoop( CreateCurveComposite()) ;
if ( IsNull( pCrvLoop))
return false ;
pCrvLoop->FromPolyLine( vPL[i]) ;
if ( pCrvLoop->IsValid())
SrfBC.AddCurve( Release( pCrvLoop)) ;
}
// 2) ricavo la FlatRegion per il controllo delle curve e creo quella da restiruire alla fine
pSfrRawCheck.Set( SrfBC.GetSurf()) ;
if ( IsNull( pSfrRawCheck) || ! pSfrRawCheck->IsValid())
return false ;
SurfFlatRegionByContours SfrBC_Final ;
// 3) per ogni Chunk-c della FlatRegion da svuotare, controllo le TmpProp delle curve
bool bChanged = false ;
for ( int c = 0 ; c < pSfr->GetChunkCount() ; ++ c) {
// 3.1) estraggo il bordo esterno ( controllo solo quello )
PtrOwner<ICurveComposite> pCrvExt( ConvertCurveToComposite( pSfr->GetLoop( c, 0))) ;
if ( IsNull( pCrvExt) || ! pCrvExt->IsValid())
return false ;
// 3.2) scorro tutte le curve cambiando la TmpProp1 se necessario
for ( int u = 0 ; u < pCrvExt->GetCurveCount() ; ++ u) {
// 3.2.1) ricavo la curva u-esima
PtrOwner<ICurve> pCrv_u( pCrvExt->GetCurve( u)->Clone()) ;
if ( IsNull( pCrv_u) || ! pCrv_u->IsValid())
return false ;
// 3.2.2) continuo solo se è aperta
if ( pCrv_u->GetTempProp( 0) != 1)
continue ;
// 3.2.3) classifico la curva con la FlatRegion ricavata dal grezzo
CRVCVECTOR ccClass ;
if ( pSfrRawCheck->GetCurveClassification( *pCrv_u, 1500 * EPS_SMALL, ccClass)) {
if (( int)ccClass.size() == 1 && ccClass[0].nClass == CRVC_IN) {
// 3.2.4) se interna, cambio le TmpProps
pCrvExt->SetCurveTempProp( u, -2, 1) ;
// 3.2.5) aggiorno il Flag
bChanged = true ;
}
}
}
// 3.3) aggiungo il loopEsterno modificato
SfrBC_Final.AddCurve( Release( pCrvExt)) ;
// 3.4) aggiungo eventuali isole
for ( int l = 1 ; l < pSfr->GetLoopCount( c) ; ++ l)
SfrBC_Final.AddCurve( pSfr->GetLoop( c, l)) ;
}
// 4) se non ho modificato nulla, allora esco
if ( ! bChanged)
return true ;
// 5) altrimenti sostituisco la FlatRegion
PtrOwner<ISurfFlatRegion> pSfrFinal( SfrBC_Final.GetSurf()) ;
if ( ! IsNull( pSfrFinal) && pSfrFinal->IsValid()) {
pSfr->Clear() ;
pSfr->CopyFrom( pSfrFinal) ;
}
// 6) controllo validità
return pSfr != nullptr && pSfr->IsValid() && pSfr->GetChunkCount() != 0 ;
}
//----------------------------------------------------------------------------
bool
Pocketing::CalcRegionElevation( const ICurveComposite* pCompo, const Vector3d& vtTool, double dDepth, double dRad,
double& dElev) const
{
// inizializzo l'elevazione
dElev = 0 ;
// affondamento come vettore
Vector3d vtDepth = vtTool * dDepth ;
// Offsetto la curva della quantità stabvilità per la ricerca di proiezioni
OffsetCurve OffsCrv ;
if ( ! OffsCrv.Make( pCompo, m_dMaxLenRawProj, ICurve::OFF_FILLET)) {
m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ;
return false ;
}
PtrOwner<ICurveComposite> pCompoExtended( ConvertCurveToComposite( OffsCrv.GetLongerCurve())) ;
if ( IsNull( pCompoExtended) || ! pCompoExtended->IsValid())
return false ;
// Campiono il contorno
int nMaxInd = pCompoExtended->GetCurveCount() - 1 ;
for ( int i = 0 ; i <= nMaxInd ; ++ i) {
// curva corrente
const ICurve* pCrvC = pCompoExtended->GetCurve( i) ;
Point3d ptStart ; pCrvC->GetStartPoint( ptStart) ;
Point3d ptMid ; pCrvC->GetMidPoint( ptMid) ;
Point3d ptEnd ; pCrvC->GetEndPoint( ptEnd) ;
// elevazione della curva
double dCurrElev ;
if ( GetElevation( m_nPhase, ptStart - vtDepth, ptMid - vtDepth, ptEnd - vtDepth, vtTool, dCurrElev)) {
if ( dCurrElev > dElev)
dElev = dCurrElev ;
}
else {
m_pMchMgr->SetLastError( 2408, "Error in Pocketing : Entity GetElevation") ;
return false ;
}
}
// Campiono l'interno con una griglia (uso linee parallele a X)
// determino il riferimento di base
Frame3d frPocket ;
Point3d ptCen ; pCompoExtended->GetCentroid( ptCen) ;
frPocket.Set( ptCen, vtTool) ;
// copio il contorno e lo porto nel riferimento
PtrOwner<ICurveComposite> pCompoL( pCompoExtended->Clone()) ;
if ( IsNull( pCompoL) || ! pCompoL->ToLoc( frPocket)) {
m_pMchMgr->SetLastError( 2408, "Error in Pocketing : Entity GetElevation") ;
return false ;
}
// ingombro del contorno in locale
BBox3d b3Pocket ;
pCompoL->GetLocalBBox( b3Pocket) ;
Point3d ptMin ; double dDimX, dDimY, dDimZ ;
b3Pocket.GetMinDim( ptMin, dDimX, dDimY, dDimZ) ;
// passi in Y
const double STEP = m_TParams.m_dDiam ;
int nYStep = max( int( ceil( ( dDimY - 20 * EPS_SMALL) / STEP)), 2) ;
double dYStep = ( nYStep > 0 ? ( dDimY - 20 * EPS_SMALL) / nYStep : 0) ;
// calcolo le linee di svuotatura
for ( int i = 1 ; i < nYStep ; ++ i) {
// definisco la linea
PtrOwner<ICurveLine> pLine( CreateCurveLine()) ;
const double EXP_LEN = 1.0 ;
Point3d ptStart( ptMin.x - EXP_LEN, ptMin.y + 10 * EPS_SMALL + i * dYStep, ptMin.z + dDimZ) ;
if ( IsNull( pLine) || ! pLine->SetPVL( ptStart, X_AX, dDimX + 2 * EXP_LEN)) {
m_pMchMgr->SetLastError( 2408, "Error in Pocketing : Entity GetElevation") ;
return false ;
}
// calcolo la classificazione della curva rispetto al contorno
IntersCurveCurve intCC( *pLine, *pCompoL) ;
CRVCVECTOR ccClass ;
if ( intCC.GetCurveClassification( 0, EPS_SMALL, ccClass)) {
// determino gli intervalli di curva interni
Intervals inOk ;
for ( auto& ccOne : ccClass) {
if ( ccOne.nClass == CRVC_IN) {
// ricavo punto iniziale e finale
Point3d ptStart ;
pLine->GetPointD1D2( ccOne.dParS, ICurve::FROM_PLUS, ptStart) ;
Point3d ptEnd ;
pLine->GetPointD1D2( ccOne.dParE, ICurve::FROM_MINUS, ptEnd) ;
// calcolo la distanza tra questi due punti
double dDist = Dist( ptStart, ptEnd) ;
// il tratto interno lo campiono rispetto ad X
for ( int j = 0 ; j <= int( dDist / STEP) + 1 ; ++ j) {
Point3d ptCurr ;
pLine->GetPointD1D2( ccOne.dParS + j * ( ccOne.dParE - ccOne.dParS) / ( dDist / STEP + 1), ICurve::FROM_PLUS, ptCurr) ;
ptCurr.ToGlob( frPocket) ;
double dCurrElev ;
if ( GetElevation( m_nPhase, ptCurr - vtDepth, vtTool, dCurrElev)) {
if ( dCurrElev > dElev)
dElev = dCurrElev ;
}
else {
m_pMchMgr->SetLastError( 2408, "Error in Pocketing : Entity GetElevation") ;
return false ;
}
}
}
}
}
// altrimenti uso tutta la curva
else {
Point3d ptStart ;
pLine->GetStartPoint( ptStart) ;
ptStart.ToGlob( frPocket) ;
Point3d ptEnd ;
pLine->GetEndPoint( ptEnd) ;
ptEnd.ToGlob( frPocket) ;
// elevazione della curva
double dCurrElev ;
if ( GetElevation( m_nPhase, ptStart - vtDepth, ptEnd - vtDepth, vtTool, dCurrElev)) {
if ( dCurrElev > dElev)
dElev = dCurrElev ;
}
else {
m_pMchMgr->SetLastError( 2408, "Error in Pocketing : Entity GetElevation") ;
return false ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::VerifyPathFromBottom( const ISurfFlatRegion* pSrfPock, const Vector3d& vtTool)
{
// se non è svuotatura dal basso in alto, esco
if ( vtTool.z > MIN_ZDIR_TOP_TOOL)
return true ;
// se c'è testa non dall'alto o tavola basculante, esco
if ( ! m_bAboveHead || m_bTiltingTab)
return true ;
// recupero dati di eventuale rinvio da sotto
if ( ! GetAggrBottomData( m_TParams.m_sHead, m_AggrBottom) || m_AggrBottom.nType == 0) {
m_pMchMgr->SetLastError( 2409, "Error in Pocketing : missing aggregate from bottom") ;
return false ;
}
// calcolo il minimo della massima distanza del percorso dal contorno del grezzo
double dMinDist = INFINITO ;
Vector3d vtMinDir ;
VCT3DVECTOR vDir ;
for ( int c = 0 ; c < pSrfPock->GetChunkCount() ; c++) {
for ( int l = 0 ; l < pSrfPock->GetLoopCount( c) ; l++) {
PtrOwner<ICurveComposite> pCompo( GetCurveComposite( pSrfPock->GetLoop( c, l))) ;
if ( IsNull( pCompo))
return false ;
double dParS, dParE ; pCompo->GetDomain( dParS, dParE) ;
for ( double dPar = dParS ; dPar < dParE + EPS_PARAM ; dPar += 0.5) {
// distanza minima del punto e relativa direzione dal contorno del grezzo
Point3d ptP ; double dCurrDist = INFINITO ; Vector3d vtCurrDir ;
if ( pCompo->GetPointD1D2( dPar, ICurve::FROM_MINUS, ptP) &&
GetMinDistanceFromRawSide( m_nPhase, ptP, 0, m_AggrBottom.vtMDir, MCH_AGB_DELTAMAX_MDIR, dCurrDist, vtCurrDir) &&
! vtCurrDir.IsSmallXY()) {
if ( dCurrDist < dMinDist - 10 * EPS_SMALL &&
find_if( vDir.begin(), vDir.end(), [&]( const Vector3d& vtV) { return vtCurrDir * vtV > cos(15 * DEGTORAD); }) == vDir.end()) {
// inserisco la direzione tra quelle già esplorate
vDir.emplace_back( vtCurrDir) ;
// determino la distanza di tutti gli altri punti dal contorno del grezzo lungo questa direzione
for ( double dPar2 = dParS; dPar2 < dParE + EPS_PARAM; dPar2 += 0.5) {
if ( abs( dPar2 - dPar) > EPS_PARAM) {
Point3d ptQ ;
double dQDist ;
if ( pCompo->GetPointD1D2( dPar2, ICurve::FROM_MINUS, ptQ) &&
GetDistanceFromRawSide( m_nPhase, ptQ, vtCurrDir, dQDist) && dQDist > dCurrDist)
dCurrDist = dQDist ;
}
}
// se la massima distanza trovata è inferiore al minimo, lo aggiorno
if ( dCurrDist < dMinDist) {
dMinDist = dCurrDist ;
vtMinDir = vtCurrDir ;
}
}
}
}
}
}
// se supera il limite, errore
if ( dMinDist > m_AggrBottom.dDMax) {
m_pMchMgr->SetLastError( 2410, "Error in Pocketing : path too far from part sides") ;
return false ;
}
// assegno direzione di accesso e segnalo utilizzo aggregato da sotto
m_vtAggrBottom = vtMinDir ;
m_bAggrBottom = true ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GeneratePocketingPv( int nPathId, const ISurfFlatRegion* pSrfPock)
{
// creo copia della curva composita
PtrOwner<ISurfFlatRegion> pSfr( CloneSurfFlatRegion( pSrfPock)) ;
if ( IsNull( pSfr))
return false ;
// ne recupero il contorno
PtrOwner< ICurve> pCrv2 ;
pCrv2.Set( pSfr->GetLoop( 0, 0)) ;
if ( IsNull( pCrv2))
return false ;
// inserisco la curva nel DB
int nC2Id = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pCrv2)) ;
if ( nC2Id == GDB_ID_NULL)
return false ;
// assegno nome e colore
m_pGeomDB->SetName( nC2Id, MCH_PV_CUT) ;
m_pGeomDB->SetMaterial( nC2Id, RED) ;
// eventuali altri contorni ( interni di contornatura chiusa)
const int MAX_INT_LOOP = 1000 ;
for ( int i = 1 ; i <= MAX_INT_LOOP ; ++i) {
PtrOwner< ICurve> pCrv3 ;
pCrv3.Set( pSfr->GetLoop( 0, i)) ;
if ( IsNull( pCrv3))
break ;
// inserisco la curva nel DB
int nC3Id = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pCrv3)) ;
if ( nC3Id == GDB_ID_NULL)
return false ;
// assegno nome e colore
m_pGeomDB->SetName( nC3Id, MCH_PV_CUT) ;
m_pGeomDB->SetMaterial( nC3Id, RED) ;
}
// inserisco la regione nel DB
int nRId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pSfr)) ;
if ( nRId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nRId, MCH_PV_RCUT) ;
m_pGeomDB->SetMaterial( nRId, Color( 255, 0, 0, 60)) ;
// la copio anche come regione ridotta
int nRrId = m_pGeomDB->Copy( nRId, GDB_ID_NULL, nPathId) ;
if ( nRrId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nRrId, MCH_PV_RRCUT) ;
m_pGeomDB->SetMaterial( nRrId, INVISIBLE) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::CheckSelectedId( ) {
// se non ho almeno due Id selezionati, allora esco
if (( int)m_vId.size() <= 1)
return true ;
// Controllo Tra gli Id Selezionati se ho una Trimesh
// NB. Il primo Id selezionato ( o i primi Id selezionati nel caso di curve) rapprensentano la geometria che
// voglio svuotare; cerco, se presente, una TriMesh dopo l'indice 0
for ( int i = 1 ; i < ( int)m_vId.size() ; ++ i) {
int nCurrId = m_vId[i].nId ;
// recupero l'oggetto geometrico associato a tale Id
const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( nCurrId) ;
if ( pGObj == nullptr)
return false ;
// se tale oggetto esiste ed è una TriMesh, allora rappresenta il risultato della svuotatura voluto
if ( pGObj->GetType() == SRF_TRIMESH)
return DetectShape( nCurrId, GLOB_FRM) ;
}
return true ;
}
//----------------------------------------------------------------------------
static double
GetCurveRadius( const ICurve* pCrv)
{
if ( pCrv == nullptr)
return 0.0 ;
BBox3d b3Loc ;
if ( ! pCrv->GetLocalBBox( b3Loc, BBF_EXACT))
return 0.0 ;
double dRad ;
if ( ! b3Loc.GetRadius( dRad))
return 0.0 ;
return dRad ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AddZigZag( const ISurfFlatRegion* pSrfPock, const Vector3d& vtTool, const Vector3d& vtExtr,
double dDepth, double dMaxElev, double dElev, double dOkStep, bool bSplitArcs)
{
// recupero distanze di sicurezza
double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ;
double dSafeAggrBottZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeAggrBottZ() ;
// lunghezza di approccio/retrazione
double dAppr = m_Params.m_dStartPos ;
// determino numero e affondamento degli step
int nStep = 1 ;
nStep = max( 1, static_cast<int>( ceil( dElev / dOkStep))) ;
double dStep = dElev / nStep ;
// raggio utensile
double dTRad = m_TParams.m_dDiam / 2 ;
// Offset della regione per curva ZigZag
double dOffs = dTRad + GetOffsR() ;
double dExtra = (( m_TParams.m_nType != TT_MILL_POLISHING) ? min( 0.1 * m_TParams.m_dDiam, 2.0) : 0) ;
// inizializzazione delle informazioni necessarie per eventuale superficie uguale per lo step successivo
const int CRV_BORDER = 1 ;
struct CrvInfo {
PtrOwner<ICurveComposite> pCrvCompo ;
int nCrvType = 0 ;
Point3d ptStart = ORIG ;
bool bMidOut = false ;
Vector3d vtMidOut = V_NULL ;
int nChunk ;
} ;
struct ChunkInfo {
bool bOptZigZag = false ;
int nOptClosedSides = 0 ;
bool bOptTwoOpposite = false ;
Frame3d frFrame = GLOB_FRM ;
double dOptZigZagOffs = 0. ;
} ;
// ciclo su tutti i chunks della superificie originale
for ( int c = 0 ; c < pSrfPock->GetChunkCount() ; ++ c) {
// copio il chunk c-esimo
PtrOwner<ISurfFlatRegion> pSrfChunk(( pSrfPock->CloneChunk( c))) ;
if ( IsNull( pSrfChunk))
return false ;
ISURFFRPOVECTOR vSrfSliced( nStep) ; // vettore delle superficie ricavate ( per ogni step)
vector<ICRVCOMPOPOVECTOR> vCrvOEWithFlags( nStep) ; // vettore delle relative curve originali ( per ogni step)
BOOLVECTOR vbChangedPrec( nStep, false) ; // vettore di Flag per superfici uguali tra steps consecutivi
VCT3DVECTOR vVtTrasl( nStep, V_NULL) ; // vettore contenente le quote per le passate di svuotature
// modifico il Chunk (c)-esimo in base alla geometria
if ( ! GetParamsAtEachStep( vSrfSliced, vCrvOEWithFlags, vbChangedPrec, vVtTrasl, pSrfChunk,
nStep, vtTool, dElev, dDepth, dStep))
return false ;
// dichiarazione vettori info per steps
vector<CrvInfo> vCrvInfo ;
vector<ChunkInfo> vChunkInfo ;
// ciclo su tutti gli step
for ( int j = 1 ; j <= nStep ; ++j) {
// se superificie non valida, salto allo step successivo
if ( IsNull( vSrfSliced[ j-1]) || vSrfSliced[j-1]->GetChunkCount() == 0) {
vSrfSliced[j-1].Set( pSrfChunk->Clone()) ;
continue ;
}
PtrOwner<ISurfFlatRegion> pSrfFinal( CloneSurfFlatRegion( vSrfSliced[j - 1])) ;
if ( IsNull( pSrfFinal))
return false ;
// superficie per ingressi ed uscite
PtrOwner<ISurfFlatRegion> pSrfLeanInOut( CloneSurfFlatRegion( pSrfFinal)) ;
if ( IsNull( pSrfLeanInOut))
return false ;
// se la superficie è cambiata ( o sono al primo step), reset dei parametri step precedente e ricalcolo
if ( vbChangedPrec[j-1] || j == 1) {
vCrvInfo.clear() ;
vChunkInfo.clear() ;
vChunkInfo.resize( vSrfSliced[j-1]->GetChunkCount()) ;
// ciclo su tutti i chunk della superificie ( chunk (cc)-esimo per lo step (j)-esimo)
for ( int cc = 0 ; cc < vSrfSliced[j-1]->GetChunkCount() ; ++cc) {
// copio il Chunk (cc)-esimo allo step (j)-esimo
PtrOwner<ISurfFlatRegion> pSrfChunkFinal(( vSrfSliced[j-1]->CloneChunk( cc))) ;
if ( IsNull( pSrfChunkFinal))
return false ;
// cerco la curva originale del chunk (cc)-esimo ( per casi ottimizzati)
int nInd = 0 ; // indice del vettore delle curve esterne relativo al chunk (cc)-esimo
if ( ! GetOptCrvIndex( vCrvOEWithFlags, j, pSrfChunkFinal, nInd))
return false ;
// determino il riferimento in base alla svuotatura ( per poter orientare il frame per m_dSideAngle)
Frame3d frPocket ;
Point3d ptCen ; pSrfChunkFinal->GetCentroid( ptCen) ;
frPocket.Set( ptCen, vtExtr) ;
frPocket.Rotate( ptCen, vtExtr, m_Params.m_dSideAngle) ;
// porto la superificie nel nuovo sistema di riferimento
pSrfChunkFinal->ToLoc( frPocket) ;
// verifico se si tratta di caso ottimizzato
bool bOptimizedZigZag = false ;
ICRVCOMPOPOVECTOR vpCrvs ; // vettore con i paths a ZigZag per il Chunk (cc)-esimo allo step (j)-esimo
ICRVCOMPOPOVECTOR vCrvIslMergeBorders ; // vettore delle possibili isole mergiate per il Chunk (cc)-esimo allo step (j)-esimo
double dOptZigZagOffs = 0. ; // Offset per uscita dal grezzo nel caso di ottimizzazione
int nClosedSides = 0 ; // se caso ottimizzato, numero di lati chiusi
bool bTwoOpposite = false ; // se caso otimizzato, flag per lati chiusi opposti
if ( ! OptimizedZigZag( pSrfChunkFinal, vtTool, dDepth, dSafeZ, frPocket, vCrvOEWithFlags[j-1][nInd],
bOptimizedZigZag, vpCrvs, vCrvIslMergeBorders, dOptZigZagOffs, nClosedSides,
bTwoOpposite))
return false ;
// aggiorno le informazioni sul chunk attuale ( potrebbero essere usate per il successivo)
vChunkInfo[cc].bOptZigZag = bOptimizedZigZag ;
vChunkInfo[cc].nOptClosedSides = nClosedSides ;
vChunkInfo[cc].bOptTwoOpposite = bTwoOpposite ;
vChunkInfo[cc].frFrame = frPocket ;
vChunkInfo[cc].dOptZigZagOffs = dOptZigZagOffs ;
// se caso ottimizzato e vettore di curve ZigZag valido
if ( bOptimizedZigZag) {
vCrvInfo.resize( int( vpCrvs.size()) + int( vCrvIslMergeBorders.size())) ;
// aggiorno le curve per lo step attuale ( potrebbero essere usate per il successivo)
for ( int x = 0 ; x < int( vpCrvs.size()) ; ++ x) {
/*
CrvInfo myCrvInfo ;
myCrvInfo.pCrvCompo.Set( vpCrvs[x]->Clone()) ;
Point3d ptS ;
myCrvInfo.pCrvCompo->GetStartPoint( ptS) ;
myCrvInfo.ptStart = ptS ;
myCrvInfo.nChunk = cc ;
vCrvInfo.emplace_back( myCrvInfo) ;
*/
vCrvInfo[x].pCrvCompo.Set( vpCrvs[x]->Clone()) ;
Point3d ptS ;
vCrvInfo[x].pCrvCompo->GetStartPoint( ptS) ;
vCrvInfo[x].ptStart = ptS ;
vCrvInfo[x].nChunk = cc ;
}
// creo localmente i parametri della funzione
VCT3DVECTOR vVtMidOut(( int)vCrvIslMergeBorders.size()) ;
BOOLVECTOR vbMidOut(( int)vCrvIslMergeBorders.size()) ;
PNTVECTOR vPtStart(( int)vCrvIslMergeBorders.size()) ;
// se la superficie è cambiata, allora ricalcolo i parametri
for ( int x = 0 ; x < int( vCrvIslMergeBorders.size()) ; ++ x) {
// se richisto, inverto
if ( m_Params.m_bInvert)
vCrvIslMergeBorders[x]->Invert() ;
// setto la Feed per la curva di contorno
AssignFeedForEdgeCleaning( vCrvIslMergeBorders[x], vCrvOEWithFlags[j-1], nInd) ;
if ( vCrvIslMergeBorders[x]->IsClosed()) {
bool bOutTmp = false ;
if ( ! SetBetterPtStartForSubChunks( vCrvIslMergeBorders[x], pSrfChunkFinal,
vPtStart[x], vVtMidOut[x], bOutTmp))
return false ;
vbMidOut[x] = bOutTmp ; // vector<bool>::reference da Bit a Bool
}
else {
vCrvIslMergeBorders[x]->GetStartPoint( vPtStart[x]) ;
vbMidOut[x] = false ; // migliorabile
vVtMidOut[x] = V_NULL ; // migliorabile
}
}
// guardo il punto finale in cui si trova la fresa dopo al percorso a ZigZag
// e riordino le curve ( e i relativi vettori) in base alla vicinanza
// ( piccola ottimizzazione per l'ordine dei percorsi sui bordi )
Point3d ptEnd ;
if ( vpCrvs.size() > 0)
vpCrvs.back()->GetEndPoint( ptEnd) ;
if ( int( vCrvIslMergeBorders.size()) != 0 &&
! OrderCurvesByLastPntOfPath( vCrvIslMergeBorders, ptEnd, vPtStart, vVtMidOut, vbMidOut))
return false ;
int nOff_index = int( vCrvInfo.size()) ;
for ( int x = 0 ; x < int( vCrvIslMergeBorders.size()) ; ++ x) {
vCrvInfo[nOff_index + x].pCrvCompo.Set( Release( vCrvIslMergeBorders[x])) ;
vCrvInfo[nOff_index + x].nCrvType = CRV_BORDER ;
vCrvInfo[nOff_index + x].ptStart = vPtStart[x] ;
vCrvInfo[nOff_index + x].bMidOut = vbMidOut[x] ;
vCrvInfo[nOff_index + x].vtMidOut = vVtMidOut[x] ;
vCrvInfo[nOff_index + x].nChunk = cc ;
}
}
// se caso non ottimizzato
else {
// effettuo il primo Offset della regione e controllo quanti Chunks ottengo...
// l'Offset contiene una quantità Extra, per stare leggermente più staccato dal bordo
PtrOwner<ISurfFlatRegion> pSrfZigZag( CloneSurfFlatRegion( pSrfChunkFinal)) ;
if ( ! pSrfZigZag->Offset( - dOffs - dExtra, ICurve::OFF_FILLET)) {
m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ;
return false ;
}
// effettuo un secondo Offset per ottenere le curve di contorno per ripulire la svuotatura a ZigZag
// Questo offset serve per ricavare le curve che l'utensile dovrà percorrere dopo aver svuotato a ZigZag
// Curva esterna ( non percorsa nel caso a ZigZag ottimizzato)
// Curve interne ( le isole, queste vanno percorse anche nei casi ottimizzati)
// Per le curve interne, questo Offset viene sempre fatto ( a prescindere dai casi ottimizzati )
PtrOwner<ISurfFlatRegion> pSrfForCrv( CloneSurfFlatRegion( pSrfChunkFinal)) ;
if ( ! pSrfForCrv->Offset( - dOffs, ICurve::OFF_FILLET)) {
m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ;
return false ;
}
// Avendo effettuato due Offsets ( -dOffs-dExtra e -dOffs ) non è detto che il numero di Chunks tra le nuove
// superifici sia uguale... Inizio a scorre i chunks della superficie per le curve di contorno e,
// per ognuna di esse, cerco il/i Chunck per il percorso a ZigZag contenuti.
for ( int cfc = 0 ; cfc < pSrfForCrv->GetChunkCount() ; ++ cfc) { // scorro i chunk della superificie per i bordi
for ( int cfz = 0 ; cfz < pSrfZigZag->GetChunkCount() ; ++ cfz) { // scorro i chunk della superificie per i percorsi ZigZag
// e la regione è dentro al Chunk per i contorni
if ( pSrfZigZag->GetChunkSimpleClassification( cfz, *pSrfForCrv, cfc) == REGC_IN1) {
// svuoto il vettore delle curve ( potrebbe essere riempito dal percorso precedente
vpCrvs.clear() ;
// Calcolo il percorso a ZigZag
PtrOwner<ISurfFlatRegion> pSrfZigZagChunk( pSrfZigZag->CloneChunk( cfz)) ;
if ( ! CalcZigZag( pSrfZigZagChunk, vpCrvs))
return false ;
// memorizzo le curve ( per lo step successivo)
int nIndex_offs = int( vCrvInfo.size()) ;
vCrvInfo.resize( int( vpCrvs.size()) + nIndex_offs) ;
for ( int x = 0 ; x < int( vpCrvs.size()) ; ++ x) {
vCrvInfo[ nIndex_offs + x].pCrvCompo.Set( Release( vpCrvs[x])) ;
vCrvInfo[ nIndex_offs + x].nChunk = cc ;
}
}
// se la regione non è dentro alla curva esterna allora la ignoro
// ( la ritroverò interna ad un'altra curva per i bordi successivamante o l'ho già considerata in precedenza)
else
continue ;
}
// se lucidatura non aggiungo contorno
if ( m_TParams.m_nType == TT_MILL_POLISHING)
continue ;
// Una volta percorse le curve di ZigZag devo aggiungere le curve per il bordo
// creo un vettore con tutti i loop formati, aggiustando i loro punti iniziali
// e portandoli nel frame della svuotatura
ICRVCOMPOPOVECTOR vAllCrv ;
VCT3DVECTOR vVtMidOut( pSrfForCrv->GetLoopCount( cfc)) ;
BOOLVECTOR vbMidOut( pSrfForCrv->GetLoopCount( cfc)) ;
PNTVECTOR vPtStart( pSrfForCrv->GetLoopCount( cfc)) ;
for ( int l = 0 ; l < pSrfForCrv->GetLoopCount( cfc) ; ++ l) {
PtrOwner<ICurveComposite> pCrvLoop( ConvertCurveToComposite( pSrfForCrv->GetLoop( cfc, l))) ;
if ( IsNull( pCrvLoop))
return false ;
bool bOutTmp = false ;
if ( ! SetBetterPtStartForSubChunks( pCrvLoop, pSrfChunkFinal,
vPtStart[l], vVtMidOut[l], bOutTmp))
return false ;
vbMidOut[l] = bOutTmp ; // vector<bool>::reference da Bit a Bool
// se richiesto, la inverto
if ( m_Params.m_bInvert)
pCrvLoop->Invert() ;
// setto la Feed per la curva di contorno
AssignFeedForEdgeCleaning( pCrvLoop, vCrvOEWithFlags[j-1], nInd) ;
// inserisco la curva nel vettore
vAllCrv.emplace_back( Release( pCrvLoop)) ;
}
// guardo il punto finale in cui si trova la fresa dopo al percorso a ZigZag
// e le riordino le curve ( e i relativi vettori ) in base alla vicinanza
// ( piccola ottimizzazione per l'ordine dei percorsi sui bordi )
Point3d ptEnd ;
if ( vpCrvs.size() > 0)
vCrvInfo.back().pCrvCompo->GetEndPoint( ptEnd) ;
// riordino le curve
if ( ! OrderCurvesByLastPntOfPath( vAllCrv, ptEnd, vPtStart, vVtMidOut, vbMidOut))
return false ;
int nIndex_offs = int( vCrvInfo.size()) ;
vCrvInfo.resize( int( vAllCrv.size()) + nIndex_offs) ;
for ( int x = 0 ; x < int( vAllCrv.size()) ; ++ x) {
vCrvInfo[ nIndex_offs + x].pCrvCompo.Set( Release( vAllCrv[x])) ;
vCrvInfo[ nIndex_offs + x].nCrvType = CRV_BORDER ;
vCrvInfo[ nIndex_offs + x].bMidOut = vbMidOut[x] ;
vCrvInfo[ nIndex_offs + x].ptStart = vPtStart[x] ;
vCrvInfo[ nIndex_offs + x].vtMidOut = vVtMidOut[x] ;
}
}
}
}
}
// disegno a seconda del tipo di curva che ho ricavato
for ( int u = 0 ; u < int( vCrvInfo.size()) ; ++ u) {
// prendo la curva corrente
PtrOwner<ICurveComposite> pCrvCurr( vCrvInfo[u].pCrvCompo->Clone()) ;
if ( IsNull( pCrvCurr))
return false ;
// recupero il frame attuale e porto la curva in globale
Frame3d frCurr = vChunkInfo[vCrvInfo[u].nChunk].frFrame ;
pCrvCurr->ToGlob( frCurr) ;
// flag per LeadIn fuori/dentro al grezzo
bool bOutRawLeadIn = false ;
// determino l'affondamento attuale
double dSink = dElev - dDepth + dMaxElev - vVtTrasl[j-1].Len() ;
// =================== CURVA PERCORSO ZIGZAG ==============================================
if ( vCrvInfo[u].nCrvType == 0) {
// se caso ottimizzato
bool bOptZigZag = vChunkInfo[vCrvInfo[u].nChunk].bOptZigZag ;
if ( bOptZigZag) {
// recupero l'Offset ottimizzato precedentemente calcolato
double dOffsOpt = vChunkInfo[vCrvInfo[u].nChunk].dOptZigZagOffs ;
// recupero il numero di lati chiusi
int nClosedSide = vChunkInfo[vCrvInfo[u].nChunk].nOptClosedSides ;
// recupero flat di due lati chiusi paralleli
bool bOptTwoOpposite = vChunkInfo[vCrvInfo[u].nChunk].bOptTwoOpposite ;
// se un lato chiuso
if ( nClosedSide == 1) {
// inverto il percorso
pCrvCurr->Invert() ;
// verifico se attacco fuori dal grezzo
Point3d ptStart ;
pCrvCurr->GetStartPoint( ptStart) ;
Vector3d vtDir ;
pCrvCurr->GetStartDir( vtDir) ;
Point3d ptTest = ptStart + ( - vtDir) *
( m_TParams.m_dDiam / 2 - dOffsOpt + dSafeZ) ;
ptTest += - vtTool * dDepth ;
double dTestElev ;
// se è nel grezzo provo a ruotare di 90 gradi
if ( GetElevation( m_nPhase, ptTest, vtTool,
m_TParams.m_dDiam / 2 - dOffsOpt, vtTool,
dTestElev) && dTestElev > EPS_SMALL) {
Vector3d vtDirO = vtDir ;
vtDirO.Rotate( vtTool, ( m_Params.m_bInvert ? -90 : 90)) ;
Point3d ptTestO = ptStart + vtDirO *
( m_TParams.m_dDiam / 2 - dOffsOpt + dSafeZ) ;
ptTestO += - vtTool * dDepth ;
double dTestElevO ;
// se è fuori dal grezzo uso inizio ruotato
if ( ! GetElevation( m_nPhase, ptTestO, vtTool,
m_TParams.m_dDiam / 2 - dOffsOpt,
vtTool, dTestElevO) || dTestElevO < EPS_SMALL) {
Point3d ptNewStart = ptStart + vtDirO ;
pCrvCurr->AddLine( ptNewStart, false) ;
}
}
}
// se due lati chiusi consecutivi o tre lati chiusi...
else if (( nClosedSide == 2 || nClosedSide == 3) && ! bOptTwoOpposite) {
// inverto il percorso
pCrvCurr->Invert() ;
// allungo opportunamente inizio e fine
Point3d ptStart ;
pCrvCurr->GetStartPoint( ptStart) ;
Vector3d vtDir ;
pCrvCurr->GetStartDir( vtDir) ;
vtDir.Rotate( frCurr.VersZ(), ( m_Params.m_bInvert ? -90 : 90)) ;
ptStart += vtDir ;
Point3d ptEnd ;
pCrvCurr->GetEndPoint( ptEnd) ;
ptEnd += OrthoCompo( ptStart - ptEnd, frCurr.VersX()) ;
pCrvCurr->AddLine( ptEnd, true) ;
pCrvCurr->AddLine( ptStart, false) ;
}
// estendo la fine del percorso
if ( ! ( nClosedSide == 3 && bOptTwoOpposite))
pCrvCurr->ExtendEndByLen( max( m_TParams.m_dDiam / 4 - dOffsOpt, 0.0)) ;
// aggiungo il tratto per l'entrata, verifico se attacco fuori dal grezzo
Point3d ptStart ;
pCrvCurr->GetStartPoint( ptStart) ;
Vector3d vtDir ;
pCrvCurr->GetStartDir( vtDir) ;
ptStart += -vtDir * ( m_TParams.m_dDiam / 2 - dOffsOpt + dSafeZ) ;
ptStart += -vtTool * dDepth ;
// controllo l'elevazione
double dTestElev ;
if ( ! GetElevation( m_nPhase, ptStart, vtTool, m_TParams.m_dDiam / 2, vtTool, dTestElev) ||
dTestElev < EPS_SMALL)
bOutRawLeadIn = true ;
// sistemo attacco ( per essere completamente fuori dal grezzo)
if ( bOutRawLeadIn || m_bOpenOutRaw)
pCrvCurr->ExtendStartByLen( m_TParams.m_dDiam / 2 - dOffsOpt + dSafeZ) ;
}
// se lucidatura
if ( m_TParams.m_nType == TT_MILL_POLISHING) {
// se attacco a scivolo
if ( GetLeadInType() == POCKET_LI_GLIDE) {
double dU;
pCrvCurr->GetParamAtLength( m_Params.m_dLiTang, dU) ;
pCrvCurr->AddJoint( dU) ;
Point3d ptStart ;
pCrvCurr->GetStartPoint( ptStart) ;
pCrvCurr->ModifyStart( ptStart + vtTool * m_Params.m_dLiElev) ;
}
// se uscita a scivolo
if ( GetLeadOutType() == POCKET_LO_GLIDE) {
double dLen, dU ;
pCrvCurr->GetLength( dLen) ;
pCrvCurr->GetParamAtLength( dLen - m_Params.m_dLoTang, dU) ;
pCrvCurr->AddJoint( dU) ;
Point3d ptEnd ;
pCrvCurr->GetEndPoint( ptEnd) ;
pCrvCurr->ModifyEnd( ptEnd + vtTool * m_Params.m_dLiElev) ;
}
}
// ---------------------------- Disegno le curve a ZigZag (vpCrv) -------------------------
bool bStart = true ;
// ciclo sulle curve elementari
int nMaxInd = pCrvCurr->GetCurveCount() - 1 ;
for ( int i = 0 ; i <= nMaxInd ; ++ i) {
// curva corrente
const ICurve* pCrvC = pCrvCurr->GetCurve( i) ;
// copio la curva e la traslo allo step richisto
PtrOwner<ICurve> pCurve( pCrvC->Clone()) ;
if ( IsNull( pCurve))
return false;
pCurve->Translate( vVtTrasl[j-1]) ;
// --- se PRIMA ENTITA' ---
if ( i == 0) {
// dati inizio entità
Point3d ptStart ;
pCurve->GetStartPoint( ptStart) ;
Vector3d vtStart ;
pCurve->GetStartDir( vtStart) ;
// determino inizio attacco
Point3d ptP1 ;
if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, nullptr, ptP1))
return false ;
// determino elevazione su inizio attacco
double dStElev = dSink ;
dStElev -= ( ptP1 - ptStart) * vtExtr ;
// se ottimizzata e attacco nel grezzo
if ( bOptZigZag && !( bOutRawLeadIn || m_bOpenOutRaw)) {
// se richiesto attacco a zigzag o a spirale, l'elevazione va nell'attacco
if ( GetLeadInType() == POCKET_LI_ZIGZAG || GetLeadInType() == POCKET_LI_HELIX) {
ptP1 += vtExtr * dStElev ;
dStElev = 0 ;
}
}
// se inizio, approccio globale al punto iniziale
if ( bStart) {
if ( ! AddApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, bOutRawLeadIn || m_bOpenOutRaw)) {
m_pMchMgr->SetLastError( 2414, "Error in Pocketing : Approach not computable") ;
return false ;
}
bStart = false ;
}
// altrimenti, approccio di collegamento
else {
if ( ! ( nStep > 1 && j > 1 && bOutRawLeadIn && bOptZigZag)) {
if ( ! AddLinkApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, bOutRawLeadIn || m_bOpenOutRaw)) {
m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ;
return false ;
}
}
}
// aggiungo attacco
SetFeed( GetStartFeed()) ;
if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrfLeanInOut, nullptr, !m_Params.m_bInvert,
bSplitArcs, bOutRawLeadIn || m_bOpenOutRaw)) {
m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ;
return false ;
}
}
// elaborazioni sulla curva corrente
double dMinFeed = GetFeed() * GetSideStep() / m_TParams.m_dDiam ;
double dFeed = pCurve->GetTempProp( 0) / FEED_DIVISOR < dMinFeed - 50 * EPS_SMALL ?
GetFeed() : pCurve->GetTempProp( 0) / FEED_DIVISOR ;
SetFeed( dFeed) ;
if ( pCurve->GetType() == CRV_LINE) {
ICurveLine* pLine = GetCurveLine( pCurve) ;
Point3d ptP3 = pLine->GetEnd() ;
if ( AddLinearMove( ptP3) == GDB_ID_NULL)
return false ;
}
else if ( pCurve->GetType() == CRV_ARC) {
ICurveArc* pArc = GetCurveArc( pCurve) ;
Point3d ptCen = pArc->GetCenter() ;
double dAngCen = pArc->GetAngCenter() ;
Vector3d vtN = pArc->GetNormVersor() ;
Point3d ptP3 ;
pArc->GetEndPoint(ptP3) ;
if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL)
return false ;
}
// --- se ULTIMA ENTITA' ---
if ( i == nMaxInd) {
// dati fine entità
Point3d ptEnd ;
pCurve->GetEndPoint( ptEnd) ;
Vector3d vtEnd ;
pCurve->GetEndDir( vtEnd) ;
// aggiungo uscita
double dEndElev = dSink ;
Point3d ptP1 ;
SetFeed( GetEndFeed()) ;
if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, nullptr, bSplitArcs, true, ptP1, dEndElev, false)) {
m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ;
return false ;
}
// se lucidatura o caso ottimizzato e ultimo percorso di ultimo step, aggiungo retrazione
if (( m_TParams.m_nType == TT_MILL_POLISHING || bOptZigZag) && j == nStep) {
if ( ! AddRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) {
m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Retract not computable") ;
return false ;
}
}
// altrimenti, aggiungo retrazione di collegamento
else {
if ( ! AddLinkRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) {
m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ;
return false ;
}
}
}
}
}
// =================== CURVA BORDO ESTERNO ==============================================
else {
bool bForcedOutStart = false ;
// se la curva è valida per entrata da fuori, aggiungo un piccolo tratto lineare
if ( vCrvInfo[u].bMidOut) {
// calcolo il punto fuori
Point3d ptOut = vCrvInfo[u].ptStart + vCrvInfo[u].vtMidOut * ( 0.5 * m_TParams.m_dDiam + dSafeZ) ;
ptOut.ToGlob( frCurr) ;
ptOut.Translate( vVtTrasl[j-1]) ;
double dStElev ;
bool bOutStart = ( ! GetElevation( m_nPhase, ptOut, vtTool, 0.5 * m_TParams.m_dDiam, vtTool, dStElev) ||
dStElev < EPS_SMALL) ;
if ( bOutStart || m_bOpenOutRaw) {
// aggiungo alla curva il tratto lineare
ptOut.Translate( - vVtTrasl[j-1]) ;
pCrvCurr->AddLine( ptOut, false) ;
AssignFeedForLineInOut( pCrvCurr, true) ;
}
// verifico se ingresso da considerare fuori grezzo anche se dentro
bForcedOutStart = ( vCrvInfo[u].bMidOut && m_bOpenOutRaw) ;
// se utensile che non lavora di testa e ingresso non fuori dal pezzo, errore
if ( m_TParams.m_nType == TT_MILL_NOTIP && !bOutStart && ! bForcedOutStart) {
if ( ! LeadInRawIsOk()) {
m_pMchMgr->SetLastError( 2431, "Error in Pocketing : LeadIn with Mill NoTip in material") ;
return false;
}
}
}
// ----- disegno le curve di contorno -------------------
// aggiungo la lavorazione di questa curva
Point3d ptP1 ;
// ciclo sulle curve elementari
int nMaxInd = pCrvCurr->GetCurveCount() - 1 ;
for ( int i = 0 ; i <= nMaxInd ; ++i) {
// curva corrente
const ICurve* pCrvC = pCrvCurr->GetCurve( i) ;
// copio la curva
PtrOwner<ICurve> pCurve( pCrvC->Clone()) ;
if ( IsNull( pCurve))
return false ;
// traslo nello step richiesto
pCurve->Translate( vVtTrasl[j-1]) ;
// --- se PRIMA ENTITA' ---
if ( i == 0) {
// dati inizio entità
Point3d ptStart ;
Vector3d vtStart ;
pCurve->GetStartPoint( ptStart) ;
pCurve->GetStartDir( vtStart) ;
// se primo step, approccio e affondo
// determino inizio attacco
if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, nullptr, ptP1))
return false ;
// determino elevazione su inizio attacco
double dStElev = dSink ;
dStElev -= ( ptP1 - ptStart) * vtExtr ;
// se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco
if ( GetLeadInType() == POCKET_LI_ZIGZAG ||
GetLeadInType() == POCKET_LI_HELIX ||
GetLeadInType() == POCKET_LI_GLIDE) {
ptP1 += vtExtr * dStElev ;
dStElev = 0 ;
}
// approccio al punto iniziale
if ( ! AddLinkApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr,
vCrvInfo[u].bMidOut || bForcedOutStart)) {
m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ;
return false ;
}
// aggiungo attacco
SetFeed( GetStartFeed()) ;
if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrfLeanInOut, nullptr, !m_Params.m_bInvert,
bSplitArcs, vCrvInfo[u].bMidOut || bForcedOutStart)) {
m_pMchMgr->SetLastError(2415, "Error in Pocketing : LeadIn not computable");
return false;
}
}
// elaborazioni sulla curva corrente
double dMinFeed = GetFeed() * GetSideStep() / m_TParams.m_dDiam ;
double dFeed = pCurve->GetTempProp( 0) / FEED_DIVISOR < dMinFeed - 50 * EPS_SMALL ?
GetFeed() : pCurve->GetTempProp( 0) / FEED_DIVISOR ;
SetFeed( dFeed) ;
if ( pCurve->GetType() == CRV_LINE) {
ICurveLine* pLine( GetCurveLine( pCurve)) ;
Point3d ptP3 = pLine->GetEnd() ;
if ( AddLinearMove( ptP3) == GDB_ID_NULL)
return false ;
}
else if ( pCurve->GetType() == CRV_ARC) {
ICurveArc* pArc( GetCurveArc( pCurve)) ;
Point3d ptCen = pArc->GetCenter() ;
double dAngCen = pArc->GetAngCenter() ;
Vector3d vtN = pArc->GetNormVersor() ;
Point3d ptP3 ;
pArc->GetEndPoint( ptP3) ;
if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL)
return false ;
}
// se ultima entità
if ( i == nMaxInd) {
// se ultimo step, uscita e retrazione di collegamento
// dati fine entità
Point3d ptEnd ;
pCurve->GetEndPoint( ptEnd) ;
Vector3d vtEnd ;
pCurve->GetEndDir( vtEnd) ;
// aggiungo uscita
double dEndElev = dSink ;
SetFeed( GetEndFeed()) ;
if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, nullptr, bSplitArcs, false, ptP1, dEndElev, ( u == ( int)vCrvInfo.size()))) {
m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ;
return false ;
}
// se ci sono ancora curve, aggiungo retrazione di collegamento
if ( pCrvCurr->GetCurveCount() > 0) {
if ( ! AddLinkRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) {
m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ;
return false ;
}
}
// altrimenti retrazione finale
else {
if ( ! AddRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) {
m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Retract not computable") ;
return false ;
}
}
}
}
}
} // fine ciclo sulle curve da disegnare
} // fine ciclo sugli step
} // fine ciclo sui chunk della superficie originale ( prima di operazioni con il grezzo
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::CalcZigZag( const ISurfFlatRegion* pSrfZigZag, ICRVCOMPOPOVECTOR& vpCrvs)
{
// check parametri
if ( pSrfZigZag == nullptr)
return true ;
// creo il vettore dei contorni
ICRVCOMPOPOVECTOR vFirstOff ;
for ( int c = 0 ; c < pSrfZigZag->GetChunkCount() ; ++ c) { // sempre 1...
for ( int l = 0 ; l < pSrfZigZag->GetLoopCount( c) ;++ l) {
vFirstOff.emplace_back( GetCurveComposite( pSrfZigZag->GetLoop( c, l))) ;
}
}
// ingombro del contorno offsettato
BBox3d b3Pocket ;
vFirstOff[0]->GetLocalBBox( b3Pocket) ;
Point3d ptMin ; double dDimX, dDimY, dDimZ ;
b3Pocket.GetMinDim( ptMin, dDimX, dDimY, dDimZ) ;
// lunghezza del contorno offsettato
double dLen ; vFirstOff[0]->GetLength( dLen) ;
// passi in Y
int nYStep = static_cast< int >( ceil(( dDimY - 30 * EPS_SMALL) / GetSideStep())) ;
double dYStep = ( nYStep > 0 ? ( dDimY - 30 * EPS_SMALL) / nYStep : 0) ;
int nRef = (( nYStep + ( m_Params.m_bInvert ? 0 : 1)) % 2) ;
// tratto valido
struct Section {
bool bActive ;
Point3d ptS ;
Point3d ptE ;
double dOs ;
double dOe ;
int nOffIndS ;
int nOffIndE ;
} ;
struct ParIsland {
double dU ;
int nInd ;
} ;
// raccolta di tratti
typedef vector<vector<Section>> VECVECSECT ; VECVECSECT vvSec ;
vvSec.resize( nYStep + 1) ;
// calcolo le linee di svuotatura
int nCount = 0 ;
for ( int i = 0 ; i <= nYStep ; ++ i) {
// determino senso
bool bPlus = (( i % 2) == nRef) ;
// definisco la linea
PtrOwner<ICurveLine> pLine( CreateCurveLine()) ;
const double EXP_LEN = 1.0 ;
Point3d ptStart( ptMin.x - EXP_LEN, ptMin.y + 10 * EPS_SMALL + i * dYStep, ptMin.z + dDimZ) ;
if ( IsNull( pLine) || ! pLine->SetPVL( ptStart, X_AX, dDimX + 2 * EXP_LEN)) {
m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ;
return false ;
}
if ( ! bPlus)
pLine->Invert() ;
// calcolo la classificazione della linea rispetto alla superificie
CRVCVECTOR ccClass ;
pSrfZigZag->GetCurveClassification( *pLine, EPS_SMALL, ccClass) ;
for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) {
if ( ccClass[j].nClass == CRVC_IN) { // memorizzo il segmento
Section currSec;
currSec.bActive = true;
PtrOwner<ICurveLine> pSeg( GetCurveLine( pLine->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE))) ;
Point3d ptS, ptE ;
pSeg->GetStartPoint( ptS) ; pSeg->GetEndPoint( ptE) ;
currSec.ptS = ptS ; currSec.ptE = ptE ;
for ( int k = 0 ; k < int( vFirstOff.size()) ; ++ k) {
if ( vFirstOff[k]->IsPointOn( ptS)) {
currSec.nOffIndS = k ;
double dUOS; vFirstOff[k]->GetParamAtPoint( ptS, dUOS) ;
currSec.dOs = dUOS ;
}
if ( vFirstOff[k]->IsPointOn( ptE)){
currSec.nOffIndE = k ;
double dUOE; vFirstOff[k]->GetParamAtPoint( ptE, dUOE) ;
currSec.dOe = dUOE ;
}
}
vvSec[i].emplace_back( currSec) ;
++nCount ; // numero di segmenti inseriti
}
}
}
int nStatus = 0 ; // 0 -> inizio oppure ho inserito una parte di isola | 2 -> sto inserendo un segmento
Point3d ptS_ref ;
PtrOwner<ICurveComposite> pLastSeg( CreateCurveComposite()) ; // ultimo segmento nel percorso
PtrOwner<ICurveComposite> pCrvLink( CreateCurveComposite()) ; // ultimo link aggiunto
// vettore dei link aggiunti ( per Feed )
ICRVCOMPOPOVECTOR vAddedLinks ;
bool bFirstLine = true ; // flag per prima linea di ogni percorso
// creo i percorsi di svuotatura
vpCrvs.reserve( nCount) ;
int nI = -1, nJ = -1 ;
while ( true) {
// se sezione non valida
if ( nI < 0 || nJ < 0) {
// ricerco la prima valida ( il primo segmento con bActive messo a true)
for ( int k = 0 ; k < int( vvSec.size()) && nI < 0 ; ++ k) {
for ( int l = 0 ; l < int( vvSec[k].size()) && nJ < 0 ; ++ l) {
if ( vvSec[k][l].bActive) {
nI = k ;
nJ = l ;
}
}
}
// se trovata, creo nuova curva composita
if ( nI >= 0 && nJ >= 0) {
// creo la curva
vpCrvs.emplace_back( CreateCurveComposite()) ;
nStatus = 0 ;
// aggiungo punto iniziale
vpCrvs.back()->AddPoint( vvSec[nI][nJ].ptS) ;
bFirstLine = true ;
}
// altrimenti, esco
else
break ;
}
// determino senso
bool bPlus = (( nI % 2) == nRef) ;
// aggiungo la sezione alla curva
Section& Sec = vvSec[nI][nJ] ;
Sec.bActive = false ;
// creo i vettori con le linee Under e Above nella struttura della Section
ICURVEPOVECTOR vLineAbove ;
if ( nI < nYStep) {
for ( int a = 0 ; a < ( int)vvSec[nI + 1].size() ; ++ a) {
if ( vvSec[nI + 1][a].bActive)
continue ;
PtrOwner<ICurveLine> pLA( CreateCurveLine()) ;
pLA->Set( vvSec[nI + 1][a].ptS, vvSec[nI + 1][a].ptE) ;
vLineAbove.emplace_back( Release( pLA)) ;
}
}
ICURVEPOVECTOR vLineUnder ;
if ( nI > 0) {
for ( int u = 0 ; u < ( int)vvSec[nI - 1].size() ; ++ u) {
if ( vvSec[ nI - 1][u].bActive)
continue ;
PtrOwner<ICurveLine> pLU( CreateCurveLine()) ;
pLU->Set( vvSec[nI - 1][u].ptS, vvSec[nI - 1][u].ptE) ;
vLineUnder.emplace_back( Release( pLU)) ;
}
}
// creo la linea come curva composita, aggiungerò dei Joint per ogni tratto con Feed differente
PtrOwner<ICurveComposite> pLineCompo( CreateCurveComposite()) ;
if ( IsNull( pLineCompo))
return false ;
Point3d ptE_l ;
if ( bFirstLine)
ptE_l = vvSec[nI][nJ].ptS ;
else
vpCrvs.back()->GetEndPoint( ptE_l) ;
pLineCompo->AddPoint( ptE_l) ;
pLineCompo->AddLine( vvSec[nI][nJ].ptE) ;
if ( ! AssignFeedZigZagOneWay( pLineCompo, false, vLineAbove, vLineUnder, vAddedLinks)) // Assegno la Feed
return false ;
bFirstLine = false ;
vpCrvs.back()->AddCurve( pLineCompo->Clone()) ; // aggiungo la curva al percorso
if ( nStatus == 0) { // primo segmento per il raccordo smussato
pLastSeg.Set( pLineCompo) ;
pLastSeg->GetStartPoint( ptS_ref) ;
}
if ( nStatus == 2) { // ho precedentemente aggiunto il bordo di un'isola, quindi mi salvo il secondo segmento
PtrOwner<ICurveComposite> pSeg1( CloneCurveComposite( pLastSeg)) ;
PtrOwner<ICurveComposite> pSeg2( CloneCurveComposite( pLineCompo)) ;
if ( ! CalcZigZagLink( pSeg1, pSeg2, pCrvLink))
return false ;
// aggiorno il vettore delle curve ZigZag
Point3d ptE_Seg1 ;
pSeg1->GetEndPoint( ptE_Seg1) ;
double dUS_Link = EPS_SMALL ;
vpCrvs.back()->GetParamAtPoint( ptE_Seg1, dUS_Link) ;
if ( ! vpCrvs.back()->TrimEndAtParam( dUS_Link))
vpCrvs.back()->Clear() ;
if ( ! AssignFeedZigZagOneWay( pCrvLink, true, vLineAbove, vLineUnder, vAddedLinks))
return false ;
vpCrvs.back()->AddCurve( pCrvLink->Clone()) ; // aggiungo il Link
vpCrvs.back()->AddCurve( pSeg2->Clone()) ; // aggiungo pSeg2
// aggiorno il vettore dei Link ( nel caso sia un link tra due segmenti sullo stesso livello )
Point3d ptS1 ;
pSeg1->GetStartPoint( ptS1) ;
Point3d ptS2 ;
pSeg2->GetStartPoint( ptS2) ;
if ( abs( ptS1.y - ptS2.y) < 50 * EPS_SMALL)
vAddedLinks.emplace_back( pCrvLink->Clone()) ;
// pSeg2 ora diventa pSeg1 e il procedimento si itera per tutto il percorso
pLastSeg.Set( Release( pSeg2)) ;
}
// cerco nella stessa fila o in quella successiva sezione successiva raccordabile tramite il contorno
double dUstart = Sec.dOe ;
int nIndexIslandE = Sec.nOffIndE ; // isola di arrivo
double dUmin, dUmax ;
vFirstOff[nIndexIslandE]->GetDomain( dUmin, dUmax) ;
double dUspan = dUmax - dUmin ;
double dUref = ( bPlus ? INFINITO : -INFINITO) ;
int nNextI = -1 ;
int nNextJ = -1 ;
int li = nJ + 1 ;
for ( int k = nI ; k <= nI + 1 && k < int( vvSec.size()) ; ++ k) {
for ( int l = li ; l < int( vvSec[k].size()) ; ++ l) {
if ( ! vvSec[k][l].bActive) // se sezione non attiva... non la considero
continue ;
if ( vvSec[k][l].nOffIndS != nIndexIslandE) // se isola diversa... non la considero
continue ;
double dU = vvSec[k][l].dOs ;
if ( bPlus) {
if ( dU < dUstart)
dU += dUspan ;
if ( dU < dUref) {
dUref = dU ;
nNextI = k ;
nNextJ = l ;
}
}
else {
if ( dU > dUstart)
dU -= dUspan ;
if ( dU > dUref) {
dUref = dU ;
nNextI = k ;
nNextJ = l ;
}
}
}
li = 0 ;
}
// se trovato, controllo il contorno dell'isola
if ( nNextI != -1) {
PtrOwner<ICurve> pCopy ;
if ( bPlus) {
if ( dUref > dUmax)
dUref -= dUspan ;
pCopy.Set( vFirstOff[nIndexIslandE]->CopyParamRange( dUstart, dUref)) ;
if ( ! IsNull( pCopy)) {
double dCLen ; pCopy->GetLength( dCLen) ;
if ( dCLen > 0.5 * dLen) {
pCopy.Set( vFirstOff[nIndexIslandE]->CopyParamRange( dUref, dUstart)) ;
if ( ! IsNull( pCopy))
pCopy->Invert() ;
}
}
}
else {
if ( dUref < dUmin)
dUref += dUspan ;
pCopy.Set( vFirstOff[nIndexIslandE]->CopyParamRange( dUref, dUstart)) ;
if ( ! IsNull( pCopy)) {
pCopy->Invert() ;
double dCLen; pCopy->GetLength( dCLen) ;
if ( dCLen > 0.5 * dLen)
pCopy.Set( vFirstOff[nIndexIslandE]->CopyParamRange( dUstart, dUref)) ;
}
}
// controllo che nel percorso scelto non ritorni indietro superando la precendete passata
BBox3d b3Copy ;
if ( ! IsNull( pCopy))
pCopy->GetLocalBBox( b3Copy) ;
if ( ! b3Copy.IsEmpty() && ( b3Copy.GetMax().y - b3Copy.GetMin().y) < dYStep + 10 * EPS_SMALL) { // tengo la curva (non ritorno indietro più dello step)
Point3d ptS, ptE ;
pCrvLink->Clear() ;
pCrvLink->AddCurve( pCopy->Clone()) ;
vpCrvs.back()->AddCurve( Release( pCopy)) ;
nStatus = 2 ; // aggiunta parte di isola
// aggiungo il Link
nI = nNextI ;
nJ = nNextJ ;
}
else {
nI = -1 ;
nJ = -1 ;
}
}
else {
nI = -1 ;
nJ = -1 ;
}
}
return true ;
}
//----------------------------------------------------------
bool
Pocketing::GetUnclearedRegion( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vCrvs, ICURVEPOVECTOR& vLinks,
const ICurveComposite* pCrv_orig, ISurfFlatRegion* pSrfToCut)
{
// controllo dei parametri
if ( vFirstOffs.size() == 0 || ( int)vCrvs.size() < ( int)vFirstOffs.size())
return false ;
pSrfToCut->Clear() ;
// 1) creo la regione esterna
PtrOwner<ISurfFlatRegion> pSrfExtern( CreateSurfFlatRegion()) ;
if ( IsNull( pSrfExtern))
return false ;
for ( int i = 0 ; i < int( vFirstOffs.size()) ; ++ i) {
if ( i == 0)
pSrfExtern->AddExtLoop( vFirstOffs[i]->Clone()) ;
else {
PtrOwner<ICurve> pCrvIntLoop( vFirstOffs[i]->Clone()) ;
if( IsNull( pCrvIntLoop) || ! pCrvIntLoop->Invert() || ! pSrfExtern->AddIntLoop( pCrvIntLoop->Clone()))
return false ;
}
}
// ---- le seguenti regioni sono distinte per calcolar emeglio la Feed ----
// 2) Creo la regione svuotata dal Tool negli Offset, nei Links e sia dagli Offsets che dai Links
PtrOwner<ISurfFlatRegion> pSrfTool_Offs( CreateSurfFlatRegion()) ;
PtrOwner<ISurfFlatRegion> pSrfTool_Links( CreateSurfFlatRegion()) ;
PtrOwner<ISurfFlatRegion> pSrfTool( CreateSurfFlatRegion()) ;
if ( IsNull( pSrfTool_Offs) || IsNull( pSrfTool_Links) || IsNull( pSrfTool))
return false ;
// creo un vettore che conterrà solamente i Link percorsi fino ad Ora
ICRVCOMPOPOVECTOR vLinks_done ;
for ( int i = m_Params.m_nSubType == POCKET_SUB_SPIRALIN ? 0 : ( int)vCrvs.size() - 1 ;
m_Params.m_nSubType == POCKET_SUB_SPIRALIN ? i < int( vCrvs.size()) : i >= 0 ;
m_Params.m_nSubType == POCKET_SUB_SPIRALIN ? ++ i : -- i) {
// ================= LINK ================================
if ( i <= ( int)vLinks.size() && ! IsNull( vLinks[i]) && vLinks[i]->IsValid()) {
// Feed
PtrOwner<ICurveComposite> pCompoLink_i( CreateCurveComposite()) ;
if ( IsNull( pCompoLink_i))
return false ;
pCompoLink_i->AddCurve( vLinks[i]->Clone()) ;
if ( ! AssignFeedSpiral( pCompoLink_i, pSrfTool_Offs, true, vLinks_done, pCrv_orig, m_TParams.m_dDiam / 3))
return false ;
// per Link ...
PtrOwner<ICurve> pCrvLink_i( vLinks[i]->Clone()) ;
if ( IsNull( pCrvLink_i))
return false ;
PtrOwner<ISurfFlatRegion> pSrfToolRegLinki( GetSurfFlatRegionFromFatCurve( Release( pCrvLink_i), m_TParams.m_dDiam / 2 + 5 * EPS_SMALL, false, false)) ;
if ( ! IsNull( pSrfToolRegLinki)) {
if ( ! pSrfTool_Links->IsValid() || pSrfTool_Links->GetChunkCount() == 0)
pSrfTool_Links.Set( pSrfToolRegLinki) ;
else
pSrfTool_Links->Add( *pSrfToolRegLinki) ;
}
// risetto il Link come curva composita ...
vLinks[i].Set( pCompoLink_i->Clone()) ;
// inserisco il Link nel vettore dei Link percorsi
vLinks_done.emplace_back( Release( pCompoLink_i)) ;
}
// ================== OFFSET =============================
// Feed
if ( ! AssignFeedSpiral( vCrvs[i], pSrfTool_Offs, false, vLinks_done, pCrv_orig, m_TParams.m_dDiam / 3))
return false ;
// aggiorno la superificie svuotata
PtrOwner<ICurveComposite> pCrvOffs_i( CloneCurveComposite( vCrvs[i])) ;
if ( IsNull( pCrvOffs_i))
return false ;
PtrOwner<ISurfFlatRegion> pSrfToolRegOffi( GetSurfFlatRegionFromFatCurve( Release( pCrvOffs_i) , m_TParams.m_dDiam / 2 + 5 * EPS_SMALL, false, false)) ;
if ( ! IsNull( pSrfToolRegOffi)) {
if ( ! pSrfTool_Offs->IsValid() || pSrfTool_Offs->GetChunkCount() == 0)
pSrfTool_Offs.Set( Release( pSrfToolRegOffi)) ;
else
pSrfTool_Offs->Add( *pSrfToolRegOffi) ;
}
}
// 3) Calcolo la superificie svuotata
pSrfTool.Set( pSrfTool_Offs) ;
pSrfTool->Add( *pSrfTool_Links) ;
// 4) Creo la regione contenente tutte le parti non svuotate
pSrfToCut->CopyFrom( pSrfExtern) ;
if ( ! pSrfToCut->Subtract( *pSrfTool))
return false ;
return true ;
}
//----------------------------------------------------------
bool
Pocketing::CalcZigZagLink( ICurveComposite* pCrv1, ICurveComposite* pCrv2, ICurveComposite* pCrvLink) {
// controllo dei parametri
if ( pCrv1 == nullptr || pCrv2 == nullptr)
return false ;
pCrvLink->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ;
// prendo i parametri per il raccordo
Vector3d vtS, vtE, vtH ;
pCrv1->GetEndDir( vtS) ;
pCrv2->GetStartDir( vtE) ;
Point3d ptS, ptE, ptE1, ptS2 ;
pCrv1->GetEndPoint( ptS) ;
pCrv2->GetStartPoint( ptE) ;
vtH = ptE - ptS ;
double dLen1, dLen2 ;
pCrv1->GetLength( dLen1) ;
pCrv2->GetLength( dLen2) ;
double dUS1, dUE1, dUS2, dUE2 ;
pCrv1->GetDomain( dUS1, dUE1) ;
pCrv2->GetDomain( dUS2, dUE2) ;
double dAngle, dAngleH ;
double dDist = Dist( ptS, ptE) ;
// curve per controllo validità del collegamento
PtrOwner<ICurveComposite> pCrvH1( CreateCurveComposite()) ;
PtrOwner<ICurveComposite> pCrvH2( CreateCurveComposite()) ;
PtrOwner<ICurveComposite> pCrvTempLink( CreateCurveComposite()) ;
PtrOwner<ICurveComposite> pCrvTest( CreateCurveComposite()) ;
if ( IsNull( pCrvH1) || IsNull( pCrvH2) || IsNull( pCrvTempLink) || IsNull( pCrvTest))
return false ;
if ( vtS.GetAngle( vtE, dAngle) &&
abs( dAngle) < ANG_STRAIGHT + 5 * EPS_SMALL && abs( dAngle) > ANG_STRAIGHT - 5 * EPS_SMALL &&
vtH.GetAngle( vtE, dAngleH) &&
abs( dAngleH) < ANG_RIGHT + 5 * EPS_SMALL && abs( dAngleH) > ANG_RIGHT - 5 * EPS_SMALL &&
dLen1 > dDist && dLen2 > dDist &&
pCrvLink->GetCurveCount() == 1 && pCrvLink->GetFirstCurve()->GetType() == CRV_LINE) {
// CREO UNA SEMICIRCONFERENZA
double dRad = dDist / 2 ; // raggio
Point3d ptNS, ptNE ;
pCrv1->GetParamAtLength( dLen1 - dRad, dUE1) ;
pCrv2->GetParamAtLength( dRad, dUS2) ;
pCrv1->GetPointD1D2( dUE1, ICurve::FROM_MINUS, ptNS) ; // parametro di intersezione su curva 1
pCrv2->GetPointD1D2( dUS2, ICurve::FROM_PLUS, ptNE) ; // parametro di intersezione su curva 2
PtrOwner<ICurveArc> pSemiCir( CreateCurveArc()) ;
if ( pSemiCir->Set2PVN( ptNS, ptNE, vtS, Z_AX)) {
pCrvH1.Set( GetCurveComposite( pCrv1->CopyParamRange( dUS1, dUE1))) ;
pCrvH2.Set( GetCurveComposite( pCrv2->CopyParamRange( dUS2, dUE2))) ;
pCrvTempLink->AddCurve( pSemiCir->Clone()) ;
}
// controllo finale sui raccordi ammissibili ...
if ( pCrvTest->AddCurve( pCrvH1->Clone()) && pCrvTest->AddCurve( pCrvTempLink->Clone()) &&
pCrvTest->AddCurve( pCrvH2->Clone())) {
if ( ! pCrv1->TrimEndAtParam( dUE1))
pCrv1->Clear() ;
pCrvLink->Clear() ;
pCrvLink->AddCurve( Release( pCrvTempLink)) ;
if ( ! pCrv2->TrimStartAtParam( dUS2))
pCrv2->Clear() ;
return true ;
}
}
else {
// DEVO SMUSSARE LA CURVA FORMATA DA pCrv1 - pCrvLink ( da creare) - pCrv2
pCrvH1->AddCurve( pCrv1->Clone()) ;
pCrvH2->AddCurve( pCrv2->Clone()) ;
pCrvTempLink->AddCurve( pCrvLink->Clone()) ;
// prendo le lunghezze necessarie
double dLenSeg1 = EPS_SMALL ; double dLenSeg2 = EPS_SMALL ;
double dLenI_s = EPS_SMALL ; // lunghezza prima curva del Link
double dLenI_e = EPS_SMALL ; // lunghezza ultima curva del Link
pCrvH1->GetLength( dLenSeg1) ;
pCrvH2->GetLength( dLenSeg2) ;
pCrvTempLink->GetFirstCurve()->GetLength( dLenI_s) ;
pCrvTempLink->GetLastCurve()->GetLength( dLenI_e) ;
// raccordo pSeg1 con pCrvLink
double dTollLeft = 1 - ( dLen1 - ( m_TParams.m_dTDiam / 16)) / dLen1 ; // % parametro sinistro per smusso
double dTollRight = ( m_TParams.m_dTDiam / 16) / dLenI_s ; // % parametro destro di smusso
PtrOwner<ICurveComposite> pCrv_Seg1_Isl( CreateCurveComposite()) ; // curva unione di pSeg1 e pCrvLink smussata
pCrv_Seg1_Isl->AddCurve( pCrvH1->Clone()) ;
pCrv_Seg1_Isl->AddCurve( pCrvTempLink->Clone()) ;
ModifyCurveToSmoothed( pCrv_Seg1_Isl, dTollLeft, dTollRight) ;
// raccordo questa curva con pSeg2
double dUS_1IH, dUE_1IH, dToTLen ;
pCrv_Seg1_Isl->GetDomain( dUS_1IH, dUE_1IH) ; // dominio della curva smussata tra pSeg1 e PCrvLink
pCrv_Seg1_Isl->GetLength( dToTLen) ; // nuova lunghezza della curva smussata tra pSeg1 e pCrvLink
dTollLeft = 1 - ( dLenI_e - ( m_TParams.m_dTDiam / 16)) / dLenI_e ; // % paramtro sinistro per smusso
dTollRight = ( m_TParams.m_dTDiam / 16) / dLen2 ; // % parametro destro per smusso
PtrOwner<ICurveComposite> pCrv_smoothed( CreateCurveComposite()) ; // curva unione del primo smusso con pSeg2
pCrv_smoothed->AddCurve( pCrv_Seg1_Isl->Clone()) ;
pCrv_smoothed->AddCurve( pCrvH2->Clone()) ;
ModifyCurveToSmoothed( pCrv_smoothed, dTollLeft, dTollRight) ;
// recupero i parametri del nuovo collegamento che si è creato dallo smusso
pCrvH1->Clear() ;
pCrvTempLink->Clear() ;
pCrvH2->Clear() ;
int nStat = -1 ;
for ( int u = 0 ; u < pCrv_smoothed->GetCurveCount() ; ++ u) {
// recupero la curva u-esima
const ICurve* pCrv = pCrv_smoothed->GetCurve( u) ;
if ( pCrv->GetType() == CRV_LINE) {
if ( CheckSimpleOverlap( pCrv, pCrv1, nStat, EPS_SMALL) && nStat == 1)
pCrvH1->AddCurve( pCrv->Clone()) ;
else if ( CheckSimpleOverlap( pCrv, pCrv2, nStat, EPS_SMALL) && nStat == 1)
pCrvH2->AddCurve( pCrv->Clone()) ;
}
}
Point3d ptCrv1_e, ptCrv2_s ;
double dULink_s = EPS_SMALL ;
double dULink_e = EPS_SMALL ;
pCrvH1->GetEndPoint( ptCrv1_e) ;
pCrv1->GetParamAtPoint( ptCrv1_e, dULink_s) ;
if ( ! pCrv1->TrimEndAtParam( dULink_s))
pCrv1->Clear() ;
pCrvH2->GetStartPoint( ptCrv2_s) ;
pCrv2->GetParamAtPoint( ptCrv2_s, dULink_e) ;
if ( ! pCrv2->TrimStartAtParam( dULink_e))
pCrv2->Clear() ;
pCrv_smoothed->GetParamAtPoint( ptCrv1_e, dULink_s) ;
pCrv_smoothed->GetParamAtPoint( ptCrv2_s, dULink_e) ;
pCrvLink->Clear() ;
pCrvLink->AddCurve( GetCurveComposite( pCrv_smoothed->CopyParamRange( dULink_s, dULink_e))) ;
return true ;
}
return false ;
}
//----------------------------------------------------------
bool
Pocketing::OptimizedZigZag( ISurfFlatRegion* pSrf, const Vector3d& vtTool, double dDepth, double dSafeZ,
Frame3d& frPocket, ICurveComposite* pCrvOrig, bool& bOptimizedZigZag,
ICRVCOMPOPOVECTOR& vpCrvs, ICRVCOMPOPOVECTOR& vCrvIslMergeBorders, double& dOffs,
int& nClosedSides, bool& bTwoOpposite)
{
// clono la superficie (chunk c-esimo dell'originale)
PtrOwner<ISurfFlatRegion> pSrfPocket( CloneSurfFlatRegion( pSrf)) ;
if ( IsNull( pSrfPocket))
return false ;
// recupero la curva ORIGINALE che delimita la svuotatura (questa curva non risente dell'offset fatto dalla superificie creata dopo)
PtrOwner<ICurveComposite> pCrvForId( GetCurveComposite( pSrfPocket->GetLoop( 0, 0))) ;
int nCrvId = pCrvForId->GetTempProp( 0) ;
PtrOwner<ICurveComposite> pCrvPocket( CloneCurveComposite( m_pGeomDB->GetGeoObj( nCrvId))) ;
bool bSrfOriIsCut = false ;
if ( IsNull( pCrvPocket)) {
pCrvPocket.Set( pCrvOrig->Clone()) ;
if ( IsNull( pCrvPocket) || pCrvPocket->GetCurveCount() == 0)
return true ;
bSrfOriIsCut = true ;
}
// porto la curva nel sistema di riferimento locale
pCrvPocket->ToLoc( frPocket) ;
m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvPocket->Clone()) ;
// setto proprietà sulle curve
if ( ! bSrfOriIsCut)
SetCurveAllTempProp( nCrvId, GetForcedClosed(), pCrvPocket) ;
pCrvPocket->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ;
// sistemo senso antiorario visto dalla direzione di estrusione
Vector3d vtPocket; pCrvPocket->GetExtrusion( vtPocket) ;
Plane3d plPlane ; double dArea ;
pCrvPocket->GetArea( plPlane, dArea) ;
if ( plPlane.GetVersN() * vtPocket * dArea < 0)
pCrvPocket->Invert() ;
// recupero gli id dei lati chiusi
INTVECTOR vnInfoClosed ;
for ( int i = 0 ; i < pCrvPocket->GetCurveCount() ; i ++) {
int nProp ;
if ( pCrvPocket->GetCurveTempProp( i, nProp) && nProp == 0)
vnInfoClosed.push_back( i) ;
}
nClosedSides = vnInfoClosed.size() ;
// modifico pCrvPocket per poterla passare a CalcZigZag
Vector3d vtDir ; // direzione principale del segmento più lungo (linea)
switch ( nClosedSides) {
case 0 : // 0 lati CHIUSI -> tutti APERTI
ZigZagOptimizedNoClosedEdges( pCrvPocket, bOptimizedZigZag, vtDir, dOffs) ;
break ;
case 1 : // 1 lato CHIUSO
ZigZagOptimizedOneClosedEdge( pCrvPocket, vnInfoClosed[0], bOptimizedZigZag, vtDir, dOffs) ;
break ;
case 2 : // 2 lati CHIUSI
ZigZagOptimizedTwoClosedEdges( pCrvPocket, vnInfoClosed, bOptimizedZigZag, bTwoOpposite, vtDir, dOffs) ;
break ;
case 3 : // 3 lati CHIUSI
ZigZagOptimizedThreeClosedEdges( pCrvPocket, vnInfoClosed, bOptimizedZigZag, bTwoOpposite, vtDir, dOffs) ;
break ;
default : // nessuna ottimizzazione...
bOptimizedZigZag = false ;
break ;
}
m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvPocket->Clone()) ;
// se non sono in un caso ottimizzato, allora esco
if ( ! bOptimizedZigZag)
return true ;
// frame per direzione più lunga per la svuotatura a ZigZag
if ( vtDir.IsZero())
pCrvPocket->GetStartDir( vtDir) ;
double dAng ;
vtDir.GetAngleXY( X_AX, dAng) ;
if ( nClosedSides == 0)
dAng += m_Params.m_dSideAngle ;
pCrvPocket->ToGlob( frPocket) ;
Frame3d frameH( frPocket) ;
Point3d ptCen = frPocket.Orig() ;
Vector3d vtExtr = frPocket.VersZ() ;
frPocket.Rotate( ptCen, vtExtr, -dAng) ;
pCrvPocket->ToLoc( frPocket) ;
// vettore contenente le curve di primo Offset ottimizzate ( bordo esterno Optimized e isole )
ICRVCOMPOPOVECTOR vFirstOffsets ;
vFirstOffsets.emplace_back( pCrvPocket->Clone()) ; // la curva esterna modificata
// parametri per Offset
double dTRad = m_TParams.m_dDiam / 2 ;
double dMyOffs = dTRad + GetOffsR() ;
double dExtra = (( m_TParams.m_nType != TT_MILL_POLISHING) ? min( 0.1 * m_TParams.m_dDiam, 2.0) : 0) ;
// Offsetto la superficie per ricavare informazioni su eventuali isole e sulle loro possibili unioni
PtrOwner<ISurfFlatRegion> pSrfPocketClone( CloneSurfFlatRegion( pSrfPocket)) ;
if ( IsNull( pSrfPocketClone))
return false ;
if ( ! pSrfPocketClone->Offset( - dMyOffs - dExtra, ICurve::OFF_FILLET)) { // le isole interne vanno Offsettate
m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ;
return false ;
}
// creo la superficie per svuotatura ZigZag
PtrOwner<ISurfFlatRegion> pSfrZigZag( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrZigZag) || ! pSfrZigZag->AddExtLoop( *pCrvPocket))
return false ;
// creo la superficie per le curve di bordo
PtrOwner<ISurfFlatRegion> pSfrForCrv( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrForCrv) || ! pSfrForCrv->AddExtLoop( *pCrvPocket))
return false ;
// creo una superficie come somma delle isole
PtrOwner<ISurfFlatRegion> pSfrToTIsl( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrToTIsl))
return false ;
// prendo i loop interni dalla superficie originale !
for ( int c = 0 ; c < pSrfPocket->GetChunkCount() ; ++ c) { // sempre 1... (?)
for ( int l = 1 ; l < pSrfPocket->GetLoopCount( c) ; ++ l) {
PtrOwner<ICurveComposite> pCrvIslLoop( ConvertCurveToComposite( pSrfPocket->GetLoop( c, l))) ;
if ( IsNull( pCrvIslLoop) || ! pCrvIslLoop->IsValid())
return false ;
pCrvIslLoop->ToGlob( frameH) ;
pCrvIslLoop->ToLoc( frPocket) ;
// creo la superficie dal bordo dell'isola
// ( NB. facendo l'offset di un'isola non è detto che ottengo una sola curva)
PtrOwner<ISurfFlatRegion> pSfrIslOff1( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrIslOff1) || ! pSfrIslOff1->AddExtLoop( *pCrvIslLoop))
return false ;
// per sottrarre devono essere coerenti
if ( AreOppositeVectorApprox( pSfrIslOff1->GetNormVersor(), pSfrZigZag->GetNormVersor()))
pSfrIslOff1->Invert() ;
PtrOwner<ISurfFlatRegion> pSfrIslOff2( CloneSurfFlatRegion( pSfrIslOff1)) ;
if ( IsNull( pSfrIslOff2))
return false ;
// Offset 1 ed Offset 2
if ( ! pSfrIslOff1->Offset( dMyOffs + dExtra, ICurve::OFF_FILLET) ||
! pSfrIslOff2->Offset( dMyOffs, ICurve::OFF_FILLET))
return false ;
// aggiorno la regione totale delle isole
if ( ! pSfrToTIsl->IsValid() || pSfrToTIsl->GetChunkCount() == 0)
pSfrToTIsl.Set( pSfrIslOff1->Clone()) ;
else
pSfrToTIsl->Add( *pSfrIslOff1) ;
// sottraggo
if ( ! pSfrZigZag->Subtract( *pSfrIslOff1) || ! pSfrForCrv->Subtract( *pSfrIslOff2)) {
if ( ! pSfrZigZag->Subtract( *pSfrIslOff1)) {
m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrZigZag->Clone()) ;
m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrIslOff1->Clone()) ;
}
else {
m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrForCrv->Clone()) ;
m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrIslOff2->Clone()) ;
}
return false ;
}
}
}
// calcolo il percorso di svuotatura
if ( ! CalcZigZag( pSfrZigZag, vpCrvs))
return false ;
// controllo se il Loop esterno ha cambiato area ( in questo caso si è unito con un'isola e tale
// bordo deve essere percorso
double dAreaPrec, dAreaAft ;
const ICurve* pCrvExtLoop = pSfrForCrv->GetLoop( 0, 0) ;
Plane3d plH ;
if ( ! pCrvPocket->GetArea( plH, dAreaPrec) ||
! pCrvExtLoop->GetArea( plH, dAreaAft))
return false ;
if ( abs( dAreaPrec - dAreaAft) > 5000 * EPS_SMALL) {
ICURVEPOVECTOR vCrv ;
ChainCurves ChainC ;
// il bordo esterno si è unito all'isola => devo percorrere la parte di bordo interna all'isola
for ( int c = 0 ; c < pSfrForCrv->GetChunkCount() ; ++ c) {
const ICurve* pCrvExt = pSfrForCrv->GetLoop( c, 0) ;
CRVCVECTOR ccClass ;
if ( ! pSfrToTIsl->GetCurveClassification( *pCrvExt, EPS_SMALL, ccClass))
return false ;
for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) {
if ( ccClass[j].nClass == CRVC_IN) {
// recupero il tratto interno
PtrOwner<ICurve> pCrv_In( pCrvExt->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ;
if ( ! IsNull( pCrv_In))
vCrv.emplace_back( Release( pCrv_In)) ;
}
}
if ( int( vCrv.size()) == 0)
continue ;
ChainC.Init( true, 10 * EPS_SMALL, int( vCrv.size())) ;
for ( int k = 0 ; k < int( vCrv.size()) ; ++ k) {
// recupero i dati della curva necessari al concatenamento e li assegno
Point3d ptStart, ptEnd ;
Vector3d vtStart, vtEnd ;
if ( ! vCrv[k]->GetStartPoint( ptStart) || ! vCrv[k]->GetStartDir( vtStart) ||
! vCrv[k]->GetEndPoint( ptEnd) || ! vCrv[k]->GetEndDir( vtEnd))
return false ;
ChainC.AddCurve( k + 1, ptStart, vtStart, ptEnd, vtEnd) ;
}
Point3d ptE ; vpCrvs.back()->GetEndPoint( ptE) ;
INTVECTOR vInds ;
while ( ChainC.GetChainFromNear( ptE, false, vInds)) {
PtrOwner<ICurveComposite> pCrvCompo_Curr( CreateCurveComposite()) ;
if ( IsNull( pCrvCompo_Curr))
return false ;
for ( int i = 0 ; i < int( vInds.size()) ; ++ i) {
if ( vInds[i] < 0)
vCrv[abs( vInds[i]) - 1]->Invert() ;
pCrvCompo_Curr->AddCurve( Release( vCrv[abs( vInds[i]) - 1])) ;
}
if ( ! IsNull( pCrvCompo_Curr) && pCrvCompo_Curr->IsValid())
vCrvIslMergeBorders.emplace_back( Release( pCrvCompo_Curr)) ;
}
}
}
// inserisco a prescindere tutte le isole
for ( int c = 0 ; c < pSfrForCrv->GetChunkCount() ; ++ c)
for ( int l = 1 ; l < pSfrForCrv->GetLoopCount( c) ; ++ l)
vCrvIslMergeBorders.emplace_back( ConvertCurveToComposite( pSfrForCrv->GetLoop( c, l))) ;
return true ;
}
//------------------------------------------------------------------
bool
Pocketing::ZigZagOptimizedNoClosedEdges( ICurveComposite* pCrvPocket, bool& bOptimizedZigZag, Vector3d& vtDir,
double& dOffs)
{
// individuo il segmento di retta più lungo
int nMax = -1 ;
double dMaxLen = 0 ;
for ( int i = 0 ; i < int( pCrvPocket->GetCurveCount()) ; ++ i) {
const ICurve* pCrv = pCrvPocket->GetCurve( i) ;
if ( pCrv->GetType() == CRV_LINE) {
double dLen = 0 ; pCrv->GetLength( dLen) ;
if ( dLen > dMaxLen) {
dMaxLen = dLen ;
nMax = i ;
}
}
}
if ( nMax == -1)
return true ;
pCrvPocket->GetCurve( nMax)->GetStartDir( vtDir) ;
// aggiorno pCrvPocket con eventuale offset per regioni residue
if ( ! ZigZagOptimizedComputeOffset( pCrvPocket, vtDir, 0, {}, dOffs))
return true ;
bOptimizedZigZag = true ;
return true ;
}
//------------------------------------------------------------------
bool
Pocketing::ZigZagOptimizedOneClosedEdge( ICurveComposite* pCrvPocket, int nClosedId, bool& bOptimizedZigZag, Vector3d& vtDir,
double& dOffs)
{
// verifico che il lato chiuso sia una linea
PtrOwner<ICurveLine> pCrv( CloneCurveLine( pCrvPocket->GetCurve( nClosedId))) ;
if ( IsNull( pCrv))
return true ;
// aggiorno pCrvPocket con eventuale offset per regioni residue
pCrv->GetStartDir( vtDir) ;
if ( ! ZigZagOptimizedComputeOffset( pCrvPocket, vtDir, 1, {nClosedId}, dOffs))
return true ;
// setto il vettore estrusione per eseguire correttamente offset
Vector3d vtExtr ;
pCrvPocket->GetExtrusion( vtExtr) ;
pCrv->SetExtrusion( vtExtr) ;
pCrv->SimpleOffset( -m_TParams.m_dDiam / 2 - GetOffsR() + 10 * EPS_SMALL) ;
pCrv->ExtendStartByLen( 300) ;
pCrv->ExtendEndByLen( 300) ;
// sarà la prima curva del percorso
if ( ! CutCurveWithLine( pCrvPocket, pCrv))
return false ;
bOptimizedZigZag = true ;
return true ;
}
//------------------------------------------------------------------
bool
Pocketing::ZigZagOptimizedTwoClosedEdges( ICurveComposite* pCrvPocket, const INTVECTOR& vnClosedIds, bool& bOptimizedZigZag,
bool& bOpposite, Vector3d& vtDir, double& dOffs)
{
// verifico che i lati chiusi siano linee
PtrOwner<ICurveLine> pCrv1( CloneCurveLine( pCrvPocket->GetCurve( vnClosedIds[0]))) ;
PtrOwner<ICurveLine> pCrv2( CloneCurveLine( pCrvPocket->GetCurve( vnClosedIds[1]))) ;
if ( IsNull( pCrv1) || IsNull( pCrv2))
return true ;
// verifico abbiano direzioni opposte
Vector3d vtDir1, vtDir2 ;
pCrv1->GetStartDir( vtDir1) ;
pCrv2->GetStartDir( vtDir2) ;
if ( AreOppositeVectorApprox( vtDir1, vtDir2))
bOpposite = true ;
else {
// verifico siano consecutive
Point3d ptStart1 ;
pCrv1->GetStartPoint( ptStart1) ;
Point3d ptEnd1 ;
pCrv1->GetEndPoint( ptEnd1) ;
Point3d ptStart2 ;
pCrv2->GetStartPoint( ptStart2) ;
Point3d ptEnd2 ;
pCrv2->GetEndPoint( ptEnd2) ;
if ( AreSamePointApprox( ptEnd1, ptStart2) || AreSamePointApprox( ptEnd2, ptStart1))
bOpposite = false ;
else
return true ;
}
// setto il vettore estrusione per eseguire correttamente offset
Vector3d vtExtr ;
pCrvPocket->GetExtrusion( vtExtr) ;
pCrv1->SetExtrusion( vtExtr) ;
pCrv2->SetExtrusion( vtExtr) ;
// determino la curva chiusa più lunga
double dLen1 ; pCrv1->GetLength( dLen1) ;
double dLen2 ; pCrv2->GetLength( dLen2) ;
// se non opposti, verifico che almeno una delle due sia corta
if ( ! bOpposite && dLen1 > 1.5 * m_TParams.m_dDiam && dLen2 > 1.5 * m_TParams.m_dDiam)
return true ;
// trovo la direzione principale della svuotatura
if ( dLen1 > dLen2)
pCrv1->GetStartDir( vtDir) ;
else
pCrv2->GetStartDir( vtDir) ;
// aggiorno pCrvPocket con eventuale offset per regioni residue
if ( ! ZigZagOptimizedComputeOffset( pCrvPocket, vtDir, bOpposite ? 2 : 1, vnClosedIds, dOffs))
return true ;
double dMyOffs = m_TParams.m_dDiam / 2 + GetOffsR() - 10 * EPS_SMALL ;
pCrv1->SimpleOffset( -dMyOffs) ;
pCrv1->ExtendStartByLen( 300) ;
pCrv1->ExtendEndByLen( 300) ;
if ( ! CutCurveWithLine( pCrvPocket, pCrv1))
return false ;
// sarà la prima curva del percorso
pCrv2->SimpleOffset( -dMyOffs) ;
pCrv2->ExtendStartByLen( 300) ;
pCrv2->ExtendEndByLen( 300) ;
if ( ! CutCurveWithLine( pCrvPocket, pCrv2))
return false ;
bOptimizedZigZag = true ;
return true ;
}
//------------------------------------------------------------------
bool
Pocketing::ZigZagOptimizedThreeClosedEdges( ICurveComposite* pCrvPocket, const INTVECTOR& vnClosedIds, bool& bOptimizedZigZag,
bool& bOpposite, Vector3d& vtDir,double& dOffs)
{
// verifico che i lati chiusi siano linee
PtrOwner<ICurveLine> pCrv1( CloneCurveLine( pCrvPocket->GetCurve( vnClosedIds[0]))) ;
PtrOwner<ICurveLine> pCrv2( CloneCurveLine( pCrvPocket->GetCurve( vnClosedIds[1]))) ;
PtrOwner<ICurveLine> pCrv3( CloneCurveLine( pCrvPocket->GetCurve( vnClosedIds[2]))) ;
if ( IsNull( pCrv1) || IsNull( pCrv2) || IsNull( pCrv3))
return true ;
// verifico siano consecutivi
Point3d ptStart1 ;
pCrv1->GetStartPoint( ptStart1) ;
Point3d ptEnd1 ;
pCrv1->GetEndPoint( ptEnd1) ;
Point3d ptStart2 ;
pCrv2->GetStartPoint( ptStart2) ;
Point3d ptEnd2 ;
pCrv2->GetEndPoint( ptEnd2) ;
Point3d ptStart3 ;
pCrv3->GetStartPoint( ptStart3) ;
Point3d ptEnd3 ;
pCrv3->GetEndPoint( ptEnd3) ;
if ( AreSamePointApprox( ptEnd1, ptStart2) && AreSamePointApprox( ptEnd2, ptStart3))
;
else if ( AreSamePointApprox( ptEnd2, ptStart3) && AreSamePointApprox( ptEnd3, ptStart1)) {
swap( pCrv1, pCrv2) ;
swap( pCrv2, pCrv3) ;
}
else if ( AreSamePointApprox( ptEnd3, ptStart1) && AreSamePointApprox( ptEnd1, ptStart2)) {
swap( pCrv1, pCrv3) ;
swap( pCrv3, pCrv2) ;
}
else
return true ;
// calcolo la direzione della svuotatura e verifico che lati non siano troppo lunghi
double dLen1 ; pCrv1->GetLength( dLen1) ;
double dLen2 ; pCrv2->GetLength( dLen2) ;
double dLen3 ; pCrv3->GetLength( dLen3) ;
if ( dLen2 > dLen1 && dLen2 > dLen3) {
if ( dLen1 > /*1.5 **/ m_TParams.m_dDiam / 2 + 5 * EPS_SMALL || dLen3 > /*1.5 **/ m_TParams.m_dDiam / 2 + 5 * EPS_SMALL)
return true ;
pCrv2->GetStartDir( vtDir) ;
bOpposite = false ;
}
else {
if ( dLen2 > /*1.5 **/ m_TParams.m_dDiam / 2 + 5 * EPS_SMALL)
return true ;
pCrv3->GetStartDir( vtDir) ;
bOpposite = true ;
}
// aggiorno pCrvPocket con eventuale offset per regioni residue
if ( ! ZigZagOptimizedComputeOffset( pCrvPocket, vtDir, 1, vnClosedIds, dOffs))
return true ;
// setto il vettore estrusione per eseguire correttamente offset
Vector3d vtExtr ;
pCrvPocket->GetExtrusion( vtExtr) ;
pCrv1->SetExtrusion( vtExtr) ;
pCrv2->SetExtrusion( vtExtr) ;
pCrv3->SetExtrusion( vtExtr) ;
double dMyOffs = m_TParams.m_dDiam / 2 + GetOffsR() - 10 * EPS_SMALL ;
pCrv1->SimpleOffset( - dMyOffs) ;
pCrv1->ExtendStartByLen( 300) ;
pCrv1->ExtendEndByLen( 300) ;
if ( ! CutCurveWithLine( pCrvPocket, pCrv1))
return false ;
pCrv3->SimpleOffset( -dMyOffs) ;
pCrv3->ExtendStartByLen( 300) ;
pCrv3->ExtendEndByLen( 300) ;
if ( ! CutCurveWithLine( pCrvPocket, pCrv3))
return false ;
// sarà la prima curva del percorso
pCrv2->SimpleOffset( -dMyOffs) ;
pCrv2->ExtendStartByLen( 300) ;
pCrv2->ExtendEndByLen( 300) ;
if ( ! CutCurveWithLine( pCrvPocket, pCrv2))
return false ;
bOptimizedZigZag = true ;
return true ;
}
//------------------------------------------------------------------
bool
Pocketing::ZigZagOptimizedComputeOffset( ICurveComposite* pCrvPocket, const Vector3d& vtMainDir, int nOffsettedEdgesOnY,
const INTVECTOR& vnClosedIds, double& dOffs)
{
// calcolo il side step che verr utilizzato in CalcZigZag
Frame3d frLoc ;
if ( ! frLoc.Set( ORIG, Z_AX, vtMainDir))
return true ;
BBox3d b3Loc ;
pCrvPocket->ToLoc( frLoc) ;
pCrvPocket->GetLocalBBox( b3Loc) ;
pCrvPocket->ToGlob( frLoc) ;
Point3d pt ;
double dDimX, dDimY, dDimZ ;
b3Loc.GetMinDim( pt, dDimX, dDimY, dDimZ) ;
// riduco la DimY della svuotatura in base al numero di lati chiusi che saranno offsettati lungo quella direzione
dDimY -= nOffsettedEdgesOnY * ( 0.5 * m_TParams.m_dDiam + GetOffsR()) ;
int nYStep = static_cast<int>( ceil( ( dDimY - 30 * EPS_SMALL) / GetSideStep())) ;
double dYSideStep = ( nYStep > 0 ? ( dDimY - 30 * EPS_SMALL) / nYStep : 0) ;
// individuo i lati vicini a quelli closed
for ( int i = 0 ; i < ( int)vnClosedIds.size() ; i ++) {
int nNext = vnClosedIds[i] == pCrvPocket->GetCurveCount() - 1 ? 0 : vnClosedIds[i] + 1 ;
int nPrev = vnClosedIds[i] == 0 ? pCrvPocket->GetCurveCount() - 1 : vnClosedIds[i] - 1 ;
pCrvPocket->SetCurveTempProp( nNext, 1, 1) ;
pCrvPocket->SetCurveTempProp( nPrev, 1, 1) ;
}
// verifico se resteranno aree residue e calcolo eventuale offset per pCrvPocket
dOffs = 0 ;
for ( int i = 0 ; i < pCrvPocket->GetCurveCount() ; i ++) {
double dOffsTmp = 0 ;
double dVal = 0 ;
if ( pCrvPocket->GetCurve(i)->GetType() == CRV_LINE) {
Vector3d vtDir ;
if ( ! pCrvPocket->GetCurve( i)->GetStartDir( vtDir))
return false ;
int nProp ;
pCrvPocket->GetCurveTempProp( i, nProp, 1) ;
double dLen ;
pCrvPocket->GetCurve( i)->GetLength( dLen) ;
if ( nProp == 1 && dLen > 1000 * EPS_SMALL) {
// gestione speciale se vicino al lato closed
double dCosAlpha = vtMainDir * vtDir ;
if ( abs( dCosAlpha) > EPS_SMALL && abs( dCosAlpha) < 1 - EPS_SMALL)
dOffsTmp = abs( 0.5 * m_TParams.m_dDiam * dCosAlpha) ;
}
else {
double dSinAlpha = ( vtMainDir ^ vtDir).Len() ;
if ( abs( dSinAlpha) > EPS_SMALL)
dVal = ( dYSideStep - 0.5 * m_TParams.m_dDiam) / dSinAlpha - 0.5 * m_TParams.m_dDiam ;
if ( dVal > EPS_SMALL) {
double dCosAlpha = vtMainDir * vtDir ;
dOffsTmp = abs( ( dYSideStep - 0.5 * m_TParams.m_dDiam) * dCosAlpha) ;
}
}
}
if ( dOffsTmp > dOffs)
dOffs = dOffsTmp ;
}
// aggiusto offset
double dMinOffs = max( 0., 0.5 * m_TParams.m_dDiam - m_Params.m_dSideStep) ;
dOffs = max( dOffs, dMinOffs) ;
if ( dOffs > EPS_SMALL) {
// calcolo offset
OffsetCurve OffsCrv ;
if ( ! OffsCrv.Make( pCrvPocket, dOffs, ICurve::OFF_EXTEND)) {
m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ;
return false ;
}
if ( OffsCrv.GetCurveCount() > 1)
return false ;
// aggiorno pCrvPocket
pCrvPocket->Clear() ;
pCrvPocket->AddCurve( OffsCrv.GetCurve()) ;
}
return true ;
}
//------------------------------------------------------------------
bool
Pocketing::CutCurveWithLine( ICurveComposite* pCrvA, const ICurveLine* pCrvB)
{
IntersCurveCurve IntersCC( *pCrvA, *pCrvB) ;
CRVCVECTOR ccClass ;
IntersCC.GetCurveClassification( 1, EPS_SMALL, ccClass) ;
if ( ccClass.size() != 3 || ccClass[0].nClass != CRVC_OUT || ccClass[1].nClass == CRVC_OUT || ccClass[2].nClass != CRVC_OUT)
return false ;
Point3d ptS, ptE ;
pCrvB->GetPointD1D2( ccClass[1].dParS, ICurve::FROM_MINUS, ptS) ;
pCrvB->GetPointD1D2( ccClass[1].dParE, ICurve::FROM_MINUS, ptE) ;
double dParS, dParE ;
pCrvA->GetParamAtPoint( ptS, dParS) ;
pCrvA->GetParamAtPoint( ptE, dParE) ;
PtrOwner<ICurveComposite> pCrvTmp( CloneCurveComposite( pCrvA)) ;
if ( IsNull( pCrvTmp))
return false ;
pCrvA->Clear() ;
pCrvA->AddCurve( pCrvB->CopyParamRange( ccClass[1].dParS, ccClass[1].dParE)) ;
pCrvA->AddCurve( pCrvTmp->CopyParamRange( dParE, dParS)) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AddOneWay( const ISurfFlatRegion* pSrfPock, const Vector3d& vtTool, const Vector3d& vtExtr,
double dDepth, double dElev, double dOkStep, bool bSplitArcs)
{
// recupero distanze di sicurezza
double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ;
double dSafeAggrBottZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeAggrBottZ() ;
// lunghezza di approccio/retrazione
double dAppr = m_Params.m_dStartPos ;
// se utensile che non lavora di testa poichè ingresso non fuori dal pezzo, errore
if ( m_TParams.m_nType == TT_MILL_NOTIP) {
if ( ! LeadInRawIsOk()) {
m_pMchMgr->SetLastError( 2431, "Error in Pocketing : LeadIn with Mill NoTip in material") ;
return false;
}
}
// determino numero e affondamento degli step
int nStep = 1 ;
nStep = max( 1, static_cast<int>( ceil(dElev / dOkStep))) ;
double dStep = dElev / nStep ;
double dTRad = 0.5 * m_TParams.m_dDiam ;
double dOffs = dTRad + GetOffsR() ;
double dExtra = min( 0.1 * m_TParams.m_dDiam, 1.0) ;
// copio la regione da svuotare
PtrOwner<ISurfFlatRegion> pSrfToPock( pSrfPock->Clone()) ;
if ( IsNull( pSrfToPock))
return false ;
// creo le regioni ideali --------------------------------------------
// creo un frame di riferimento della svuotatura
Frame3d frLoc ;
Point3d ptC ; pSrfToPock->GetCentroid( ptC) ;
Vector3d vtN = pSrfPock->GetNormVersor() ;
frLoc.Set( ptC, vtN) ;
pSrfToPock->ToLoc( frLoc) ;
ISURFFRPOVECTOR vSrfFlat ;
INTVECTOR vIndChunk ;
PNTVECTOR vPtCheck ;
struct PtSPtC { // struttura per punti inziali
int nInd ; // indice per vettori vPtStart, vbMidOpen, vPtMidOpen, vVtMidOut
Point3d ptC ; // punto check sulla curva
} ;
if ( ! OptimizeChunkOneWay( pSrfToPock, vSrfFlat, vIndChunk, vPtCheck))
return false ;
typedef vector<PtSPtC> vPtSCheck ;
vPtSCheck vNewPtStart(( int)vIndChunk.size()) ;
for ( int i = 0 ; i < ( int)vIndChunk.size() ; ++ i){
vNewPtStart[i].nInd = vIndChunk[i] ;
vNewPtStart[i].ptC = vPtCheck[i] ;
}
// riporto le superifici ideali nel sistema di riferimento globale
for ( int i = 0 ; i < (int )vSrfFlat.size() ; ++ i)
vSrfFlat[i]->ToGlob( frLoc) ;
// ------------------------------------------------------------------
// === per ogni superificie ideale creo 2 Offsets ===
// - dOffs con le curve da percorrere all'inizio ( bordo da percorrere, senza mai superarlo)
// - dOffs - dExtra per definire le curve interne della svuotatura ( bordo immaginario per il OneWay )
for ( int nIs = 0 ; nIs < int( vSrfFlat.size()) ; ++ nIs) {
// copio la superificie ideale
PtrOwner<ISurfFlatRegion> pSrfIdeal( CloneSurfFlatRegion( vSrfFlat[nIs])) ;
if ( IsNull( pSrfIdeal))
return false ;
ISURFFRPOVECTOR vSrfSliced( nStep) ;
vector<ICRVCOMPOPOVECTOR> vCrvOEWithFlags( nStep) ;
BOOLVECTOR vbChangedPrec( nStep, false) ;
VCT3DVECTOR vVtTrasl( nStep, V_NULL) ;
if ( ! GetParamsAtEachStep( vSrfSliced, vCrvOEWithFlags, vbChangedPrec, vVtTrasl, pSrfIdeal,
nStep, vtTool, dElev, dDepth, dStep))
return false ;
Point3d ptP1 ; // per LeadIn
for ( int j = 1 ; j <= nStep ; ++ j) {
// se superificie non valida, salto allo step successivo
if ( IsNull( vSrfSliced[ j-1]) || vSrfSliced[j-1]->GetChunkCount() == 0) {
vSrfSliced[j-1].Set( vSrfFlat[nIs]->Clone()) ;
continue ;
}
// per entrate ed uscite
PtrOwner<ISurfFlatRegion> pSrfLeanInOut( CloneSurfFlatRegion( vSrfSliced[j-1])) ;
if ( IsNull( pSrfLeanInOut) || pSrfLeanInOut->GetChunkCount() == 0)
return false ;
// === PRIMO OFFSET ===
// NB. Effettuando il primo Offset, il numero di chunk qui potrebbe cambiare...
PtrOwner<ISurfFlatRegion> pSrfFirstOffs( CloneSurfFlatRegion( vSrfSliced[j-1])) ;
if ( IsNull( pSrfFirstOffs) || pSrfFirstOffs->GetChunkCount() == 0)
return false ;
if ( ! pSrfFirstOffs->Offset( - dOffs, ICurve::OFF_FILLET)) {
m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ;
return false ;
}
// creo un frame di riferimento per ogni superificie da svuotare
Frame3d frLocI ;
Point3d ptC ; pSrfToPock->GetCentroid( ptC) ;
Vector3d vtN = pSrfToPock->GetNormVersor() ;
frLocI.Set( ptC, vtN) ;
vSrfSliced[j-1]->ToLoc( frLocI) ;
// salvo tutte le curve di Offset in un vettore per poi ordinarle e sistemare i punti iniziali
ICRVCOMPOPOVECTOR vAllCrv ;
// vettore di indici, mi dice a quale chunk la curva vAllCrv-u-esima appartiene
INTVECTOR vInd ;
// NB. Questa Superificie la userò solamente dopo, quando andrò creare le traettorie rettilinee per la OneWay
// A questa superificie non andrò ad effettuare un ulteriore Offset con -dExtra, in quando potrei lasciare delle
// regioni non svuotate ( come soluzione interseco ogni segmento di OneWay con questa superificie Offsettata di
// -dOffs e tagliando ogni segmento, lo accorcio sia all'inizio che alla fine della quantità dExtra
// organizzo i Chunck della superificie elaborata con il grezzo ...
for ( int c = 0 ; c < vSrfSliced[j-1]->GetChunkCount() ; ++ c) {
PtrOwner<ISurfFlatRegion> pSrfChuck_c( vSrfSliced[j-1]->CloneChunk( c)) ;
if ( IsNull( pSrfChuck_c))
return false ;
if ( ! pSrfChuck_c->Offset( - dOffs, ICurve::OFF_FILLET)) {
m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ;
return false ;
}
for ( int cc = 0 ; cc < pSrfChuck_c->GetChunkCount() ; ++ cc) {
for ( int l = 0 ; l < pSrfChuck_c->GetLoopCount( cc) ; ++ l) {
vAllCrv.emplace_back( GetCurveComposite( pSrfChuck_c->GetLoop( cc, l))) ;
vInd.emplace_back( c) ;
}
}
}
if (( int)vAllCrv.size() == 0)
return false ;
// Sistemo i punti iniziali per i nuovi Chunks ------------------------------------------
VCT3DVECTOR vVtMidOut(( int)vAllCrv.size(), V_NULL) ;
BOOLVECTOR vbMidOut(( int)vAllCrv.size(), false) ;
PNTVECTOR vPtStart(( int)vAllCrv.size(), Point3d( 0,0,0)) ;
BOOLVECTOR vbForcedOutStart(( int)vAllCrv.size(), false) ;
// le curve ottenute andranno percorse dall'utensile
for ( int u = 0 ; u < ( int)vAllCrv.size() ; ++ u) {
// per ogni curva di bordo...
bool bOutTmp = false ;
PtrOwner<ISurfFlatRegion> pSrfCurrChunk( vSrfSliced[j-1]->CloneChunk( vInd[u])) ;
if ( IsNull( pSrfCurrChunk))
return false ;
if ( ! SetBetterPtStartForSubChunks( vAllCrv[u], pSrfCurrChunk,
vPtStart[u], vVtMidOut[u], bOutTmp))
return false ;
vbMidOut[u] = bOutTmp ; // vector<bool>::reference da Bit a Bool
PtrOwner<ICurveComposite> pOffs( CreateCurveComposite()) ; // copio la curva ...
if ( IsNull( pOffs) || ! pOffs->AddCurve( vAllCrv[u]->Clone())) {
m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ;
return false ;
}
// riporto i valori nel sistema di riferimento corretto
vPtStart[u].ToGlob( frLocI) ;
vVtMidOut[u].ToGlob( frLocI) ;
vAllCrv[u]->ToGlob( frLocI) ;
// se richiesto, la inverto
if ( m_Params.m_bInvert)
vAllCrv[u]->Invert() ;
// setto la Feed per la curva di contorno
AssignFeedForEdgeCleaning( vAllCrv[u], vCrvOEWithFlags[j-1]) ;
// se la curva è valida per entrata da fuori, aggiungo un piccolo tratto lineare
if ( vbMidOut[u]) {
// calcolo il punto fuori
Point3d ptOut = vPtStart[u] + vVtMidOut[u] * ( 0.5 * m_TParams.m_dDiam + dSafeZ) ;
ptOut.Translate( - vtTool * ( dDepth - dElev + j * dStep)) ;
double dStElev ;
bool bOutStart = ( ! GetElevation( m_nPhase, ptOut, vtTool, 0.5 * m_TParams.m_dDiam, vtTool, dStElev) || dStElev < EPS_SMALL);
if ( bOutStart || m_bOpenOutRaw) {
// aggiungo alla curva il tratto lineare
ptOut.Translate( vtTool * ( dDepth - dElev + j * dStep)) ;
vAllCrv[u]->AddLine( ptOut, false) ;
AssignFeedForLineInOut( vAllCrv[u], true) ;
}
// verifico se ingresso da considerare fuori grezzo anche se dentro
vbForcedOutStart[u] = ( vbMidOut[u] && m_bOpenOutRaw) ;
// se utensile che non lavora di testa e ingresso non fuori dal pezzo, errore
if ( m_TParams.m_nType == TT_MILL_NOTIP && !bOutStart && !vbForcedOutStart[u]) {
if ( ! LeadInRawIsOk()) {
m_pMchMgr->SetLastError( 2431, "Error in Pocketing : LeadIn with Mill NoTip in material") ;
return false ;
}
}
}
}
// riordino le curve ( e i relativi vettori ) in base alla vicinanza
// ( piccola ottimizzazione per l'ordine dei percorsi sui bordi )
Point3d ptStart ; vAllCrv[0]->GetStartPoint( ptStart) ;
if ( ! OrderCurvesByLastPntOfPath( vAllCrv, ptStart, vPtStart, vVtMidOut, vbMidOut))
return false ;
// ---------------------------- Disegno le curve di contorno ----------------------
for ( int u = 0 ; u < int( vAllCrv.size()) ; ++ u) { // percorro tutte le curve ( ordinate )
// recupero la prima curva di offset disponibile
PtrOwner<ICurveComposite> pOffs( CreateCurveComposite());
if ( IsNull( pOffs) || ! pOffs->AddCurve( vAllCrv[u]->Clone())) {
m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ;
return false;
}
// aggiungo la lavorazione di questa curva
Point3d ptP1 ;
double dStElev ;
// ciclo sulle curve elementari
int nMaxInd = pOffs->GetCurveCount() - 1 ;
for ( int i = 0 ; i <= nMaxInd ; ++i) {
// curva corrente
const ICurve* pCrvC = pOffs->GetCurve( i) ;
// copio la curva
PtrOwner<ICurve> pCurve( pCrvC->Clone()) ;
if ( IsNull( pCurve))
return false ;
// aggiungo affondamento
pCurve->Translate( -vtTool * ( dDepth - dElev + j * dStep)) ;
// SE PRIMA ENTITA'
if ( i == 0) {
// dati inizio entità
Point3d ptStart ;
Vector3d vtStart ;
pCurve->GetStartPoint( ptStart) ;
pCurve->GetStartDir( vtStart) ;
Point3d ptForElev = ptStart ;
if( vbMidOut[u] || vbForcedOutStart[u])
pCurve->GetEndPoint( ptForElev) ;
// se primo step o la superificie rispetto allo step prima non è cambiata o il numero
// di chunk è maggiore di 1, approccio e affondo
//if ( true || j == 1 || vbChangedPrec[j-1] || vSrfSliced[j-2]->GetChunkCount() > 1) {
// determino inizio attacco
if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, nullptr, ptP1))
return false ;
// determino elevazione su inizio attacco
//double dStElev ;
if ( ! GetElevation( m_nPhase, ptForElev - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev))
dStElev = j * dStep ;
bool bAhUnderRaw = m_bAboveHead && ! m_bAggrBottom && ! m_bTiltingTab &&
GetAhPointUnderRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(),
m_TParams.m_dLen, false, dSafeZ, vtTool, dStElev) ;
bool bUhAboveRaw = ! m_bAboveHead &&
GetUhPointAboveRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(),
m_TParams.m_dLen, false, dSafeZ, vtTool, dStElev) ;
if ( bAhUnderRaw || bUhAboveRaw || m_bTiltingTab)
dStElev = max( dStElev, j * dStep) ;
dStElev -= ( ptP1 - ptStart) * vtExtr ;
// se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco
if ( GetLeadInType() == POCKET_LI_ZIGZAG ||
GetLeadInType() == POCKET_LI_HELIX ||
GetLeadInType() == POCKET_LI_GLIDE) {
ptP1 += vtExtr * dStElev ;
dStElev = 0 ;
}
// approccio al punto iniziale // false sempre ?
if ( ! AddApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, vbMidOut[u] || vbForcedOutStart[u])) {
m_pMchMgr->SetLastError( 2414, "Error in Pocketing : Approach not computable") ;
return false ;
}
// aggiungo attacco
SetFeed( GetStartFeed()) ;
if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrfLeanInOut, nullptr, !m_Params.m_bInvert, bSplitArcs, vbMidOut[u] || vbForcedOutStart[u])) {
m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ;
return false ;
}
//}
// altrimenti solo collegamento
// else {
// SetFeed( GetStartFeed()) ;
// GetCurrPos( ptP1) ;
// if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrfLeanInOut, nullptr, !m_Params.m_bInvert, bSplitArcs)) {
// m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ;
// return false ;
// }
// }
}
// elaborazioni sulla curva corrente
// elaborazioni sulla curva corrente
double dMinFeed = GetFeed() * GetSideStep() / m_TParams.m_dDiam ;
double dFeed = pCurve->GetTempProp( 0) / FEED_DIVISOR < dMinFeed - 50 * EPS_SMALL ?
GetFeed() : pCurve->GetTempProp( 0) / FEED_DIVISOR ;
//DrawColoredCrvForFeedTest( pCurve, dFeed) ;
SetFeed( dFeed) ;
if ( pCurve->GetType() == CRV_LINE) {
ICurveLine* pLine = GetCurveLine( pCurve) ;
Point3d ptP3 = pLine->GetEnd() ;
//SetFeed( dFeedRid * GetFeed()) ;
if ( AddLinearMove( ptP3) == GDB_ID_NULL)
return false ;
}
else if ( pCurve->GetType() == CRV_ARC) {
ICurveArc* pArc = GetCurveArc( pCurve) ;
Point3d ptCen = pArc->GetCenter() ;
double dAngCen = pArc->GetAngCenter() ;
Vector3d vtN = pArc->GetNormVersor() ;
Point3d ptP3 ;
pArc->GetEndPoint( ptP3) ;
//SetFeed( dFeedRid * GetFeed()) ;
if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL)
return false ;
}
// SE ULTIMA ENTITA'
if ( i == nMaxInd) {
// se ultimo step, uscita e retrazione di collegamento
//if ( j == nStep ) {
// dati fine entità
Point3d ptEnd ;
pCurve->GetEndPoint( ptEnd) ;
Vector3d vtEnd ;
pCurve->GetEndDir( vtEnd) ;
// aggiungo uscita
//Point3d ptP1 ; <----------- ?????????????
//double dEndElev = dElev ;
//double dEndElev = dStElev ;
double dEndElev ;
if ( ! GetElevation( m_nPhase, ptEnd - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dEndElev))
dEndElev = j * dStep ;
dEndElev = max( dEndElev, j * dStep) ;
SetFeed( GetEndFeed()) ;
if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, nullptr, bSplitArcs, false, ptP1, dEndElev, false)) {
m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ;
return false ;
}
// aggiungo retrazione
if ( ! AddLinkRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) {
m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ;
return false ;
}
// }
}
}
} // fine ciclo sulle curve di Offset i-esime
// ===== SEGMENTI =========
// determino il riferimento in base alla svuotatura ( Serve per Orientare i segmenti in base al m_dSideAngle )
Frame3d frPocket ;
Point3d ptCen ; pSrfFirstOffs->GetCentroid( ptCen) ;
frPocket.Set( ptCen, vtExtr) ;
frPocket.Rotate ( ptCen, vtExtr, m_Params.m_dSideAngle) ;
pSrfFirstOffs->ToLoc( frPocket) ;
BBox3d b3Pocket ; pSrfFirstOffs->GetLocalBBox( b3Pocket) ;
Point3d ptMin ; double dDimX, dDimY, dDimZ ;
b3Pocket.GetMinDim( ptMin, dDimX, dDimY, dDimZ) ;
// passi in Y
int nYStep = static_cast<int>( ceil(( dDimY + 2 * dExtra) / GetSideStep())) ;
double dYStep = ( nYStep > 0 ? ( dDimY + 2 * dExtra) / nYStep : 0) ;
--nYStep ;
// vettore dei segmenti al di sotto della linea corrente ( per la Feed)
ICURVEPOVECTOR vLineUnder ;
ICURVEPOVECTOR vLineAbove ; // in questo caso sempre vuoto
ICRVCOMPOPOVECTOR vCrvLink ; // in questo caso sempre vuoto
// calcolo le linee di svuotatura
const double EXP_LEN = 1.0 ;
//for ( int j = 1 ; j <= nStep ; ++j) {
for ( int i = 1 ; i <= nYStep ; ++ i) {
// definisco la linea
PtrOwner<ICurveLine> pLine( CreateCurveLine()) ;
Point3d ptStart( ptMin.x - EXP_LEN, ptMin.y + ( - dExtra + i * dYStep), ptMin.z + dDimZ) ;
if ( IsNull( pLine) || ! pLine->SetPVL( ptStart, X_AX, dDimX + 2 * EXP_LEN)) {
m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ;
return false ;
}
// linea come composita per Feed ( la dovrò spezzare)
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
if ( IsNull( pCrvCompo))
return false ;
// vettore di tutti i segmenti lineari che si formano nello step nYStep
ICURVEPOVECTOR vAddedLines ;
// riempio il vettore di segmenti
CRVCVECTOR ccClassSeg ;
pSrfFirstOffs->GetCurveClassification( *pLine, EPS_SMALL, ccClassSeg) ;
for ( int w = 0 ; w < int( ccClassSeg.size()) ; ++w) {
if ( ccClassSeg[w].nClass == CRVC_IN) {
PtrOwner<ICurveLine> pCrvSeg( GetCurveLine( pLine->CopyParamRange( ccClassSeg[w].dParS, ccClassSeg[w].dParE))) ;
double duF, dLen ;
// accorcio leggermente il segmento per non toccare la prima curva di Offset
if ( ! pCrvSeg->GetLength( dLen) ||
dLen < 2 * dExtra ||
! pCrvSeg->GetParamAtLength( dLen - dExtra, duF) ||
! pCrvSeg->TrimStartAtLen( dExtra) ||
! pCrvSeg->TrimEndAtParam( duF))
pCrvSeg.Set( GetCurveLine( pLine->CopyParamRange( ccClassSeg[w].dParS, ccClassSeg[w].dParE))) ;
Point3d ptS, ptE ;
pCrvSeg->GetStartPoint( ptS) ;
//pCrvSeg->GetEndPoint( ptE) ;
// imposto la Feed
//vAddedLines.emplace_back( pCrvSeg->Clone()) ;
pCrvCompo->Clear() ;
pCrvCompo->AddCurve( pCrvSeg->Clone()) ;
vAddedLines.emplace_back( pCrvCompo->Clone()) ;
if ( ! AssignFeedZigZagOneWay( pCrvCompo, false, vLineAbove, vLineUnder, vCrvLink))
return false ;
//PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
//if ( IsNull( pCrvCompo))
// return false ;
//pCrvCompo->AddCurve( pCrvSeg->Clone()) ;
//if ( ! AssignFeedOneWay( pCrvSeg, pSrfRemoved) ||
// ! GetDynamicClearedRegion( pSrfRemoved, pCrvCompo))
// return false ;
// INIZIO
ptS.ToGlob( frPocket) ;
ptS.Translate( -vtTool * ( dDepth - dElev + j * dStep)) ;
// determino inizio attacco
Point3d ptP ;
if ( ! CalcLeadInStart( ptS, frPocket.VersX(), vtExtr, nullptr, ptP))
return false ;
// determino elevazione su inizio attacco
double dStElev ;
if ( ! GetElevation( m_nPhase, ptS - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev))
dStElev = j * dStep ;
bool bAhUnderRaw = m_bAboveHead && ! m_bAggrBottom && ! m_bTiltingTab &&
GetAhPointUnderRaw( ptP, vtTool, 0, GetRadiusForStartEndElevation(),
m_TParams.m_dLen, false, dSafeZ, vtTool, dStElev) ;
bool bUhAboveRaw = ! m_bAboveHead &&
GetUhPointAboveRaw( ptP, vtTool, 0, GetRadiusForStartEndElevation(),
m_TParams.m_dLen, false, dSafeZ, vtTool, dStElev) ;
if( bAhUnderRaw || bUhAboveRaw || ( i == 1 && w == 1))
dStElev = max( dStElev, j * dStep) ;
dStElev -= ( ptP - ptS) * vtExtr ;
// sempre approccio di collegamento
if ( ! AddLinkApproach( ptP, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr)) {
m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ;
return false ;
}
// aggiungo attacco (forzato ad essere lineare)
SetFeed( GetStartFeed()) ;
if ( ! AddLeadIn( ptP, ptS, frPocket.VersX(), vtExtr, pSrfLeanInOut, nullptr, !m_Params.m_bInvert, bSplitArcs, true)) {
m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ;
return false ;
}
for ( int u = 0 ; u < pCrvCompo->GetCurveCount() ; ++ u) {
//ptE.ToGlob( frPocket) ;
//ptE.Translate( -vtTool * (dDepth - dElev + j * dStep)) ;
const ICurve* pCurve( pCrvCompo->GetCurve( u)) ;
pCurve->GetEndPoint( ptE) ;
ptE.ToGlob( frPocket) ;
ptE.Translate( -vtTool * ( dDepth - dElev + j * dStep)) ;
// movimento al punto finale
// elaborazioni sulla curva corrente
double dMinFeed = GetFeed() * GetSideStep() / m_TParams.m_dDiam ;
double dFeed = pCurve->GetTempProp( 0) / FEED_DIVISOR < dMinFeed - 50 * EPS_SMALL ?
GetFeed() : pCurve->GetTempProp( 0) / FEED_DIVISOR ;
SetFeed( dFeed) ;
//PtrOwner<ICurve> pCrv_TestFeed( pCurve->Clone()) ;
//pCrv_TestFeed->ToGlob( frPocket) ;
//if ( abs( dFeed - GetMinFeed()) < EPS_SMALL) {
// int rosso = m_pGeomDB->AddGeoObj(GDB_ID_NULL, GDB_ID_ROOT, pCrv_TestFeed->Clone()) ;
// m_pGeomDB->SetMaterial( rosso, RED) ;
//}
//if ( abs( dFeed - GetMaxFeed()) < EPS_SMALL) {
// int verde = m_pGeomDB->AddGeoObj(GDB_ID_NULL, GDB_ID_ROOT, pCrv_TestFeed->Clone()) ;
// m_pGeomDB->SetMaterial( verde, GREEN) ;
//}
//SetFeed( dFeed) ;
//SetFeed( GetFeed()) ;
if ( AddLinearMove( ptE) == GDB_ID_NULL)
return false ;
}
// FINE
Point3d ptQ ;
//double dEndElev = dElev ;
double dEndElev ;
if ( ! GetElevation( m_nPhase, ptE - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dEndElev))
dEndElev = j * dStep ;
dEndElev = max( dEndElev, j * dStep) ;
SetFeed( GetEndFeed()) ;
if ( ! AddLeadOut( ptE, frPocket.VersX(), vtExtr, nullptr, bSplitArcs, true, ptQ, dEndElev)) {
m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ;
return false ;
}
// se ultimo movimento di ultima area, aggiungo retrazione globale
if ( j == nStep && i == nYStep && w == ( int)ccClassSeg.size() - 2) {
if ( ! AddRetract( ptQ, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) {
m_pMchMgr->SetLastError( 2417, "Error in Pocketing : Retract not computable") ;
return false ;
}
}
// altrimenti aggiungo retrazione di collegamento
else {
if ( ! AddLinkRetract( ptQ, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) {
m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ;
return false ;
}
}
}
}
vLineUnder.clear() ;
for ( int u = 0 ; u < ( int)vAddedLines.size() ; ++ u)
vLineUnder.emplace_back( vAddedLines[u]->Clone()) ;
}
} // fine ciclo sugli step
} // fine ciclo sulle superifici ideali
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AddSpiralIn( const ISurfFlatRegion* pSrfPock, const Vector3d& vtTool, const Vector3d& vtExtr,
double dDepth, double dElev, double dMaxElev, double dOkStep, bool bSplitArcs)
{
// recupero distanze di sicurezza
double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ;
double dSafeAggrBottZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeAggrBottZ() ;
// lunghezza di approccio/retrazione
double dAppr = m_Params.m_dStartPos ;
// determino numero e affondamento degli step
int nStep = 1 ;
nStep = max( 1, static_cast<int>( ceil( dElev / dOkStep))) ;
double dStep = dElev / nStep ;
// ciclo sui chunk della superificie da svuotare
for ( int c = 0 ; c < pSrfPock->GetChunkCount() ; ++ c) {
// copio il chunk c-esimo
PtrOwner<ISurfFlatRegion> pSrfChunk( GetSurfFlatRegion( pSrfPock->CloneChunk( c))) ;
if ( IsNull( pSrfChunk))
return false ;
// modifico le superifici in base alla geometria del grezzo e alla geometria dell'entità selezionata
ISURFFRPOVECTOR vSrfSliced( nStep) ;
vector<ICRVCOMPOPOVECTOR> vCrvOEWithFlags( nStep) ;
BOOLVECTOR vbChangedPrec( nStep, false) ;
VCT3DVECTOR vVtTrasl( nStep, V_NULL) ;
if ( ! GetParamsAtEachStep( vSrfSliced, vCrvOEWithFlags, vbChangedPrec, vVtTrasl, pSrfChunk,
nStep, vtTool, dElev, dDepth, dStep))
return false ;
Point3d ptP1, ptStartPrec ; // per LeadIn attuale e precedente
bool bMidOutPrec ; // flag per entrata precedente da fuori dal grezzo
BOOLVECTOR vbMidOutPrec ; // flags per effettiva entrata precedente da fuori dal grezzo
ICRVCOMPOPOVECTOR vMCrv_step_prec ; // vettore delle curve dei percorsidi svuotatura dello step precedente
ICRVCOMPOPOVECTOR vRCrv_step_prec ; // vettore delle curve dei percorsi di ritorno dello step precedente
vector<Vector3d> vvtMidOutPrec ; // vettore dei versori delle direzioni di uscita dello step precedente
INTVECTOR vnRegTot_prec ; // vettore dei numeri delle regioni formate dal primo Offset nello step precedente
BOOLVECTOR vbOptTrap_prec ; // flags per caso ottimizzato svuotratura dello step precedente
int nOffs_act = 0 ;
// ciclo su tutti gli step
for ( int j = 1 ; j <= nStep ; ++ j) {
// se superificie non valida, salto allo step successivo
if ( IsNull( vSrfSliced[j-1]) || vSrfSliced[j-1]->GetChunkCount() == 0) {
vSrfSliced[j-1].Set( pSrfChunk->Clone()) ;
continue ;
}
// la superificie che lavoro è quella ottenuta in precedenza allo step j-esimo
PtrOwner<ISurfFlatRegion> pSrfFinal( CloneSurfFlatRegion( vSrfSliced[j-1])) ;
if ( IsNull( pSrfFinal))
return false ;
nOffs_act = 0 ; // reset indice dei vettori per step precedenti
if ( vbChangedPrec[j-1]) {
// se lo step attuale è cambiato rispetto al precedente -> Flush info step precedente
vMCrv_step_prec.clear() ;
vRCrv_step_prec.clear() ;
vnRegTot_prec.clear() ;
vbMidOutPrec.clear() ;
vvtMidOutPrec.clear() ;
vbOptTrap_prec.clear() ;
}
for ( int cc = 0 ; cc < ( int)pSrfFinal->GetChunkCount() ; ++ cc) { // per ogni suo chunk cc-esimo...
// il numero di chunk dopo aver intersecato e proiettato può cambiare
// essendo una svuotatura a spirale, facendo il primo offset del chunk cc-esimo potrei ottenere
// ulteriori chunks ( ad esempio se la superificie presenta delle parti molto strette)
// MAX_REGS = 50 -> # massimo di Chunks nuovi accettati
const int MAX_REGS = 50 ;
int nReg = 0 ; // chunk nuovo corrente da svuotare
PtrOwner<ISurfFlatRegion> pSrfChunkFinal( pSrfFinal->CloneChunk( cc)) ;
// ciclo su tutte le regioni che posso ottenere col primo Offset del chunc cc-esimo
while ( nReg < MAX_REGS) {
// superifice per ingressi ed uscite
PtrOwner<ISurfFlatRegion> pSrfLeanInOut( CloneSurfFlatRegion( pSrfChunkFinal)) ;
if ( IsNull( pSrfLeanInOut))
return false ;
// calcolo la spirale dall'esterno all'interno e la curva che unisce inizio e fine
PtrOwner<ICurveComposite> pMCrv( CreateCurveComposite()) ; // percorso di svuotatura
PtrOwner<ICurveComposite> pRCrv( CreateCurveComposite()) ; // percorso di ritorno
if ( IsNull( pMCrv) || IsNull( pRCrv)) {
m_pMchMgr->SetLastError( 2411, "Error in Pocketing : toolpath allocation failed") ;
return false ;
}
int nRegTot ; // numero di regioni create dal primo Offset per lo step attuale
bool bOutStart ; // flag per entrata da fuori per lo step attuale
bool bForcedOutStart ; // flag per forzare l'entrata da fuori allo step attuale
Point3d ptStart ; // punto iniziale del percorso
Vector3d vtMidOut ; // vettore verso l'esterno nel caso di entrata da fuori ammissibile ( -> da CalcSpiral)
bool bMidOut ; // ammissibilità entrata da fuori ( da calcolare step per step)
bool bOptimizedTrap = false ; // se ho un caso spirale o trapezio
// NB. se la superficie è rimasta la stessa, utilizzo pMCrv e pRCrv dello step precedente
// ( non c'è bisogno di ricalcolare tutti i percorsi)
if ( ! vbChangedPrec[j-1] && j != 1) {
if ( nOffs_act > ( int)vMCrv_step_prec.size() - 1)
break ;
pMCrv.Set( vMCrv_step_prec[nOffs_act]->Clone()) ;
pRCrv.Set( vRCrv_step_prec[nOffs_act]->Clone()) ;
nRegTot = vnRegTot_prec[nOffs_act] ;
bMidOut = vbMidOutPrec[nOffs_act] ;
vMCrv_step_prec[nOffs_act]->GetStartPoint( ptStart) ;
vtMidOut = vvtMidOutPrec[nOffs_act] ;
bOptimizedTrap = vbOptTrap_prec[nOffs_act] ;
}
else {
// se lucidatura con epicicli
if ( m_TParams.m_nType == TT_MILL_POLISHING && m_Params.m_dEpicyclesRad > EPS_SMALL) {
// verifico che i parametri lucidatura siano sensati
if ( m_Params.m_dEpicyclesDist < 100 * EPS_SMALL) {
m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ;
return false ;
}
// modifico il diametro dell'utensile per tenere conto anche del diametro degli epicicli
m_TParams.m_dDiam += 2 * m_Params.m_dEpicyclesRad ;
}
// cerco la curva originale del chunk cc-esimo ( PER CASI OTTIMIZZATI)
int nInd = 0 ; // indice del vettore delle curve esterne relativo al chunk cc-esimo
// cerco la curva originale del chunk cc-esimo
if (( int)vCrvOEWithFlags[j-1].size() == 1)
nInd = 0 ;
else {
for ( int k = 0 ; k < ( int)vCrvOEWithFlags[j-1].size() ; ++ k) {
CRVCVECTOR ccClass ;
if ( pSrfChunkFinal->GetCurveClassification( *vCrvOEWithFlags[j-1][k], EPS_SMALL, ccClass)) {
bool bIsThis = true ;
for ( int kk = 0 ; kk < ( int)ccClass.size() && bIsThis ; ++ kk) {
if ( ccClass[kk].nClass == CRVC_OUT)
bIsThis = false ;
}
if ( bIsThis) {
nInd = k ;
break ;
}
}
}
}
// ------------------------------------------------------------------------------------
nRegTot = nReg ;
// calcolo il percorso di svuotatura
if ( ! CalcSpiral( pSrfChunkFinal, nRegTot, ptStart, vtMidOut, bMidOut, bSplitArcs, pMCrv, pRCrv,
vCrvOEWithFlags[j-1][nInd], j == 1 ? true : vbChangedPrec[j-1],
bOptimizedTrap))
return false ;
// se terminate le regioni, esco
if ( pMCrv->GetCurveCount() == 0)
break ; // passo al chunk originale successivo
if ( m_TParams.m_nType == TT_MILL_POLISHING && m_Params.m_dEpicyclesRad > EPS_SMALL) {
// riporto il diametro dell'utensile al valore originale
m_TParams.m_dDiam -= 2 * m_Params.m_dEpicyclesRad ;
// aggiorno i percorsi di svuotatura con epicicli
if ( ! ComputePolishingPath( pMCrv, pRCrv, bSplitArcs)) {
m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ;
return false ;
}
}
// memorizzo le curve create e modificate per lo step successivo
vMCrv_step_prec.emplace_back( pMCrv->Clone()) ;
vRCrv_step_prec.emplace_back( pRCrv->Clone()) ;
// memorizzo i Flag per le entrate
vbMidOutPrec.push_back( bMidOut) ;
// memorizzo il numero delle regioni create dal primo Offset
vnRegTot_prec.push_back( nRegTot) ;
// memorizzo il versore di uscita calcolato
vvtMidOutPrec.push_back( vtMidOut) ;
// memorizzo caso ottimizzato
vbOptTrap_prec.push_back( bOptimizedTrap) ;
}
// controlli per entrate da fuori al grezzo
bOutStart = bMidOut ;
if ( bOutStart && ! bOptimizedTrap) {
// calcolo il punto fuori per il LeadIn
Point3d ptOut = ptStart + vtMidOut * ( 0.5 * m_TParams.m_dDiam + dSafeZ) ;
ptOut.Translate( vVtTrasl[j-1]) ; // lo traslo allo step corrente
double dStElev ;
// controllo l'elevazione
bOutStart = ( ! GetElevation( m_nPhase, ptOut, vtTool, 0.5 * m_TParams.m_dDiam, vtTool, dStElev) || dStElev < EPS_SMALL) ;
if ( bOutStart || m_bOpenOutRaw) {
// aggiungo al ritorno l'uscita
if ( pRCrv->GetCurveCount() == 0) {
Point3d ptStart ; pMCrv->GetStartPoint( ptStart) ;
pRCrv->AddPoint( ptStart) ;
}
ptOut.Translate( -vVtTrasl[j-1]) ; // lo ritraslo sulla curva
// aggiungo un tratto lineare all'inizio del percorso di svuotatura
pMCrv->AddLine( ptOut, false) ;
// assegno la sua Feed
AssignFeedForLineInOut( pMCrv, true) ;
// aggiungo un tratto lineare alla fine del percorso di svuotatura
pRCrv->AddLine( ptOut, true) ;
// assegno la sua Feed
AssignFeedForLineInOut( pRCrv, false) ;
}
}
// calcolo gli eventuali punti fuori dal grezzo nel caso ottimizzato
int nOutsideRaw = 0 ;
if ( bOptimizedTrap) {
AdjustTrapezoidSpiralForLeadInLeadOut( pMCrv, pRCrv, vtTool, dDepth, nOutsideRaw) ;
bOutStart = ( nOutsideRaw > 0) ;
// imposto la Feed
AssignFeedSpiralOpt( 1, pMCrv) ;
AssignFeedForReturnPath( pRCrv) ;
}
// verifico se l'ingresso è da considerare fuori dal grezzo anche se dentro
bForcedOutStart = ( bMidOut && m_bOpenOutRaw) ;
// se utensile che non lavora di testa e ingresso non fuori dal pezzo, errore
if ( m_TParams.m_nType == TT_MILL_NOTIP && ! ( bOutStart || bForcedOutStart)) {
if ( ! LeadInRawIsOk()) {
m_pMchMgr->SetLastError( 2431, "Error in Pocketing : LeadIn with Mill NoTip in material") ;
return false ;
}
}
// se sono nel caso ottimizzato e ho attacco e uscita entrambi dentro/fuori dal grezzo,
// ad ogni step pari inverto la direzione della curva solamente se ho un solo chunk e la superificie successiva
// non è cambiata
if ( bOptimizedTrap && nOutsideRaw != 1 && j > 1 && vSrfSliced[j-2]->GetChunkCount() == 1 && ! vbChangedPrec[j-1]
&& ( j % 2 == 0))
pMCrv->Invert() ;
++nReg ;
++ nOffs_act ;
int nMaxInd = pMCrv->GetCurveCount() - 1 ;
int nMaxRInd = pRCrv->GetCurveCount() - 1 ;
// determino l'affondamento attuale
double dSink = dElev - dDepth + dMaxElev - vVtTrasl[j-1].Len() ;
// ciclo sulle curve elementari
for ( int i = 0 ; i <= nMaxInd ; ++ i) {
// curva corrente
const ICurve* pCrvC = pMCrv->GetCurve( i) ;
// copio la curva
PtrOwner<ICurve> pCurve( pCrvC->Clone()) ;
if ( IsNull( pCurve))
return false ;
// aggiungo affondamento
pCurve->Translate( vVtTrasl[j-1]) ;
// se prima entità
if ( i == 0) {
// dati inizio entità
Point3d ptStart ;
pCurve->GetStartPoint( ptStart) ;
Vector3d vtStart ;
pCurve->GetStartDir( vtStart) ;
// Entrata ...
if ( j == 1 || vbChangedPrec[j-1] || vSrfSliced[j-2]->GetChunkCount() > 1 || nRegTot > 1) {
// Ricalcolo il punto di attacco sopra al PtStart ( modificato in precedenza dal PtOut ) quando :
// 1) sono nel primo Step o ...
// 2) la superificie è diversa da quello dello step precedente o ...
// 3) il numero di chunk allo step precedente è maggiore di 1 o ...
// 4) dal primo offset del chunk cc-esimo ottengo più regioni o ...
// determino inizio attacco
if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, pRCrv, ptP1))
return false ;
// determino elevazione su inizio attacco (se non trovata, elevazione è step)
double dStElev = dSink ;
dStElev -= ( ptP1 - ptStart) * vtExtr ;
// se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco
if ( GetLeadInType() == POCKET_LI_ZIGZAG ||
GetLeadInType() == POCKET_LI_HELIX ||
GetLeadInType() == POCKET_LI_GLIDE) {
ptP1 += vtExtr * dStElev ;
dStElev = 0 ;
}
// approccio al punto iniziale
if ( ! AddApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, bOutStart || bForcedOutStart)) {
m_pMchMgr->SetLastError( 2414, "Error in Pocketing : Approach not computable") ;
return false ;
}
//dStElev = max( dStElev, j * dStep) ;
// aggiungo attacco
SetFeed( GetStartFeed()) ;
if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrfLeanInOut, pRCrv, !m_Params.m_bInvert, bSplitArcs, bOutStart || bForcedOutStart)) {
m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ;
return false ;
}
}
// altrimenti solo collegamento
else {
SetFeed( GetStartFeed()) ;
GetCurrPos( ptP1) ;
if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrfLeanInOut, pRCrv, !m_Params.m_bInvert, bSplitArcs, bOutStart || bForcedOutStart)) {
m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ;
return false ;
}
}
}
// elaborazioni sulla curva corrente
double dMinFeed = GetFeed() * GetSideStep() / m_TParams.m_dDiam ;
double dFeed = pCurve->GetTempProp( 0) / FEED_DIVISOR < dMinFeed - 50 * EPS_SMALL ?
GetFeed() : pCurve->GetTempProp( 0) / FEED_DIVISOR ;
DrawColoredCrvForFeedTest( pCurve, dFeed) ;
SetFeed( dFeed) ;
if ( pCurve->GetType() == CRV_LINE) {
ICurveLine* pLine = GetCurveLine( pCurve) ;
Point3d ptP3 = pLine->GetEnd() ;
//SetFeed( GetFeed()) ;
//SetFeed( pCurve->GetTempProp( 0) / FEED_DIVISOR) ;
if ( AddLinearMove( ptP3) == GDB_ID_NULL)
return false ;
}
else if ( pCurve->GetType() == CRV_ARC) {
ICurveArc* pArc = GetCurveArc( pCurve) ;
Point3d ptCen = pArc->GetCenter() ;
double dAngCen = pArc->GetAngCenter() ;
Vector3d vtN = pArc->GetNormVersor() ;
Point3d ptP3 ;
pArc->GetEndPoint( ptP3) ;
//SetFeed( GetFeed()) ;
//SetFeed( pCurve->GetTempProp( 0) / FEED_DIVISOR) ;
if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL)
return false ;
}
// se ultima entità -> passo al chunk cc successivo o allo step sotto
if ( i == nMaxInd) {
// Uscita ...
if ( j < nStep && vSrfSliced[j-1]->GetChunkCount() == 1 && ! vbChangedPrec[j] && nRegTot == 1) {
// Effettuo l'uscita quando :
// 1) non sono nello step intermedio e ...
// 2) il numero di Chunk allo step attuale è 1 e...
// 3) la superificie non è cambiata dalla precedente e...
// 4) dal primo offset del chunk cc-esimo non si sono create altre regioni da svuotare
// se necessario ritorno all'inizio
if ( nMaxRInd >= 0) {
// copio la curva di ritorno
PtrOwner<ICurveComposite> pRet( pRCrv->Clone()) ;
if ( IsNull( pRet))
return false ;
// aggiungo affondamento
pRet->Translate( vVtTrasl[j-1]) ;
// se attacco a scivolo, accorcio della lunghezza dell'attacco
if ( GetLeadInType() == POCKET_LI_GLIDE) {
double dLen ; pRet->GetLength( dLen) ;
if ( dLen > m_Params.m_dLiTang + 10 * EPS_SMALL)
if ( ! pRet->TrimEndAtLen( dLen - m_Params.m_dLiTang))
pRet->Clear() ;
else
pRet->Clear() ;
}
// emetto
SetFeed( GetFeed()) ;
if ( pRet->GetCurveCount() > 0 && AddCurveMove( pRet) == GDB_ID_NULL)
return false ;
}
}
// atrimenti ultimo step, uscita e retrazione
else {
// dati fine entità
Point3d ptEnd ;
pCurve->GetEndPoint( ptEnd) ;
Vector3d vtEnd ;
pCurve->GetEndDir( vtEnd) ;
// aggiungo uscita
Point3d ptP1 ;
double dEndElev = dSink ;
SetFeed( GetEndFeed()) ;
if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, pRCrv, bSplitArcs, false, ptP1, dEndElev, true)) {
m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ;
return false ;
}
// aggiungo retrazione
if ( ! AddRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) {
m_pMchMgr->SetLastError( 2417, "Error in Pocketing : Retract not computable") ;
return false ;
}
}
}
}
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AddSpiralOut( const ISurfFlatRegion* pSrfPock, const Vector3d& vtTool, const Vector3d& vtExtr,
double dDepth, double dElev, double dMaxElev, double dOkStep, bool bSplitArcs)
{
// recupero distanze di sicurezza
double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ;
double dSafeAggrBottZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeAggrBottZ() ;
// lunghezza di approccio/retrazione
double dAppr = m_Params.m_dStartPos ;
// determino numero e affondamento degli step
int nStep = 1 ;
nStep = max( 1, static_cast<int>( ceil( dElev / dOkStep))) ;
double dStep = dElev / nStep ;
// ciclo sui chunk della superificie da svuotare
for ( int c = 0 ; c < pSrfPock->GetChunkCount() ; ++ c) {
// copio il chunk c-esimo
PtrOwner<ISurfFlatRegion> pSrfChunk( GetSurfFlatRegion( pSrfPock->CloneChunk( c))) ;
if ( IsNull( pSrfChunk))
return false ;
// modifico le superifici in base alla geometria del grezzo e alla geometria dell'entità selezionata
ISURFFRPOVECTOR vSrfSliced( nStep) ;
vector<ICRVCOMPOPOVECTOR> vCrvOEWithFlags( nStep) ;
BOOLVECTOR vbChangedPrec( nStep, false) ;
VCT3DVECTOR vVtTrasl( nStep, V_NULL) ;
if ( ! GetParamsAtEachStep( vSrfSliced, vCrvOEWithFlags, vbChangedPrec, vVtTrasl, pSrfChunk,
nStep, vtTool, dElev, dDepth, dStep))
return false ;
Point3d ptP1, ptStartPrec ; // per LeadIn attuale e precedente
bool bMidOutPrec ; // flag per entrata precedente da fuori dal grezzo
BOOLVECTOR vbMidOutPrec ; // flags per effettiva entrata precedente da fuori dal grezzo
ICRVCOMPOPOVECTOR vMCrv_step_prec ; // vettore delle curve dei percorsidi svuotatura dello step precedente
ICRVCOMPOPOVECTOR vRCrv_step_prec ; // vettore delle curve dei percorsi di ritorno dello step precedente
vector<Vector3d> vvtMidOutPrec ; // vettore dei versori delle direzioni di uscita dello step precedente
INTVECTOR vnRegTot_prec ; // vettore dei numeri delle regioni formate dal primo Offset nello step precedente
int nOffs_act = 0 ;
// ciclo su tutti gli step
for ( int j = 1 ; j <= nStep ; ++ j) {
// se superificie non valida, salto allo step successivo
if ( IsNull( vSrfSliced[ j-1]) || vSrfSliced[j-1]->GetChunkCount() == 0) {
vSrfSliced[j-1].Set( pSrfChunk->Clone()) ;
continue ;
}
// la superificie che lavoro è quella ottenuta in precedenza allo step j-esimo
PtrOwner<ISurfFlatRegion> pSrfFinal( CloneSurfFlatRegion( vSrfSliced[j - 1])) ;
if( IsNull( pSrfFinal))
return false ;
nOffs_act = 0 ; // reset indice dei vettori per step precedenti
if ( vbChangedPrec[j-1]) {
// se lo step attuale è cambiato rispetto al precedente -> Flush info step precedente
vMCrv_step_prec.clear() ;
vRCrv_step_prec.clear() ;
vnRegTot_prec.clear() ;
vbMidOutPrec.clear() ;
vvtMidOutPrec.clear() ;
}
for ( int cc = 0 ; cc < ( int)pSrfFinal->GetChunkCount() ; ++ cc) { // per ogni suo chunk cc-esimo...
const int MAX_REGS = 50 ;
int nReg = 0 ;
PtrOwner<ISurfFlatRegion> pSrfChunkFinal(( pSrfFinal->CloneChunk( cc))) ;
while ( nReg < MAX_REGS) {
// superificie per ingressi ed uscite
PtrOwner<ISurfFlatRegion> pSrfLeanInOut( CloneSurfFlatRegion( pSrfChunkFinal)) ;
if( IsNull( pSrfLeanInOut))
return false ;
// calcolo la spirale dall'interno all'esterno
PtrOwner<ICurveComposite> pMCrv( CreateCurveComposite()) ;
PtrOwner<ICurveComposite> pRCrv( CreateCurveComposite()) ;
if ( IsNull( pMCrv) || IsNull( pRCrv)) {
m_pMchMgr->SetLastError( 2411, "Error in Pocketing : toolpath allocation failed") ;
return false ;
}
int nRegTot ; // numero di regioni create dal primo Offset per lo step attuale
bool bOutStart ; // flag per entrata da fuori per lo step attuale
bool bForcedOutStart ; // flag per forzare l'entrata da fuori allo step attuale
Point3d ptStart ; // punto iniziale del percorso
Vector3d vtMidOut ; // vettore verso l'esterno nel caso di entrata da fuori ammissibile ( -> da CalcSpiral)
bool bMidOut ; // ammissibilità entrata da fuori ( da calcolare step per step)
bool bOptimizedTrap = false ; // se ho un caso spirale o trapezio
// NB. se la superficie è rimasta la stessa, utilizzo pMCrv e pRCrv dello step precedente
// ( non c'è bisogno di ricalcolare tutti i percorsi)
if ( ! vbChangedPrec[j-1] && j != 1) {
if ( nOffs_act > ( int)vMCrv_step_prec.size() - 1)
break ;
pMCrv.Set( vMCrv_step_prec[nOffs_act]->Clone()) ;
pRCrv.Set( vRCrv_step_prec[nOffs_act]->Clone()) ;
nRegTot = vnRegTot_prec[nOffs_act] ;
bMidOut = vbMidOutPrec[nOffs_act] ;
vMCrv_step_prec[nOffs_act]->GetStartPoint( ptStart) ;
vtMidOut = vvtMidOutPrec[nOffs_act] ;
}
else {
// se lucidatura con epicicli
if ( m_TParams.m_nType == TT_MILL_POLISHING && m_Params.m_dEpicyclesRad > EPS_SMALL) {
// verifico che parametri lucidatura siano sensati
if ( m_Params.m_dEpicyclesDist < 100 * EPS_SMALL) {
m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ;
return false ;
}
// modifico il diametro dell'utensile per tenere conto anche del raggio degli epicicli
m_TParams.m_dDiam += 2 * m_Params.m_dEpicyclesRad ;
}
bool bOptimizedTrap = false ;
int nInd = 0 ;
// cerco la curva originale del chunk cc-esimo ( PER CASI OTTIMIZZATI)
if (( int)vCrvOEWithFlags[j-1].size() == 1)
nInd = 0 ;
else {
for ( int k = 0 ; k < ( int)vCrvOEWithFlags[j-1].size() ; ++ k) {
CRVCVECTOR ccClass ;
if ( pSrfChunkFinal->GetCurveClassification( *vCrvOEWithFlags[j-1][k], EPS_SMALL, ccClass)) {
bool bIsThis = true ;
for ( int kk = 0 ; kk < ( int)ccClass.size() && bIsThis ; ++ kk) {
if ( ccClass[kk].nClass == CRVC_OUT)
bIsThis = false ;
}
if ( bIsThis) {
nInd = k ;
break ;
}
}
}
}
nRegTot = nReg ;
if ( ! CalcSpiral( pSrfChunkFinal, nRegTot, ptStart, vtMidOut, bMidOut, bSplitArcs, pMCrv, pRCrv,
vCrvOEWithFlags[j-1][nInd], vbChangedPrec[j-1], bOptimizedTrap))
return false ;
// se terminate le regioni, esco
if ( pMCrv->GetCurveCount() == 0)
break ;
if ( m_TParams.m_nType == TT_MILL_POLISHING && m_Params.m_dEpicyclesRad > EPS_SMALL) {
// riporto il diametro dell'utensile al valore originale
m_TParams.m_dDiam -= 2 * m_Params.m_dEpicyclesRad ;
// aggiorno i percorsi di svuotatura con epicicli
if ( ! ComputePolishingPath( pMCrv, pRCrv, bSplitArcs)) {
m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ;
return false ;
}
}
// memorizzo le curve create e modificate per lo step successivo
vMCrv_step_prec.emplace_back( pMCrv->Clone()) ;
vRCrv_step_prec.emplace_back( pRCrv->Clone()) ;
// memorizzo i Flag per le entrate
vbMidOutPrec.push_back( bMidOut) ;
// memorizzo il numero delle regioni create dal primo Offset
vnRegTot_prec.push_back( nRegTot) ;
// memorizzo il versore di uscita calcolato
vvtMidOutPrec.push_back( vtMidOut) ;
}
// nel caso ottimizzato verifico se posso entrare e uscire fuori dal grezzo
bOutStart = false ;
int nOutsideRaw = 0 ;
if ( bOptimizedTrap) {
AdjustTrapezoidSpiralForLeadInLeadOut( pMCrv, pRCrv, vtTool, dDepth, nOutsideRaw) ;
bOutStart = ( nOutsideRaw > 0) ;
AssignFeedSpiralOpt( 1, pMCrv) ;
AssignFeedForReturnPath( pRCrv) ;
}
// se utensile che non lavora di testa e ingresso non fuori dal pezzo, errore
if ( m_TParams.m_nType == TT_MILL_NOTIP && ! bOutStart) {
if ( ! LeadInRawIsOk()) {
m_pMchMgr->SetLastError( 2431, "Error in Pocketing : LeadIn with Mill NoTip in material") ;
return false ;
}
}
// inverto i percorsi, perchè sono calcolati dall'esterno all'interno (solo nel caso non ottimizzato)
if ( ! bOptimizedTrap) {
pMCrv->Invert() ;
pRCrv->Invert() ;
}
// inversione per caso ottimizzato
if ( bOptimizedTrap && nOutsideRaw != 1 && j > 1)
pMCrv->Invert() ;
++ nReg ;
++ nOffs_act ;
int nMaxInd = pMCrv->GetCurveCount() - 1 ;
int nMaxRInd = pRCrv->GetCurveCount() - 1 ;
// ciclo sulle curve elementari
for ( int i = 0 ; i <= nMaxInd ; ++ i) {
// curva corrente
const ICurve* pCrvC = pMCrv->GetCurve( i) ;
// copio la curva
PtrOwner<ICurve> pCurve( pCrvC->Clone()) ;
if ( IsNull( pCurve))
return false ;
// aggiungo affondamento
pCurve->Translate( vVtTrasl[j-1]) ;
// se prima entità
if ( i == 0) {
// dati inizio entità
Point3d ptStart ;
pCurve->GetStartPoint( ptStart) ;
Vector3d vtStart ;
pCurve->GetStartDir( vtStart) ;
// se primo step, approccio e affondo
if ( j == 1 || vbChangedPrec[j-1] || vSrfSliced[j-2]->GetChunkCount() > 1 || nRegTot > 1) {
// determino inizio attacco
if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, pRCrv, ptP1)) {
m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ;
return false ;
}
// determino elevazione su inizio attacco
double dStElev ;
if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev))
dStElev = dStep ;
bool bAhUnderRaw = m_bAboveHead && ! m_bAggrBottom && ! m_bTiltingTab &&
GetAhPointUnderRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(),
m_TParams.m_dLen, false, dSafeZ, vtTool, dStElev) ;
bool bUhAboveRaw = ! m_bAboveHead &&
GetUhPointAboveRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(),
m_TParams.m_dLen, false, dSafeZ, vtTool, dStElev) ;
//if ( bAhUnderRaw || bUhAboveRaw || m_bTiltingTab)
dStElev = max( dStElev, j * dStep) ;
dStElev -= ( ptP1 - ptStart) * vtExtr ;
// se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco
if ( GetLeadInType() == POCKET_LI_ZIGZAG ||
GetLeadInType() == POCKET_LI_HELIX ||
GetLeadInType() == POCKET_LI_GLIDE) {
ptP1 += vtExtr * dStElev ;
dStElev = 0 ;
}
// approccio al punto iniziale
if ( ! AddApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, false)) {
m_pMchMgr->SetLastError( 2414, "Error in Pocketing : Approach not computable") ;
return false ;
}
// aggiungo attacco
SetFeed( GetStartFeed()) ;
if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrfLeanInOut, pRCrv, m_Params.m_bInvert, bSplitArcs, bOutStart)) {
m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ;
return false ;
}
}
// altrimenti solo collegamento
else {
SetFeed( GetStartFeed()) ;
GetCurrPos( ptP1) ;
if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrfLeanInOut, pRCrv, m_Params.m_bInvert, bSplitArcs, bOutStart)) {
m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ;
return false ;
}
}
}
// elaborazioni sulla curva corrente
double dMinFeed = GetFeed() * GetSideStep() / m_TParams.m_dDiam ;
double dFeed = pCurve->GetTempProp( 0) / FEED_DIVISOR < dMinFeed - 50 * EPS_SMALL ?
GetFeed() : pCurve->GetTempProp( 0) / FEED_DIVISOR ;
//DrawColoredCrvForFeedTest( pCurve, dFeed) ;
SetFeed( dFeed) ;
if ( pCurve->GetType() == CRV_LINE) {
ICurveLine* pLine = GetCurveLine( pCurve) ;
Point3d ptP3 = pLine->GetEnd() ;
//SetFeed( GetFeed()) ;
//SetFeed( pCurve->GetTempProp( 0) / FEED_DIVISOR) ;
if ( AddLinearMove( ptP3) == GDB_ID_NULL)
return false ;
}
else if ( pCurve->GetType() == CRV_ARC) {
ICurveArc* pArc = GetCurveArc( pCurve) ;
Point3d ptCen = pArc->GetCenter() ;
double dAngCen = pArc->GetAngCenter() ;
Vector3d vtN = pArc->GetNormVersor() ;
Point3d ptP3 ;
pArc->GetEndPoint( ptP3) ;
//SetFeed( GetFeed());
//SetFeed( pCurve->GetTempProp( 0 ) / FEED_DIVISOR) ;
if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL)
return false ;
}
// se ultima entità
if ( i == nMaxInd) {
// se step intermedio
if ( j < nStep && vSrfSliced[j-1]->GetChunkCount() == 1 && !vbChangedPrec[j] && nRegTot == 1) {
// se necessario ritorno all'inizio
if ( nMaxRInd >= 0) {
// copio la curva di ritorno
PtrOwner<ICurveComposite> pRet( pRCrv->Clone()) ;
if ( IsNull( pRet))
return false ;
// aggiungo affondamento
pRet->Translate( vVtTrasl[j-1]) ;
// se attacco a scivolo, accorcio della lunghezza dell'attacco
if ( GetLeadInType() == POCKET_LI_GLIDE) {
double dLen ; pRet->GetLength( dLen) ;
if ( dLen > m_Params.m_dLiTang + 10 * EPS_SMALL)
if ( ! pRet->TrimEndAtLen( dLen - m_Params.m_dLiTang))
pRet->Clear() ;
else
pRet->Clear() ;
}
// emetto
SetFeed( GetFeed()) ;
if ( pRet->GetCurveCount() > 0 && AddCurveMove( pRet) == GDB_ID_NULL)
return false ;
}
}
// atrimenti ultimo step, uscita e retrazione
else {
// dati fine entità
Point3d ptEnd ;
pCurve->GetEndPoint( ptEnd) ;
Vector3d vtEnd ;
pCurve->GetEndDir( vtEnd) ;
// aggiungo uscita
Point3d ptQ ;
double dEndElev = dElev ;
SetFeed( GetEndFeed()) ;
if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, pRCrv, bSplitArcs, false, ptQ, dEndElev, false)) {
m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ;
return false ;
}
// aggiungo retrazione
if ( ! AddRetract( ptQ, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) {
m_pMchMgr->SetLastError( 2417, "Error in Pocketing : Retract not computable") ;
return false ;
}
}
}
}
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::CalcSpiral( const ISurfFlatRegion* pSrfPock, int& nReg, Point3d& ptStart, Vector3d& vtMidOut , bool& bMidOut,
bool bSplitArcs,ICurveComposite* pMCrv, ICurveComposite* pRCrv, ICurveComposite* pCrvOEWithFlags,
bool bChangedPrec, bool& bOptimizedTrap)
{
// inizializzo i risultati
pMCrv->Clear() ;
pRCrv->Clear() ;
// primo offset pari al raggio utensile + sovramateriale
double dTRad = 0.5 * m_TParams.m_dDiam ;
double dOffs = dTRad + GetOffsR() ;
// recupero il versore normale della superificie, ruotandola nel piano XY
PtrOwner<ISurfFlatRegion> pSrfToWork( pSrfPock->Clone()) ;
if ( IsNull( pSrfToWork) || pSrfToWork->GetChunkCount() == 0)
return false;
// porto il Chunk c-esimo nel sistema di riferimento locale (assieme al punto inziale)
Vector3d vtExtr = pSrfToWork->GetNormVersor() ;
Point3d ptCen ; pSrfToWork->GetCentroid( ptCen) ;
Frame3d frPocket ; frPocket.Set( ptCen, vtExtr) ;
// controllo se ho isole per i casi ottimizzati
bool bHasIsland = pSrfPock->GetLoopCount( 0) > 1 ;
// se non ho isole e curva valida allora controllo casi ottimizzati
if ( ! bHasIsland && pCrvOEWithFlags != nullptr) {
// caso spirale
PtrOwner<ICurveComposite> pCrvBorder( GetCurveComposite( pSrfPock->GetLoop( 0, 0))) ;
pCrvBorder->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ;
Point3d ptCen ; Vector3d vtN ; double dRad ; bool bCCW ;
if ( pCrvBorder->IsACircle( 100 * EPS_SMALL, ptCen, vtN, dRad, bCCW)) {
double dIntRad = 0 ;
if ( m_Params.m_nSubType == POCKET_SUB_SPIRALOUT && GetLeadInType() == POCKET_LI_HELIX) {
dIntRad = min( 0.5 * min( m_Params.m_dLiTang, m_TParams.m_dDiam), dRad - dOffs) ;
m_dMaxHelixRad = dIntRad ;
}
if ( nReg == 0) {
bool bOk = CalcCircleSpiral( ptCen, vtN, dRad - dOffs, dIntRad, bSplitArcs, pMCrv, pRCrv) ;
if ( bOk) {
pMCrv->GetStartPoint( ptStart) ;
nReg = 1 ;
pMCrv->GetStartDir( vtMidOut) ;
Vector3d vtExtr ; pMCrv->GetExtrusion( vtExtr) ;
vtMidOut.Rotate( vtExtr, 0, m_Params.m_bInvert ? 1 : -1) ;
bMidOut = pCrvBorder->GetFirstCurve()->GetTempProp() == 1 ;
return true ;
}
else
return false ;
}
else
return true ;
}
// caso trapezoide
PtrOwner<ICurveComposite> pCrvTrap( CreateCurveComposite()) ;
if ( IsNull( pCrvTrap))
return false ;
pCrvOEWithFlags->ToLoc( frPocket) ;
Frame3d frTrap ;
double dPocketSize ;
int nBase, nSecondBase ;
if ( ! GetTrapezoidFromShape( pCrvOEWithFlags, m_dDiam_Prec > 0 ? m_dDiam_Prec + m_dOffsetR_Prec :
m_TParams.m_dDiam + GetOffsR(),
pCrvTrap, frTrap, dPocketSize, nBase, nSecondBase))
return false ;
if ( pCrvTrap->IsValid()) {
pCrvTrap->SetExtrusion( vtExtr) ;
if ( nReg == 0) {
CalcTrapezoidSpiral( pCrvTrap, frTrap, dPocketSize, nBase, nSecondBase, pMCrv, pRCrv, bOptimizedTrap) ;
if ( bOptimizedTrap) {
// ----
pCrvTrap->ToGlob( frPocket) ;
if ( pCrvTrap->IsValid()) {
for ( int u = 0 ; u < pCrvTrap->GetCurveCount() ; ++ u) {
const ICurve* pCrv = pCrvTrap->GetCurve( u) ;
int a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrv->Clone()) ;
m_pGeomDB->SetMaterial( a, pCrv->GetTempProp( 0) == 0 ? BLUE : RED) ;
}
}
// ----
pMCrv->ToGlob( frPocket) ;
pRCrv->ToGlob( frPocket) ;
nReg = 1 ;
return true ;
}
}
else
return true ;
}
return false ;
}
// porto la superficie nel frame della svuotatura
pSrfToWork->ToLoc( frPocket) ;
// ciclo di offset verso l'interno
const int MAX_ITER = 1000 ;
int nIter = 0 ;
ICRVCOMPOPOVECTOR vOffs ; // vettore delle curve di offset
ICRVCOMPOPOVECTOR vOffsFirstCurve ; // curve di primo offset
PtrOwner<ISurfFlatRegion> pSrfAct( CloneSurfFlatRegion( pSrfToWork)) ; // regione attuale
PtrOwner<ISurfFlatRegion> pSrfPrec( CloneSurfFlatRegion( pSrfToWork)) ; // regione precedente
if( IsNull( pSrfAct) || IsNull( pSrfPrec) || pSrfAct->GetChunkCount() == 0 || pSrfPrec->GetChunkCount() == 0)
return false ;
while ( nIter < MAX_ITER) {
// salvo la regione
pSrfPrec.Set( pSrfAct->Clone()) ;
if ( ! pSrfAct->Offset( - dOffs, ICurve::OFF_FILLET)) {
//int nbadOffs = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrfPrec->Clone()) ;
//m_pGeomDB->Save( nbadOffs, "C:\\Users\\riccardo.elitropi\\Desktop\\Err_offs" + ToString( nbadOffs) + "__m" + ToString( dOffs) + ".nge") ;
return false ;
}
// estraggo il contorno della FlatRegion (ciclo i Chunks e prendo i rispettivi Loops)
if ( nIter == 0) {
PtrOwner<ISurfFlatRegion> pSrfChunknReg( pSrfAct->CloneChunk( nReg)) ;
nReg = pSrfAct->GetChunkCount() ; // modifico nReg per le uscite
if ( IsNull( pSrfChunknReg)) // se supero i chunk ottenuti
return true ;
pSrfAct.Set( pSrfChunknReg) ;
}
int nChunks = pSrfAct->GetChunkCount();
for ( int i = 0 ; i < nChunks ; ++ i) {
// per ogni chunk...
int nLoops = pSrfAct->GetLoopCount( i) ;
for ( int j = 0 ; j < nLoops ; ++ j) {
// per ogni loop...
PtrOwner<ICurveComposite> ptoCCBorder( GetCurveComposite( pSrfAct->GetLoop( i, j))) ;
if ( j > 0) // inverto l'orientamento delle curve interne (offset delle isole trovate)
ptoCCBorder->Invert() ;
// controllo quali regioni di Offset possono essere sostituite
bool bInsert = true ;
if ( ! CheckIfOffsetIsNecessary( ptoCCBorder, dOffs, ( int)vOffs.size(), nIter, vtExtr, bInsert))
return false ;
if ( bInsert) {
vOffs.emplace_back( Release( ptoCCBorder)) ;
}
PtrOwner<ICurveComposite> ptoCCExtBorder( GetCurveComposite( pSrfAct->GetLoop( i, j))) ;
if ( nIter == 0) { // salvo il bordo per i link (non invertiti)
vOffsFirstCurve.emplace_back( Release( ptoCCExtBorder)) ;
}
}
}
bool bSmallRad = ( nIter == 0 ? dOffs < dTRad + GetOffsR() + EPS_ZERO : dOffs < dTRad + EPS_ZERO) ;
if ( nChunks > 0)
dOffs = GetSideStep() ;
else if ( ! bSmallRad) {
pSrfAct.Set( pSrfPrec) ;
dOffs = ( nIter == 0 ? dTRad + GetOffsR() : dTRad) ;
}
else
break ;
++ nIter ;
}
// se non ho trovato curve di Offset allora esco
if (( int)vOffs.size() == 0)
return true ;
// cambio il punto iniziale della prima Curva di Offset
Point3d ptNewStart ;
double dOffR ;
if (( int)vOffs.size() > 1)
dOffR = dTRad + GetOffsR() ;
else
dOffR = dOffs ;
if ( SetBetterPtStartForSubChunks( vOffs[0], pSrfToWork, ptStart, vtMidOut, bMidOut))
vOffs[0]->GetStartPoint( ptNewStart) ;
else
return false ;
// se richiesta inversione
for ( int i = 0 ; i < ( int)vOffs.size() && m_Params.m_bInvert ; ++ i)
vOffs[i]->Invert() ;
// smusso le curve di offset ( ad eccezione della prima)
ICRVCOMPOPOVECTOR vOffsClosedCurves( vOffs.size()) ; // vettore con tutte le curve di Offset Chiuse
for ( int i = 0 ; i < int( vOffs.size()) ; ++i ) {
if ( i != 0)
ModifyCurveToSmoothed( vOffs[i], 0.01, 0.01) ;
vOffs[i]->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ;
vOffsClosedCurves[i].Set( vOffs[i]->Clone()) ;
}
for ( int i = 0 ; i < int( vOffsFirstCurve.size()) ; ++ i) {
if ( i != 0)
ModifyCurveToSmoothed( vOffsFirstCurve[i], 0.01, 0.01) ;
vOffsFirstCurve[i]->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ;
}
// setto il punto iniziale della svuotatura
double dNewUS ;
vOffs[0]->GetParamAtPoint( ptNewStart, dNewUS) ;
vOffs[0]->ChangeStartPoint( dNewUS) ;
// riordino le curve cambiando il loro punto di inizio e creando poi i collegamenti
int nClosestInd = -1 ; int nFlag ;
double dDist = INFINITO ;
Point3d ptHelp ;
ICURVEPOVECTOR vLinks( vOffs.size()) ;
for ( int i = 0 ; i < int( vOffs.size()) - 1 ; ++ i) {
Point3d ptS ;
if ( ! vOffs[i]->GetStartPoint( ptS))
return false ;
// setto i default delle variabili
if ( ! DistPointCurve( ptS, *vOffs[i+1]).GetMinDistPoint( EPS_SMALL, ptHelp, nFlag))
return false ;
dDist = INFINITO ;
for ( int j = i + 1 ; j <= int( vOffs.size()) - 1 ; ++ j) {
// cerco il punto più vicino della curva
Point3d ptE ;
if ( ! DistPointCurve( ptS, *vOffs[j]).GetMinDistPoint( EPS_SMALL, ptE, nFlag))
return false ;
if ( dDist > Dist( ptS, ptE) ) {
dDist = Dist( ptS, ptE) ;
nClosestInd = j ;
ptHelp.Set( ptE.x, ptE.y, ptE.z) ;
}
}
// avendo la curva più vicina ...
// 1) scambio la curva i con la curva nClosestInd
if ( nClosestInd != i + 1) {
PtrOwner<ICurveComposite> ptoCCHelp( Release( vOffs[i + 1])) ;
vOffs[i + 1].Set( vOffs[nClosestInd]) ;
vOffs[nClosestInd].Set( ptoCCHelp) ;
}
// 2) cambio il suo punto iniziale ...
double dU ;
Point3d ptNE( ptHelp.x, ptHelp.y, ptHelp.z) ;
if ( ! vOffs[i + 1]->GetParamAtPoint( ptNE, dU))
return false ;
vOffs[i + 1]->ChangeStartPoint( dU) ;
// 2.1) Accorcio la curva per velocizzare ...
if (( int)vOffs.size() > 1) { // accorcio se ho almeno due Offset
// copio le curve i e i+1 nel caso non riesca a tagliarle ...
double dUNS, dUNE ;
PtrOwner<ICurveComposite> pCrvTest( CreateCurveComposite()) ; // possibile collegamento tra la curva i ed i+1
PtrOwner<ICurveComposite> pOff_i0( CloneCurveComposite( vOffs[i])) ;
PtrOwner<ICurveComposite> pOff_i1( CloneCurveComposite( vOffs[i + 1])) ;
// cerco di tagliare le curve, ottenendo il collegamento
// NB. se la curva di offset è la prima, non devo tagliarla, accorcio solo le successive ...
if ( ! CutCurveToConnect( vOffs[i], vOffs[i+1], vOffsClosedCurves, vOffsFirstCurve, pCrvTest, i == 0 ? 0 : 0.01)) {
// se non sono riuscito, ritorno alla configurazione iniziale
PtrOwner<ICurveComposite> pCrvLink( CreateCurveComposite()) ;
Vector3d vS, vE ;
vOffs[i].Set( pOff_i0) ; vOffs[i+1].Set( pOff_i1) ;
if ( ! vOffs[i]->GetStartDir( vS) || ! vOffs[i+1]->GetStartDir( vE))
return false ;
if ( CalcBoundedSmootedLink( ptS, vS, ptNE, vE, 0.5, vOffsFirstCurve, pCrvLink))
vLinks[i + 1].Set( pCrvLink) ; // aggiorno il collegamento
else {
m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ;
return false ;
}
continue ;
}
if ( ! pCrvTest->GetStartPoint( ptS) ||
! pCrvTest->GetEndPoint( ptNE) ||
! vOffs[i]->GetParamAtPoint( ptS, dUNS) ||
! vOffs[i+1]->GetParamAtPoint( ptNE, dUNE))
return false ;
// imposto il nuovo punto inziale della curva successiva
vOffs[i+1]->ChangeStartPoint( dUNE) ;
PtrOwner<ICurveComposite> pCrvNewOffS( CloneCurveComposite( vOffs[i])) ;
if ( dUNS > EPS_SMALL) { // se parametro di trim sufficientemente grande
pCrvNewOffS.Set( GetCurveComposite( vOffs[i]->CopyParamRange( 0, dUNS))) ;
// sostituisco la curva i-esima con quella tagliata
vOffs[i]->Clear() ;
vOffs[i].Set( pCrvNewOffS) ;
}
// aggiorno il collegamento
vLinks[i + 1].Set( pCrvTest) ;
}
}
// copio il vettore degli Offset per settare poi la Feed
ICRVCOMPOPOVECTOR vOffsFeed ; vOffsFeed.reserve(( int)vOffs.size()) ;
for ( int i = 0 ; i < ( int)vOffs.size() ; ++ i)
vOffsFeed.emplace_back( vOffs[i]->Clone()) ;
// 3) controllo eventuali parti non svuotate...
pCrvOEWithFlags->ToLoc( frPocket) ;
PtrOwner<ISurfFlatRegion> pSrfToCut( CreateSurfFlatRegion()) ;
if ( GetUnclearedRegion( vOffsFirstCurve, vOffs, vLinks, pCrvOEWithFlags, pSrfToCut)) {
// 4) Modifico i percorsi
if ( ! RemoveExtraParts( pSrfToCut, vOffs, vOffsClosedCurves, vOffsFirstCurve, vLinks))
return false ;
}
// calcolo il percorso di ritorno
if (( int)vOffs.size() >= 2) {
pRCrv->Clear() ;
// punto inziale e finale | vettore iniziale e finale
Point3d ptStart ; vOffs.back()->GetEndPoint( ptStart) ;
Point3d ptEnd ; vOffs.front()->GetStartPoint( ptEnd) ;
Vector3d vtStart ; vOffs.back()->GetEndDir( vtStart) ;
Vector3d vtEnd ; vOffs.front()->GetStartDir( vtEnd) ;
// calcolo il ritorno (garantendo che non esca dalla svuotatura)
PtrOwner<ICurveComposite> pCrvLink( CreateCurveComposite()) ;
if ( CalcBoundedSmootedLink( ptStart, vtStart, ptEnd, vtEnd, 0.5, vOffsFirstCurve, pCrvLink)) {
pRCrv->AddCurve( Release( pCrvLink)) ;
pRCrv->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, false) ;
// se necessario, approssimo archi con rette
if ( bSplitArcs && ! ApproxWithLines( pRCrv)) {
m_pMchMgr->SetLastError( 2421, "Error in Pocketing : Linear Approx not computable") ;
return false ;
}
VerifyArcs( pRCrv) ;
}
else {
m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ;
return false ;
}
// Feed per percorso di ritorno
AssignFeedForReturnPath( pRCrv) ;
}
// creo il percorso di lavoro a partire dalla raccolta degli offset e dei collegamenti
for ( int i = 0 ; i < int( vOffs.size()) ; ++i) {
// se collegamento da aggiungere
if ( ! IsNull( vLinks[i])) {
int nCrvsCount0 = pMCrv->GetCurveCount() ;
// accodo nel percorso di lavorazione
if ( ! pMCrv->AddCurve( vLinks[i]->Clone()))
return false ;
// nel caso di lucidatura setto proprietà alle curve di collegamento per poterle identificare
if ( m_TParams.m_nType == TT_MILL_POLISHING) {
for ( int j = nCrvsCount0 ; j < pMCrv->GetCurveCount() ; ++ j)
pMCrv->SetCurveTempProp( j, LINK_CURVE_PROP) ;
}
}
pMCrv->AddCurve( vOffs[i]->Clone()) ;
}
// verifico il percorso di lavoro
if ( pMCrv->GetCurveCount() == 0) {
m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ;
return false ;
}
// se necessario, approssimo archi con rette
if ( bSplitArcs && ! ApproxWithLines( pMCrv)) {
m_pMchMgr->SetLastError( 2421, "Error in Pocketing : Linear Approx not computable") ;
return false ;
}
// eventuale sistemazione archi
VerifyArcs( pMCrv) ;
// setto estrusione
pMCrv->SetExtrusion( vtExtr) ;
// riporto tutto nel sistema di riferimento originale
pMCrv->ToGlob( frPocket) ;
pRCrv->ToGlob( frPocket) ;
ptStart.ToGlob( frPocket) ;
vtMidOut.ToGlob( frPocket) ;
pCrvOEWithFlags->ToGlob( frPocket) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::ModifyCurveToSmoothed( ICurveComposite* pCrv, double dRightPer, double dLeftPer)
{
// controllo parametri
if ( pCrv == nullptr)
return false ;
ICURVEPOVECTOR vCrvStepsToFill ; // vettore delle Curve da raccordare (curve della composita)
ICURVEPOVECTOR vCrvArcs ; // vettore contenente gli Archi (tra le curve della composita)
INTVECTOR vArcsToJump ; // vettore di indici per gli archi saltati (nel caso non si riesca a raccordare ...)
// se nella composita ho meno di due curve allora non c'è nulla da raccordare
const ICurve* pMyCrv = pCrv->GetFirstCurve() ;
while ( pMyCrv != nullptr) {
vCrvStepsToFill.emplace_back( pMyCrv->Clone()) ;
pMyCrv = pCrv->GetNextCurve() ;
}
if ( vCrvStepsToFill.size() < 2)
return false ;
// controllo se la curva è chiusa (nel caso inserisco nel vettore la prima curva due volte, all'inizio e alla fine)
if ( pCrv->IsClosed()) {
const ICurve* pMyCrvFirst = pCrv->GetFirstCurve() ;
vCrvStepsToFill.emplace_back( pMyCrvFirst->Clone()) ;
}
double dUE_ref, dUS_ref, dRadius, dPar1, dPar2 ;
// riempio il vettore degli archi, scorro tutte le curve da raccordare ( la i-esima e la (i+1)-esima )
for ( int i = 0 ; i < int( vCrvStepsToFill.size()) - 1 ; ++ i) {
// controllo che le curve non siano già tangenti
Vector3d vtS, vtE ;
if ( ! vCrvStepsToFill[i]->GetEndDir( vtS) || ! vCrvStepsToFill[i+1]->GetStartDir( vtE))
continue ;
if ( AreSameVectorApprox( vtS, vtE)) {
vCrvArcs.emplace_back( CreateCurveComposite()) ; // arco nullo
vArcsToJump.push_back( i) ; // da scartare
continue ;
}
// cerco i paramentri al dRightPer% e dLeftPer% della lunghezza della prima e della seconda curva ( per raccordarli )
double dU_cm_S = 0 ; double dULast1 = 1 ; double dULast2 = 1 ;
vCrvStepsToFill[i]->GetDomain( dU_cm_S, dULast1) ;
dUE_ref = ( 1 - dRightPer) * dULast1 ;
vCrvStepsToFill[i+1]->GetDomain( dU_cm_S, dULast2) ;
dUS_ref = dLeftPer * dULast2 ;
// prendo i punti sulle due curve rispetto a tali parametri
Point3d ptS, ptE ;
if ( ! vCrvStepsToFill[i]->GetPointD1D2( dUE_ref, ICurve::FROM_PLUS, ptS) ||
! vCrvStepsToFill[i+1]->GetPointD1D2( dUS_ref, ICurve::FROM_MINUS, ptE))
return false ;
dRadius = Dist( ptS, ptE) ; // uso come raggio la distanza tra i due punti
int nMaxTestForArcs = 3 ; // tentativi per creare l'arco
int nIterForArcs = 0 ;
bool IntersBTWArcs = false ;
// creo l'arco di raccordo
PtrOwner<ICurveArc> pCrvArc( CreateFillet( *vCrvStepsToFill[i], ptS, *vCrvStepsToFill[i+1], ptE, Z_AX, dRadius, dPar1, dPar2)) ;
// controllo che l'arco creato non sia troppo piccolo
double dArcLen ;
if ( ! IsNull( pCrvArc) && pCrvArc->IsValid() && (! pCrvArc->GetLength( dArcLen) || dArcLen < 5 * EPS_SMALL)) {
vCrvArcs.emplace_back( Release( pCrvArc)) ; // arco nullo
vArcsToJump.push_back( i) ; // da scartare
continue ;
}
if ( i != 0 && vArcsToJump[i-1] == -1 && ! IsNull( pCrvArc) && pCrvArc->IsValid()) { // dal secondo arco in poi controllo che non ci siano intersezioni tra essi
IntersCurveCurve intCCH( *pCrvArc, *vCrvArcs[i-1]) ;
if ( intCCH.GetIntersCount() > 0 )
IntersBTWArcs = true ;
}
// se ho intersezioni tra archi o l'arco creato non è valido, allora provo altre nMaxTestForArcs volte a ricrearlo avvicinando i punti
while (( IsNull( pCrvArc) || IntersBTWArcs) && nIterForArcs < nMaxTestForArcs) {
dUE_ref = ( dULast1 + dUE_ref ) * 0.5 ;
dUS_ref = dUS_ref * 0.5 ;
if ( ! vCrvStepsToFill[i]->GetPointD1D2( dUE_ref, ICurve::FROM_PLUS, ptS)
|| ! vCrvStepsToFill[i+1]->GetPointD1D2( dUS_ref, ICurve::FROM_MINUS, ptE))
return false ;
dRadius = Dist( ptS, ptE) ;
pCrvArc.Set( CreateFillet( *vCrvStepsToFill[i], ptS, *vCrvStepsToFill[i+1], ptE, Z_AX, dRadius, dPar1, dPar2)) ;
nIterForArcs++ ;
IntersBTWArcs = false ;
if ( i != 0 && vArcsToJump[i-1] == -1 && ! IsNull( pCrvArc) && pCrvArc->IsValid()) { // dal secondo arco in poi controllo che non ci siano intersezioni tra essi
IntersCurveCurve intCCH( *pCrvArc, *vCrvArcs[i-1]) ;
if ( intCCH.GetIntersCount() > 0)
IntersBTWArcs = true ;
}
}
if ( IsNull( pCrvArc) || ! pCrvArc->IsValid()) { // se ancora non riesco... salto l'arco
vCrvArcs.emplace_back( CreateCurveArc()) ; // arco nullo
vArcsToJump.push_back( i) ; // da scartare
continue ;
}
// se ho creato l'arco lo memorizzo
vCrvArcs.emplace_back( Release( pCrvArc)) ; // arco valido
vArcsToJump.push_back( -1) ; // da considerare
}
// creo la curva che restituirò
PtrOwner<ICurveComposite> pCrvCO_temp( CreateCurveComposite()) ;
if ( IsNull( pCrvCO_temp))
return false ;
Point3d ptArcHelp, ptFirstPoint ;
// unisco la curva i-esima con l'arco i-esimo (non guardo l'ultima curva nel vettore, controllo dopo il caso di curva chiusa)
for ( int i = 0 ; i < int( vCrvStepsToFill.size()) - 1 ; ++ i) {
if ( vArcsToJump[i] == -1) { // se esiste l'arco ...
Point3d ptArcS, ptArcE ;
if ( ! vCrvArcs[i]->GetStartPoint( ptArcS) ||
! vCrvArcs[i]->GetEndPoint( ptArcE) ||
! vCrvStepsToFill[i]->GetParamAtPoint( ptArcS, dUE_ref) ||
! vCrvStepsToFill[i+1]->GetParamAtPoint( ptArcE, dUS_ref))
return false ;
if ( i == 0) { // ... e sono nella prima iterazione ...
if ( ! pCrv->IsClosed()) { // ... e se la curva è aperta -> la inserisco nel nuovo percorso
if ( ! pCrvCO_temp->AddCurve( GetCurve( vCrvStepsToFill[0]->CopyParamRange( 0, dUE_ref))))
return false ;
}
ptFirstPoint = ptArcS ;
// ... e se la curva è chiusa -> non la inserisco nel nuovo percorso
}
else { // ... e non sono nella prima iterazione (non ha importanza se la curva è chiusa o aperta...)
if ( ! vCrvStepsToFill[i]->GetParamAtPoint( ptArcHelp, dUS_ref) ||
! pCrvCO_temp->AddCurve( GetCurve( vCrvStepsToFill[i]->CopyParamRange( dUS_ref, dUE_ref))))
return false ;
// aggiungo la curva 'tagliata per il raccordo'
}
if ( ! pCrvCO_temp->AddCurve( vCrvArcs[i]->Clone())) // aggiungo l'arco di raccordo
return false ;
ptArcHelp = ptArcE ;
}
else { // se non esiste l'arco ...
if ( i == 0 ) { // e sono nella prima iterazione...
if ( ! vCrvStepsToFill[0]->GetEndPoint( ptArcHelp))
return false ;
if ( ! pCrv->IsClosed()) { // ...e se aperta // aggiungo la prima curva per intero
if ( ! vCrvStepsToFill[0]->GetParamAtPoint( ptArcHelp, dUE_ref) ||
! pCrvCO_temp->AddCurve( GetCurve( vCrvStepsToFill[0]->CopyParamRange( 0, dUE_ref))))
return false ;
}
ptFirstPoint = ptArcHelp ;
}
else { // ... e non sono nella prima iterazione (non ha importanza se la curva è chiusa o aperta...)
double dUS_cm ;
if ( ! vCrvStepsToFill[i]->GetParamAtPoint( ptArcHelp, dUS_ref) ||
! vCrvStepsToFill[i]->GetDomain( dUS_cm, dUE_ref) ||
! pCrvCO_temp->AddCurve( GetCurve( vCrvStepsToFill[i]->CopyParamRange( dUS_ref, dUE_ref))) ||
! vCrvStepsToFill[i]->GetEndPoint( ptArcHelp))
return false ;
}
}
}
// ultima curva...
if ( pCrv->IsClosed()) { // se curva chiusa...
if ( ! vCrvStepsToFill[0]->GetParamAtPoint( ptArcHelp, dUS_ref) ||
! vCrvStepsToFill[0]->GetParamAtPoint( ptFirstPoint, dUE_ref) ||
! pCrvCO_temp->AddCurve( GetCurve( vCrvStepsToFill[0]->CopyParamRange( dUS_ref, dUE_ref))))
return false ;
}
else { // se curva aperta... ( non ha importanza l'esistenza o meno degli archi...)
double dUS_cm ;
if ( ! vCrvStepsToFill.back()->GetParamAtPoint( ptArcHelp, dUS_ref) ||
! vCrvStepsToFill.back()->GetDomain( dUS_cm, dUE_ref) ||
! pCrvCO_temp->AddCurve( GetCurve( vCrvStepsToFill.back()->CopyParamRange( dUS_ref, dUE_ref))))
return false ;
}
// ripristino il punto inziale se la curva è chiusa
double dNewDU ;
if ( ! pCrv->IsClosed()) {
if ( ! pCrvCO_temp->GetParamAtPoint( ptArcHelp, dNewDU))
return false ;
pCrvCO_temp->ChangeStartPoint( dNewDU) ;
}
pCrv->Clear() ;
pCrv->AddCurve( Release( pCrvCO_temp)) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, ICRVCOMPOPOVECTOR& vOffsCL,
ICRVCOMPOPOVECTOR& vFirstOffset, ICurveComposite* pCrvLink, double dLenPercS,
double dLenPercE, int nMaxIter)
{
// controllo i parametri
if ( pCrvS == nullptr || pCrvE == nullptr )
return false ;
pCrvLink->Clear() ;
PtrOwner<ICurveComposite> ptCrvFinal( CreateCurveComposite()) ;
if ( IsNull( ptCrvFinal))
return false ;
// Prendo i punti, i vettori tangenti e i parametri di essi per le curve
Point3d ptSS, ptSE, ptES, ptEE ; Vector3d vS, vE ; double dUSS, dUSE, dUES, dUEE, dLenS, dLenE ;
dUSS = 0; dUSE = 0;
pCrvS->GetEndPoint( ptSE) ;
pCrvS->GetStartPoint( ptSS);
pCrvE->GetStartPoint( ptES);
pCrvE->GetEndPoint( ptEE) ;
pCrvS->GetEndDir( vS) ;
pCrvE->GetStartDir( vE) ;
pCrvS->GetDomain( dUSS, dUSE) ;
pCrvE->GetDomain( dUES, dUEE) ;
pCrvS->GetLength( dLenS) ;
pCrvE->GetLength( dLenE) ;
// se ho una curva di primo Offset allora non devo accorciarla ...
for ( int i = 0 ; i < int( vFirstOffset.size()) ; ++ i) {
if ( vFirstOffset[i]->IsPointOn( ptSS) && vFirstOffset[i]->IsPointOn( ptSE))
dLenPercS = 0 ;
if ( vFirstOffset[i]->IsPointOn( ptES) && vFirstOffset[i]->IsPointOn( ptEE))
dLenPercE = 0 ;
}
double dLStepS = dLenPercS * dLenS ;
double dLStepE = dLenPercE * dLenE ;
dLenE = 0 ;
// calcolo i possibili BiArchi tra le due curve
int nIter = 0 ;
while ( nIter < nMaxIter) {
// calcolo il BiArco
PtrOwner<ICurveComposite> ptBiArc( CreateCurveComposite()) ;
if ( ! CalcBoundedSmootedLink( ptSE, vS, ptES, vE, 0.5, vFirstOffset, ptBiArc) ||
ptBiArc->GetCurveCount() == 0)
return false ;
ptCrvFinal->Clear() ;
ptCrvFinal.Set( ptBiArc->Clone()) ;
if ( dLenPercE == 0 && dLenPercS == 0 )
break ;
// se il BiArco creato interseca le altre curve di Offset allora mi fermo...
bool bInterr = false ;
for ( int i = 0 ; i < int( vOffsCL.size()) && ! bInterr ; ++ i) {
if ( vOffsCL[i]->IsPointOn( ptSE) || vOffsCL[i]->IsPointOn( ptES))
continue ;
CRVCVECTOR ccClass ;
IntersCurveCurve intCC( *ptBiArc, *vOffsCL[i]) ;
intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ;
if ( ccClass.size() > 1) // se intersezione
bInterr = true ;
}
if ( bInterr)
break ; // così come ultimo arco ho quello precedente (valido)
// se ho trovato un BiArco valido, allora accorcio le due curve di Offset
dLenS -= dLStepS ;
dLenE += dLStepE ;
// ricalcolo il punto iniziale e finale
pCrvS->GetParamAtLength( dLenS, dUSE) ;
pCrvS->GetPointD1D2( dUSE, ICurve::FROM_MINUS, ptSE) ;
pCrvE->GetParamAtLength( dLenE, dUES) ;
pCrvE->GetPointD1D2( dUES, ICurve::FROM_PLUS, ptES) ;
// ricalcolo il vettore tangente iniziale e finale
PtrOwner<ICurveComposite> pCrvS_clone( pCrvS->Clone()) ; // curva di Offset iniziale accorciata
PtrOwner<ICurveComposite> pCrvE_clone( pCrvE->Clone()) ; // curva di Offset finale accorciata
pCrvS_clone->ChangeStartPoint( dUSE) ;
pCrvE_clone->ChangeStartPoint( dUES) ;
pCrvS_clone->GetStartDir( vS) ;
pCrvE_clone->GetStartDir( vE) ;
++ nIter ;
}
pCrvLink->AddCurve( ptCrvFinal->Clone()) ; // ultimo arco valido trovato
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::RemoveExtraParts( ISurfFlatRegion* pSrfToCut, ICRVCOMPOPOVECTOR& vOffs, ICRVCOMPOPOVECTOR& vOffsClosedCurves, ICRVCOMPOPOVECTOR& vOffsFirstCurve, ICURVEPOVECTOR& vLinks) {
if ( pSrfToCut == nullptr || ( int)vOffs.size() == 0)
return true ;
// ciclo tutti i chunk della regione da tagliare
for ( int i = 0 ; i < pSrfToCut->GetChunkCount() ; ++ i) {
// regione i-esima da rimuovere ( chunk i-esimo )
PtrOwner<ISurfFlatRegion> pSrfChunkToCut( pSrfToCut->CloneChunk( i)) ;
if ( IsNull( pSrfChunkToCut))
return false ;
// Curva nel caso la regione si svuoti con MedialAxis
PtrOwner<ICurveComposite> pCrvPath( CreateCurveComposite()) ;
if ( IsNull( pCrvPath))
return false ;
// nel caso la regione si svuoti con un centroide -> ptGoTo è il centroide
// nel caso la regione si svuoti con un medial Axis -> ptGoTo è il punto iniziale
// -> ptGoTo è il punto finale
Point3d ptGoTo, ptGoToI ;
// flag : 0 -> non faccio nulla | 1 -> svuoto con centroide | 2 -> svuoto con un percorso
int nOptFlag = 0 ;
// ricavo il flag
// ptGoTo è il centroide, pCrvPath è la curva da seguire per svuotare la regione ( nel caso non bastasse il centroide)
if ( ! RemoveExtraPartByMedialAxis( pSrfChunkToCut, vOffsFirstCurve, nOptFlag, ptGoTo, pCrvPath) ||
nOptFlag == 0)
continue ;
if ( nOptFlag == 2 ) // se ho una curva di Medial Axis, ricavo il punto iniziale e finale
if ( ! pCrvPath->GetStartPoint( ptGoTo) ||
! pCrvPath->GetEndPoint( ptGoToI))
continue ;
// una volta trovata la curva di medial Axis ( se la regione non si svuota semplicemente passando per il
// centroide, controllo in quale direzione è più conveniente percorrerla ... ( I = Inverso)
PtrOwner<ICurveComposite> pCrvH1( CreateCurveComposite()) ;
PtrOwner<ICurveComposite> pCrvH2( CreateCurveComposite()) ;
PtrOwner<ICurveComposite> pCrvH1I( CreateCurveComposite()) ;
PtrOwner<ICurveComposite> pCrvH2I( CreateCurveComposite()) ;
if ( IsNull( pCrvH1) || IsNull( pCrvH2) || IsNull( pCrvH2) || IsNull( pCrvH2I))
return false ;
int nIndexO = 0 ;
int nIndexOI = 0 ;
// cerco il punto pià vicino a ptGoTo sugli tra i vari Offset ( escludendo il primo )
// NB. PtGoTo è il centroide o il punto iniziale del percorso di medial Axis non invertito
if ( ! CutOffsetToClosestPoint( vOffs, ptGoTo, pCrvH1, pCrvH2, nIndexO))
continue ;
if ( nOptFlag == 2) // se ho un percorso di Medial Axis, lo cerco anche per PtGoToI
if ( ! CutOffsetToClosestPoint( vOffs, ptGoToI, pCrvH1I, pCrvH2I, nIndexOI))
continue ;
// A) SE IL PUNTO PIU' VICINO E' SU UN ESTREMO DELL'OFFSET... -> Cerco un punto sui collegamenti
// ( controllo solo i punti trovati sugli offset mediante Medial Axis non invertiti)
if ( IsNull( pCrvH1) || IsNull( pCrvH2) || pCrvH1->GetCurveCount() == 0 || pCrvH2->GetCurveCount() == 0) {
bool bFound, bFoundI ; int nIndexL, nIndexLI ;
if ( ! CutLinkToClosestPoint( vLinks, vOffs, ptGoTo, pCrvH1, pCrvH2, bFound, nIndexL))
continue ;
if ( nOptFlag == 2) { // nel caso curva di Medial Axis, controllo anche nel caso invertito
if ( ! CutLinkToClosestPoint( vLinks, vOffs, ptGoToI, pCrvH1I, pCrvH2I, bFoundI, nIndexLI))
continue ;
}
// link finale scelto...
PtrOwner<ICurveComposite> ptCrvNewLink( CreateCurveComposite()) ;
if ( IsNull( ptCrvNewLink))
return false ;
if ( nOptFlag == 1) { // se svuoto con centroide, aggiusto il link con una circonferenza ( BiArco alla peggio)
if ( ! GetNewCurvetWithCentroid( pCrvH1, pCrvH2, ptGoTo, bFound, vOffsFirstCurve, ptCrvNewLink))
continue ;
}
else if ( nOptFlag == 2) { // se svuoto con curva di medial Axis...
bool bSucc = true ; bool bSuccI = true ;
// ricavo il nuovo Offset con la curva di medial Axis aggiunta
if ( ! GetNewCurvetWithPath( pCrvH1, pCrvH2, pCrvPath, vOffsFirstCurve, vOffsClosedCurves, ptCrvNewLink))
bSucc = false ;
PtrOwner<ICurveComposite> pCrvPathI( pCrvPath->Clone()) ;
pCrvPathI->Invert() ;
PtrOwner<ICurveComposite> ptCrvNewLinkI( CreateCurveComposite()) ;
if ( IsNull( ptCrvNewLinkI))
return false ;
// ricavo il nuovo Offset con la curva di medial Axis Invertita aggiunta
if ( ! GetNewCurvetWithPath( pCrvH1I, pCrvH2I, pCrvPathI, vOffsFirstCurve, vOffsClosedCurves, ptCrvNewLinkI))
bSuccI = false ;
// scelgo il miglior percorso ottenuto ( sempre verificando che siano validi...)
int nC = 0 ;
if ( bSucc && bSuccI) { // se entrambi i percorsi sono validi allora li confronto
if ( ChoosePath( ptCrvNewLink, ptCrvNewLinkI, 0, 0.25, 5 * 1000 * EPS_SMALL, nC) && nC == 1) {
ptCrvNewLink.Set( ptCrvNewLinkI) ;
nIndexL = nIndexLI ;
}
}
else if ( ! bSucc) { // altrimenti tengo l'unico valido
ptCrvNewLink.Set( ptCrvNewLinkI) ;
nIndexL = nIndexLI ;
}
}
vLinks[nIndexL].Set( ptCrvNewLink) ; // setto il nuovo Link
}
else { // B) SE NON SONO AD UN ESTREMO DELLA CURVA DI OFFSET
// nuovo Offset da restituire
PtrOwner<ICurveComposite> ptCrvNewOffs( CreateCurveComposite()) ;
if ( IsNull( ptCrvNewOffs))
return false ;
if ( nOptFlag == 1) { // se svuoto con centroide, aggiusto il link con una circonferenza ( BiArco alla peggio)
if ( ! GetNewCurvetWithCentroid( pCrvH1, pCrvH2, ptGoTo, true, vOffsFirstCurve, ptCrvNewOffs))
continue ;
}
else if ( nOptFlag == 2) { // nel caso aggiungo un medial Axis non agli estremi di un Offset
bool bSucc = true ; bool bSuccI = true ;
// come prima controllo il percorso normal ed invertito
if ( ! GetNewCurvetWithPath( pCrvH1, pCrvH2, pCrvPath, vOffsFirstCurve, vOffsClosedCurves, ptCrvNewOffs))
bSucc = false ;
PtrOwner<ICurveComposite> pCrvPathI( pCrvPath->Clone()) ;
pCrvPathI->Invert() ;
PtrOwner<ICurveComposite> ptCrvNewOffsI( CreateCurveComposite()) ;
if ( IsNull( ptCrvNewOffsI))
return false ;
if ( ! GetNewCurvetWithPath( pCrvH1I, pCrvH2I, pCrvPathI, vOffsFirstCurve, vOffsClosedCurves, ptCrvNewOffsI))
bSuccI = false ;
int nC = 0 ; // se entrambi i percorsi sono validi allora li confronto
if ( bSucc && bSuccI) {
if ( ChoosePath( ptCrvNewOffs, ptCrvNewOffsI, 0, 0.5, 5 * 1000 * EPS_SMALL, nC) && nC == 1) {
ptCrvNewOffs.Set( ptCrvNewOffsI) ;
nIndexO = nIndexOI ;
}
}
else if ( ! bSucc) { // altrimenti tengo l'unico valido
ptCrvNewOffs.Set( ptCrvNewOffsI) ;
nIndexO = nIndexOI ;
}
}
vOffs[nIndexO].Set( ptCrvNewOffs) ; // setto il nuovo Offset
}
}
return true ;
}
//---------------------------------------------------------------------------
bool
Pocketing::GetCurveWeightInfo( const ICurveComposite* pCrvCompo, double dMaxLen, double& dToTRot, int& nSmallArcs, int& nSmallLines) {
dToTRot = 0 ; nSmallArcs = 0 ; nSmallLines = 0 ;
if ( pCrvCompo == nullptr)
return true ;
int nLines = 0 ;
PtrOwner<ICurveLine> pCrvLineOld( CreateCurveLine()) ;
if ( IsNull( pCrvLineOld))
return false ;
// scorro tutte le curve della composita
const ICurve* pMyCrv = pCrvCompo->GetFirstCurve() ;
while ( pMyCrv != nullptr) {
if ( pMyCrv->GetType() == CRV_ARC) { // nel caso di archi ...
nLines = 0 ;
PtrOwner<ICurveArc> pCrvArc( GetCurveArc( pMyCrv->Clone())) ;
double dAngCenter = abs( pCrvArc->GetAngCenter()) ;
dToTRot += abs( dAngCenter) ;
double dLen = 0 ;
if ( pCrvArc->GetLength( dLen) && dLen < dMaxLen)
++ nSmallArcs ;
}
else if ( pMyCrv->GetType() == CRV_LINE) { // nel caso di linee ...
++ nLines ;
if ( nLines == 1)
pCrvLineOld.Set( GetCurveLine( pMyCrv->Clone())) ;
else {
PtrOwner<ICurveLine> pNewMyCrv( GetCurveLine( pMyCrv->Clone())) ;
Vector3d vtNew, vtOld ;
pCrvLineOld->GetEndDir( vtOld) ;
pNewMyCrv->GetStartDir( vtNew) ;
double dAngCorner ; vtOld.GetAngle( vtNew, dAngCorner) ;
dToTRot += abs( dAngCorner) ;
pCrvLineOld.Set( pNewMyCrv) ;
nLines = 0 ;
}
double dLen = 0 ;
if ( pMyCrv->GetLength( dLen) && dLen < dMaxLen)
++ nSmallLines ;
}
pMyCrv = pCrvCompo->GetNextCurve() ;
}
return true ;
}
//---------------------------------------------------------------------------
bool
Pocketing::ChoosePath( const ICurveComposite* pCrv1, const ICurveComposite* pCrv2, int nP, double dPerP, double dMaxLen, int& nC) {
// controllo dei parametri
if ( pCrv1 == nullptr || pCrv2 == nullptr ||
! ( nP == 0 || nP == 1) || dPerP > 1 || dPerP < 0 || dMaxLen < EPS_SMALL)
return false ;
// # di archi piccoli tra le due curve
int dSmallArcs1 = 0 ; int dSmallArcs2 = 0 ;
// # di segmenti piccoli tra le due curve
int dSmallLines1 = 0 ; int dSmallLines2 = 0 ;
// ------------- lunghezze --------------
double dLen1 = 0 ; double dLen2 = 0 ;
pCrv1->GetLength( dLen1) ;
pCrv2->GetLength( dLen2) ;
double CL1, CL2 ; // rapporto tra lunghezza corrente e massima
if ( dLen1 < EPS_SMALL && dLen2 < EPS_SMALL) {
CL1 = 0 ;
CL2 = 0 ;
}
else {
CL1 = dLen1 / max( dLen1, dLen2) ;
CL2 = dLen2 / max( dLen1, dLen2) ;
}
// ------------- rotazioni --------------
double dRot1 = 0 ; double dRot2 = 0 ;
if ( ! GetCurveWeightInfo( pCrv1, dMaxLen, dRot1, dSmallArcs1, dSmallLines1) ||
! GetCurveWeightInfo( pCrv2, dMaxLen, dRot2, dSmallArcs2, dSmallLines2))
return false ;
double CR1, CR2 ; // rapporto tra la somma de rotazione degli angoli correnti e quella massima
if ( dRot1 == 0 && dRot2 == 0) {
CR1 = 0 ;
CR2 = 0 ;
}
else {
CR1 = dRot1 / max( dRot1, dRot2) ;
CR2 = dRot2 / max( dRot1, dRot2) ;
}
// funzione peso ( bilancio tra lunghezze e rotazioni complessive pesate )
double Fp1 = ( nP == 0 ? dPerP : ( 1 - dPerP)) * ( CL1 + dSmallLines1) + ( nP == 0 ? ( 1 - dPerP) : dPerP) * ( CR1 + dSmallArcs1) ;
double Fp2 = ( nP == 0 ? dPerP : ( 1 - dPerP)) * ( CL2 + dSmallLines2) + ( nP == 0 ? ( 1 - dPerP) : dPerP) * ( CR2 + dSmallArcs2) ;
// scelta della prima o della seconda curva
nC = ( Fp1 > Fp2 ? 1 : 0) ;
return true ;
}
//---------------------------------------------------------------------------
bool
Pocketing::CutOffsetToClosestPoint( ICRVCOMPOPOVECTOR& vCurves, const Point3d& ptFocus,
ICurveComposite* pCrv1, ICurveComposite* pCrv2, int& nIndex)
{
// controllo di avere almeno un offset...
if (( int)vCurves.size() == 0)
return false ;
// variabili iniziali
Point3d ptCl_H ;
double dDistance = INFINITO ;
int nFlag ;
pCrv1->Clear() ;
pCrv2->Clear() ;
nIndex = -1 ;
Point3d ptCL ;
// scorro tutti gli offset ad eccezione del primo ( a meno di averne uno solo )
for ( int j = ( int)vCurves.size() == 1 ? 0 : 1 ; j < int( vCurves.size()) ; ++ j) {
// non ho offset nulli, però controllo...
if( IsNull( vCurves[j]))
continue ;
// prendo il punto più vicino
if ( ! DistPointCurve( ptFocus, *vCurves[j]).GetMinDistPoint( EPS_SMALL, ptCl_H, nFlag))
continue ;
// cerco il punto in assoluto più vicino
if ( dDistance > Dist( ptCl_H, ptFocus)) {
dDistance = Dist( ptCl_H, ptFocus) ;
ptCL = ptCl_H ;
nIndex = j ;
}
}
// se non ho trovato nulla, esco
if ( nIndex < 0)
return false ;
// ricavo le due curve ( l'Offset viene spezzato in due sottocurve mediante il punto trovato)
double dUTan ;
vCurves[nIndex]->GetParamAtPoint( ptCL, dUTan) ;
pCrv1->AddCurve( vCurves[nIndex]->Clone()) ;
if ( ! pCrv1->TrimEndAtParam( dUTan))
pCrv1->Clear() ;
pCrv2->AddCurve( vCurves[nIndex]->Clone()) ;
if ( ! pCrv2->TrimStartAtParam( dUTan))
pCrv2->Clear() ;
return true ;
}
//---------------------------------------------------------------------------
bool
Pocketing::CutLinkToClosestPoint( ICURVEPOVECTOR& vCurves, ICRVCOMPOPOVECTOR& vOffs, const Point3d& ptFocus,
ICurveComposite* pCrv1, ICurveComposite* pCrv2, bool& bFound, int& nIndex)
{
// variabili iniziali
double dDistance = INFINITO ;
Point3d ptCl_H ;
int nFlag ;
pCrv1->Clear() ;
pCrv2->Clear() ;
Point3d ptCL ;
nIndex = - 1 ;
bFound = false ;
// scorro tutti i link cercando il più vicino
for ( int j = 0 ; j < int( vCurves.size()) ; ++ j) {
// escludo i links nulli ...
if ( IsNull( vCurves[j]))
continue ;
// distanza minima tra link e curva
if ( ! DistPointCurve( ptFocus, *vCurves[j]).GetMinDistPoint( EPS_SMALL, ptCl_H, nFlag))
continue ;
// cerco la distanza minimia assoluta ( non deve essere sopra un Offset )
if ( dDistance > Dist( ptCl_H, ptFocus) &&
! ( vOffs[j-1]->IsPointOn( ptCl_H) || vOffs[j]->IsPointOn( ptCl_H))) {
dDistance = Dist( ptCl_H, ptFocus) ;
nIndex = j ;
bFound = true ;
}
}
// se non ho trovato nulla, esco
if ( nIndex < 0)
return false ;
// ricavo le due curve ( il link viene spezzato in due sottocurve mediante il punto trovato )
double dUTan ;
vCurves[nIndex]->GetParamAtPoint( ptCL, dUTan) ;
pCrv1->AddCurve( vCurves[nIndex]->Clone()) ;
if ( ! pCrv1->TrimEndAtParam( dUTan))
pCrv1->Clear( ) ;
pCrv2->AddCurve( vCurves[nIndex]->Clone()) ;
if ( ! pCrv2->TrimStartAtParam( dUTan))
pCrv2->Clear() ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetNewCurvetWithCentroid( const ICurveComposite* pCrvH1, const ICurveComposite* pCrvH2, Point3d& ptC,
bool bCir, ICRVCOMPOPOVECTOR& VFirstOff, ICurveComposite* pCrvNewCurve) {
PtrOwner<ICurveComposite> pPath1( CreateCurveComposite()) ;
PtrOwner<ICurveComposite> pPath2( CreateCurveComposite()) ;
if ( IsNull( pPath1) || IsNull( pPath2))
return false ;
pCrvNewCurve->Clear() ;
Point3d ptS, ptE = ptC ;
Vector3d vtTanS, vtTanE ;
if ( bCir) { // creo una circonferenza
// prendo il punto iniziale
if ( pCrvH1 == nullptr || pCrvH1->GetFirstCurve() == nullptr) {
if ( ! pCrvH2->GetStartPoint( ptS))
return false ;
}
else {
if ( ! pCrvH1->GetEndPoint( ptS))
return false ;
}
// creo la circonferenza
if ( ! CalcBoundedSmootedLink( ptS, vtTanS, ptE, vtTanE, 0, VFirstOff, pPath1))
return false ;
Vector3d vtS_cir ; pPath1->GetStartDir( vtS_cir) ;
Vector3d vtS_CrvH1 ; pCrvH1->GetEndDir( vtS_CrvH1) ;
if ( ! AreSameVectorApprox( vtS_cir, vtS_CrvH1))
pPath1->Invert() ;
// Assegno la Feed
if ( ! AssignFeedCrvOnUnclearedRegions( pPath1))
return false ;
// controllo che la circonferenza sia ammissibile ( solo che non esca dalle prime curve di Offset )
Point3d ptCrvS ; pPath1->GetStartPoint( ptCrvS) ;
if ( ! CutCurveByOffsets( pPath1, VFirstOff)) // taglio la curva sugli Offsets
return false ;
double dUCrvS ;
ModifyCurveToSmoothed( pPath1, 0.075, 0.075) ;
if ( pPath1->IsClosed()) {
pPath1->GetParamAtPoint( ptCrvS, dUCrvS) ;
pPath1->ChangeStartPoint( dUCrvS) ;
}
// creo la nuova curva con la circonferenza
if ( pCrvH1 != nullptr && pCrvH1->GetFirstCurve() != nullptr)
if ( ! pCrvNewCurve->AddCurve( pCrvH1->Clone())) // aggiungo inizio
return false ;
if ( ! pCrvNewCurve->AddCurve( pPath1->Clone())) // aggiungo la circonferenza
return false ;
if ( pCrvH2 != nullptr && pCrvH2->GetFirstCurve() != nullptr)
if ( ! pCrvNewCurve->AddCurve(( pCrvH2->Clone()))) // aggiungo la fine
return false ;
}
else { // creo un BiArco
// prendo il vettore tangente e il punto iniziale
if ( pCrvH1 == nullptr || pCrvH1->GetFirstCurve() == nullptr) {
if ( ! pCrvH2->GetStartDir( vtTanS) ||
! pCrvH2->GetStartPoint( ptS))
return false ;
}
else {
if ( ! pCrvH1->GetEndDir( vtTanS) ||
! pCrvH1->GetEndPoint( ptS))
return false ;
}
// creo i due Biarchi
if ( ! CalcBoundedSmootedLink( ptS, vtTanS, ptE, vtTanS, 0.5, VFirstOff, pPath1)
|| ! CalcBoundedSmootedLink( ptE, vtTanS, ptS, vtTanS, 0.5, VFirstOff, pPath2))
return false ;
// Assegno la Feed a queste nuove curve
if ( ! AssignFeedCrvOnUnclearedRegions( pPath1) ||
! AssignFeedCrvOnUnclearedRegions( pPath2))
return false ;
// creo la nuova curva con il doppio Biarco
if ( pCrvH1 != nullptr && pCrvH1->GetFirstCurve() != nullptr)
if ( ! pCrvNewCurve->AddCurve( pCrvH1->Clone())) // aggiungo inizio
return false ;
if ( ! pCrvNewCurve->AddCurve( pPath1->Clone()) || ! pCrvNewCurve->AddCurve( pPath2->Clone())) // aggiungo i due BiArchi
return false ;
if ( pCrvH2 != nullptr && pCrvH2->GetFirstCurve() != nullptr)
if ( ! pCrvNewCurve->AddCurve(( pCrvH2->Clone()))) // aggiungo la fine
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetNewCurvetWithPath( const ICurveComposite* pCrvH1, const ICurveComposite* pCrvH2, ICurveComposite* pCrvPath, ICRVCOMPOPOVECTOR& VFirstOff, ICRVCOMPOPOVECTOR& VoffsCl, ICurveComposite* pCrvNewCurve) {
PtrOwner<ICurveComposite> pPath1( CreateCurveComposite()) ;
PtrOwner<ICurveComposite> pPath2( CreateCurveComposite()) ;
if ( IsNull( pPath1) || IsNull( pPath2) || pCrvPath == nullptr)
return false ;
pCrvNewCurve->Clear() ;
Point3d ptS, ptE, ptH ;
Vector3d vtTanS, vtTanE, vtH ;
if ( ! pCrvPath->GetStartPoint( ptE) ||
! pCrvPath->GetStartDir( vtTanE) ||
! pCrvPath->GetEndPoint( ptH) ||
! pCrvPath->GetEndDir( vtH))
return false ;
if ( pCrvH1 == nullptr || pCrvH1->GetFirstCurve() == nullptr) {
if ( ! pCrvH2->GetStartPoint( ptS) ||
! pCrvH2->GetStartDir( vtTanS))
return false ;
}
else {
if ( ! pCrvH1->GetEndPoint( ptS) ||
! pCrvH1->GetEndDir( vtTanS))
return false ;
}
// creo i due Biarchi
if ( ! CalcBoundedSmootedLink( ptS, vtTanS, ptE, vtTanE, 0.5, VFirstOff, pPath1))
if ( ! CalcBoundedLink( ptS, ptE, VFirstOff, pPath1))
return false ;
if ( ! CalcBoundedSmootedLink( ptH, vtH, ptS, vtTanS, 0.5, VFirstOff, pPath2))
if ( ! CalcBoundedLink( ptH, ptS, VFirstOff, pPath2))
return false ;
// creo la curva formata da BiArco1 - Path - BiArco 2
PtrOwner<ICurveComposite> pCrvToAdd( CreateCurveComposite()) ;
if ( IsNull( pCrvToAdd) ||
! pCrvToAdd->AddCurve( pPath1->Clone()) ||
! pCrvToAdd->AddCurve( pCrvPath->Clone()) ||
! pCrvToAdd->AddCurve( pPath2->Clone()))
return false ;
// cerco di togliere le auto intersezioni tra i biarchi e le curve di Medial Axis
if ( ! ManageSmoothAndAutoInters( pCrvToAdd, pCrvPath, pPath1, pPath2, VoffsCl))
return false ;
// alla curva ottenuta setto la Feed
if ( ! AssignFeedCrvOnUnclearedRegions( pCrvToAdd))
return false ;
// curva finale
if ( pCrvH1 != nullptr && pCrvH1->GetFirstCurve() != nullptr)
if ( ! pCrvNewCurve->AddCurve( pCrvH1->Clone())) // aggiungo inizio
return false ;
if ( ! pCrvNewCurve->AddCurve( pCrvToAdd->Clone())) { // aggiungo BiArco - Path - BiArco
// nel caso non funzioni questo raccordo, recupero un biarco valido e uso questo ...
Vector3d vtHS, vtHE ;
Point3d ptHS, ptHE ;
pCrvNewCurve->GetEndPoint( ptHS) ;
pCrvNewCurve->GetEndDir( vtHS) ;
pCrvToAdd->GetStartPoint( ptHE) ;
pCrvToAdd->GetStartDir( vtHE) ;
PtrOwner<ICurveComposite> pCrvBiArcHelper( CreateCurveComposite()) ;
if ( ! CalcBoundedSmootedLink( ptHS, vtHS, ptHE, vtHE, 0.5, VFirstOff, pCrvBiArcHelper))
if ( ! CalcBoundedLink( ptHS, ptHE, VFirstOff, pCrvBiArcHelper))
return false ;
// assegno la Feed ...
if ( ! AssignFeedCrvOnUnclearedRegions( pCrvBiArcHelper))
return false ;
if ( ! pCrvNewCurve->AddCurve( Release( pCrvBiArcHelper)) ||
! pCrvNewCurve->AddCurve( pCrvToAdd->Clone()))
return false ;
}
if ( pCrvH2 != nullptr && pCrvH2->GetFirstCurve() != nullptr) {
if ( ! pCrvNewCurve->AddCurve( pCrvH2->Clone())) { // aggiungo fine
// nel caso non funzioni questo raccordo, recupero un biarco valido e uso questo ...
int nTry = 1 ; int nMaxTry = 10 ; bool bFound = false ;
while ( nTry < nMaxTry && ! bFound) {
Vector3d vtHS, vtHE ;
Point3d ptHS, ptHE ;
pCrvNewCurve->GetEndPoint( ptHS) ;
pCrvNewCurve->GetEndDir( vtHS) ;
pCrvH2->GetStartPoint( ptHE) ;
pCrvH2->GetStartDir( vtHE) ;
PtrOwner<ICurveComposite> pCrvBiArcHelper( CreateCurveComposite()) ;
if ( ! CalcBoundedSmootedLink( ptHS, vtHS, ptHE, vtHE, 0.5, VFirstOff, pCrvBiArcHelper))
if ( ! CalcBoundedLink( ptHS, ptHE, VFirstOff, pCrvBiArcHelper) )
return false ;
// assegno la Feed ...
if ( ! AssignFeedCrvOnUnclearedRegions( pCrvBiArcHelper))
return false ;
if ( ! pCrvNewCurve->AddCurve( pCrvBiArcHelper->Clone()) ||
! pCrvNewCurve->AddCurve( pCrvH2->Clone())) {
++nTry ;
}
else {
bFound = true ;
}
}
if ( ! bFound)
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::ManageSmoothAndAutoInters( ICurveComposite* pCrv, ICurveComposite* pCrvPath, ICurveComposite* pPath1, ICurveComposite* pPath2, ICRVCOMPOPOVECTOR& vOffsCL) {
// controllo parametri
if ( pCrv == nullptr)
return false ;
// check AutoIntersezioni...
SelfIntersCurve SICrv( *pCrv) ;
if ( SICrv.GetCrossOrOverlapIntersCount() > 0) { // se ci sono autointersezioni
Vector3d vTanE ; Point3d ptHS ;
pCrvPath->GetEndDir( vTanE) ;
pCrvPath->GetEndPoint( ptHS) ;
bool bFound = false ;
int nIter = -45 ;
while ( ! bFound && nIter < 45) {
vTanE.Rotate( Z_AX, 90 - nIter) ; // vettore perpendicolare
PtrOwner<ICurveLine> pLine( CreateCurveLine()) ;
pLine->SetPVL( ptHS, vTanE, m_TParams.m_dDiam / 3 - 5 * EPS_SMALL) ; // segmento uscente
CRVCVECTOR ccClass ;
IntersCurveCurve intCC( *pLine, *pCrv) ;
intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ;
if (( int)ccClass.size() > 1) // se intersezione con parte precedente inverto la direzione
pLine->SetPVL( ptHS, - vTanE, m_TParams.m_dDiam / 3 - 5 * EPS_SMALL) ;
if ( IsNull( pLine) || ! pLine->IsValid())
break ;
// punto finale segmento uscente
Point3d ptEndLine ;
pLine->GetEndPoint( ptEndLine) ;
Point3d ptNear ;
double dUS, dUE ;
pPath2->GetDomain( dUS, dUE) ;
PtrOwner<ICurve> pCrvHelper(( pPath2->CopyParamRange( dUS, dUE - 0.5))) ;
pCrvHelper->GetEndPoint( ptNear) ;
PtrOwner<ICurveLine> pLine1( GetLinePointTgCurve( ptEndLine, *pPath2, ptNear)) ; // segmento tangente
if ( IsNull( pLine1) || ! pLine1->IsValid())
break ;
// creo la nuova curva formata da BiArco 1 - Path - Segmento uscente - Segmento tangente - parte restante di Biarco 2
Point3d ptELine1 ;
pLine1->GetEndPoint( ptELine1) ;
pPath2->GetParamAtPoint( ptELine1, dUS) ;
PtrOwner<ICurveComposite> pNewPath2( GetCurveComposite( pPath2->CopyParamRange( dUS, dUE))) ;
// creo la curva formata dai due segmenti ma smussati tra loro...
PtrOwner<ICurveComposite> pCrvTwoSeg( CreateCurveComposite()) ;
if ( ! pCrvTwoSeg->AddCurve( pCrvPath->Clone()) ||
! pCrvTwoSeg->AddCurve( pLine->Clone()) ||
! pCrvTwoSeg->AddCurve( pLine1->Clone()))
return false ;
ModifyCurveToSmoothed( pCrvTwoSeg, 0.2, 0.2) ;
PtrOwner<ICurveComposite> ptNewCrv( CreateCurveComposite()) ;
if ( ptNewCrv->AddCurve( pPath1->Clone()) &&
ptNewCrv->AddCurve( pCrvTwoSeg->Clone()) &&
ptNewCrv->AddCurve( pNewPath2->Clone())) {
SelfIntersCurve SICrvLoop( *ptNewCrv) ;
if ( SICrvLoop.GetCrossOrOverlapIntersCount() == 0) {
pCrv->Clear() ;
pCrv->AddCurve( Release( ptNewCrv)) ;
bFound = true ;
}
else { // se trovo autointersezioni, ripeto cambiando l'angolo del segmento uscente
++nIter ;
}
}
else
break ;
}
}
// smusso questa curva sulle varie curve di offsets
Point3d ptCheck1, ptCheck2 ;
PtrOwner<ICurveComposite> pCrvH( pCrv->Clone()) ; // copia della curva
if ( ! CutCurveByOffsets( pCrv, vOffsCL)) { // taglio la curva sugli Offsets
pCrv->Clear() ;
pCrv->AddCurve( Release( pCrvH)) ;
}
else { // controllo che i punti iniziali coincidano
pCrv->GetStartPoint( ptCheck1) ;
pCrvH->GetStartPoint( ptCheck2) ;
if ( ! AreSamePointApprox( ptCheck1, ptCheck2)) { // se i punti iniziali della curva prima e dopo lo smusso non coincidono ...
pCrv->Clear() ;
pCrv->AddCurve( Release( pCrvH)) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::RemoveFirstLoopFromSfr( ISurfFlatRegion* pSrfOrig) {
if ( pSrfOrig == nullptr)
return true ;
PtrOwner<ISurfFlatRegion> pSrfRes( CreateSurfFlatRegion()) ;
if ( IsNull( pSrfRes))
return false ;
for ( int c = 1 ; c < pSrfOrig->GetChunkCount() ; ++ c) {
PtrOwner<ISurfFlatRegion> pSrfHelp( CreateSurfFlatRegion()) ;
if ( IsNull( pSrfHelp))
return false ;
PtrOwner<ICurveComposite> pCrvMiniChunkBorder( GetCurveComposite( pSrfOrig->GetLoop( c, 0))) ;
pSrfHelp->AddExtLoop( pCrvMiniChunkBorder->Clone()) ;
if ( c == 1)
pSrfRes.Set( pSrfHelp->Clone()) ;
else
pSrfRes->Add( *( pSrfHelp)) ;
}
pSrfOrig->Clear() ;
pSrfOrig->CopyFrom( pSrfRes) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::RemoveExtraPartByMedialAxis( const ISurfFlatRegion* pChunkToCut, ICRVCOMPOPOVECTOR& vOffsFirstCurve, int& nOptFlag, Point3d& ptCentroid, ICurveComposite* pCrvPath)
{
// nOptFlag : 0 -> non faccio nulla | 1 -> svuoto con un centroide | 2 -> svuoto con un percorso
// variabili iniziali
nOptFlag = 2 ;
bool bForceCentroid = false ;
if ( pChunkToCut == nullptr)
return false ;
// curva che l'utensile dovrà seguire per svuotare la regione e curva di ingombro del tool
PtrOwner<ICurveComposite> pCrvStepByStepPath( CreateCurveComposite()) ;
if ( IsNull( pCrvStepByStepPath))
return false ;
// copie del chunk che devo svuotare
PtrOwner<ISurfFlatRegion> pSrfChunkToCutClone( pChunkToCut->Clone()) ;
double dArea = INFINITO ;
ICRVCOMPOPOVECTOR vCrvCoMedAxi ; // vettore dei medial Axis
PNTVECTOR vPtCentroid ; // vettore di centroidi
int nIter = 0 ; // numero di iterazioni
while ( pSrfChunkToCutClone->IsValid() && pSrfChunkToCutClone->GetChunkCount() != 0 &&
pSrfChunkToCutClone->GetArea( dArea) && dArea > 10 * EPS_SMALL) {
// finchè restano parti non svuotate la cui area totale è suffcientemente grande...
if ( nIter > 25) // troppi tentativi...
break ;
nIter++ ;
PtrOwner<ISurfFlatRegion> pSrfBiggerChunk( pSrfChunkToCutClone->CloneChunk( 0)) ;
if( IsNull( pSrfBiggerChunk))
return false ;
if( ! pSrfBiggerChunk->IsValid())
break ;
double dAreaExt ;
// se l'area del chunk è piccola... rimuovo il chunk dalla superficie da svuotare
if ( pSrfBiggerChunk->GetArea( dAreaExt) && dAreaExt < 10 * EPS_SMALL) {
if ( ! RemoveFirstLoopFromSfr( pSrfChunkToCutClone))
return false ;
if( IsNull( pSrfChunkToCutClone) || ! pSrfChunkToCutClone->IsValid())
break ;
continue ;
}
// prendo il centroide del chunk
Point3d ptC ;
if ( ! pSrfBiggerChunk->GetCentroid( ptC))
break ;
// creo la superificie che racchiude il mio tool
PtrOwner<ICurveArc> pCrvToolShape( CreateCurveArc()) ;
if ( IsNull( pCrvToolShape))
return false ;
pCrvToolShape->SetXY( ptC, m_TParams.m_dDiam / 2 + 5 * EPS_SMALL) ;
PtrOwner<ISurfFlatRegion> pSrfTool( CreateSurfFlatRegion()) ;
if ( IsNull( pSrfTool) || ! pSrfTool->AddExtLoop( Release( pCrvToolShape)) ||
! pSrfTool->IsValid())
break ;
PtrOwner<ISurfFlatRegion> pSrfTest( CloneSurfFlatRegion( pSrfBiggerChunk)) ;
if( IsNull( pSrfTest))
return false ;
pSrfTest->Subtract( *pSrfTool) ;
if( IsNull( pSrfTest) || ! pSrfTest->IsValid() || ! pSrfTest->GetArea( dArea) || dArea < 10 * EPS_SMALL ||
bForceCentroid) {
if ( nIter == 1) { // se prima iterazione -> ritorno il centroide com punto
nOptFlag = 1 ;
ptCentroid = ptC ;
return true ;
}
else { // se non sono alla prima iterazione -> memorizzo il centroide nel vettore
// controllo di non aver trovato un centroide già inserito ( per simmetria del chunk)
for ( int cen = 0 ; cen < int( vPtCentroid.size()) ; ++ cen) {
if ( AreSamePointApprox( vPtCentroid[cen], ptC)) {
pSrfChunkToCutClone->Clear() ;
break ;
}
}
vPtCentroid.push_back( ptC) ;
pSrfChunkToCutClone->Subtract( *pSrfTool) ;
if( IsNull( pSrfChunkToCutClone) || ! pSrfChunkToCutClone->IsValid())
break ;
continue ;
}
}
bForceCentroid = false ;
// 1) ricavo il bordo della regione
PtrOwner<ICurve> pCrvBorder( pSrfBiggerChunk->GetLoop( 0, 0)) ;
if ( IsNull( pCrvBorder) || ! pCrvBorder->IsValid())
return false ;
// 2) ricavo il medial Axis del bordo
PolyLine PlMedAx ;
if ( ! CurveSimpleMedialAxis( pCrvBorder, PlMedAx)) {
bForceCentroid = true ;
-- nIter ;
continue ;
}
PtrOwner<ICurveComposite> pCrvMedAx( CreateCurveComposite()) ;
if ( IsNull( pCrvMedAx))
return false ;
if ( ! pCrvMedAx->FromPolyLine( PlMedAx)) {
// se questo medial Axis è troppo piccolo e la polyLine non è convertitibile in curva composita ...
bForceCentroid = true ; // 2a) forzo ad andare nel centroide
-- nIter ; // 2b) scalo una iterzione
continue ;
}
pCrvMedAx->MergeCurves( 100 * EPS_SMALL, 100 * EPS_ANG_SMALL, false) ;
PolyArc PlMedAxArc ;
pCrvMedAx->ApproxWithArcsEx( 500 * EPS_SMALL, ANG_TOL_STD_DEG, LIN_FEA_STD, PlMedAxArc) ;
pCrvMedAx->Clear() ;
if( ! pCrvMedAx->FromPolyArc( PlMedAxArc)) {
bForceCentroid = true ;
-- nIter ;
continue ;
}
// smusso la curva
ModifyCurveToSmoothed( pCrvMedAx, 0.025, 0.025) ;
// se curva valida la inserisco nel vettore, altrimenti forzo il centroide
if ( pCrvMedAx->IsValid())
vCrvCoMedAxi.emplace_back( pCrvMedAx->Clone()) ;
else {
bForceCentroid = true ;
-- nIter ;
continue ;
}
// 3) guardo quale regione svuoto con questa curva
PtrOwner<ISurfFlatRegion> pSrfRemoved( GetSurfFlatRegionFromFatCurve( Release( pCrvMedAx), m_TParams.m_dDiam / 2 + 5 * EPS_SMALL, false, false)) ;
if ( IsNull( pSrfRemoved) || ! pSrfRemoved->IsValid())
break ;
// 4) aggiorno la regione togliendo la parte percorsa dal tool
if ( ! pSrfChunkToCutClone->Subtract( *pSrfRemoved))
break ;
if ( IsNull( pSrfChunkToCutClone) || ! pSrfChunkToCutClone->IsValid())
break ;
}
// se entrambi i vettori sono vuoti l'area originaria era più piccola di 10 * EPS_SMALL -> non faccio nulla
if (( int)vCrvCoMedAxi.size() == 0 && ( int)vPtCentroid.size() == 0) {
nOptFlag = 0 ;
return true ;
}
// ora collego la varie curve medial Axis trovate tra loro (ottenendo quindi una curva che svuota tutta la regione)
PtrOwner<ICurveComposite> pCrvCoBackLink( CreateCurveComposite()) ; // curva che collega primo e ultimo medial Axis
if ( IsNull( pCrvCoBackLink))
return false ;
Point3d ptSOriginal, ptEOriginal ;
Vector3d vtSOriginal, vtEOriginal ;
// parametri iniziali del primo e ultimo medial Axis trovato
if ( ! vCrvCoMedAxi[0]->GetStartPoint( ptSOriginal) ||
! vCrvCoMedAxi.back()->GetEndPoint( ptEOriginal) ||
! vCrvCoMedAxi[0]->GetStartDir( vtSOriginal) ||
! vCrvCoMedAxi.back()->GetEndDir( vtEOriginal))
return false ;
pCrvPath->AddCurve( vCrvCoMedAxi[0]->Clone()) ; // inserisco il primo medial Axis nel percorso finale
for ( int i = 1 ; i < int( vCrvCoMedAxi.size()) ; ++ i) { // scorro i restanti
Point3d ptS, ptE ; Vector3d vtS, vtE ;
// parametri iniziali del medialAxis i-esimo e (i-1)esimo
if ( ! vCrvCoMedAxi[i]->GetStartPoint( ptE) ||
! vCrvCoMedAxi[i-1]->GetEndPoint( ptS) ||
! vCrvCoMedAxi[i]->GetStartDir( vtE) ||
! vCrvCoMedAxi[i-1]->GetEndDir( vtS))
return false ;
PtrOwner<ICurveComposite> pCrvLink( CreateCurveComposite()) ;
if ( IsNull( pCrvLink))
return false ;
if ( ! CalcBoundedSmootedLink( ptS, vtS, ptE, vtE, 0.5, vOffsFirstCurve, pCrvLink))
if ( ! CalcBoundedLink( ptS, ptE, vOffsFirstCurve, pCrvLink))
return false ;
if ( ! pCrvPath->AddCurve( pCrvLink->Clone()) || ! pCrvPath->AddCurve( vCrvCoMedAxi[i]->Clone()))
return false ;
}
if ( ! AreSamePointEpsilon( ptEOriginal, ptSOriginal, EPS_SMALL))
if ( ! CalcBoundedSmootedLink( ptEOriginal, vtEOriginal, ptSOriginal, vtSOriginal, 0.5, vOffsFirstCurve, pCrvCoBackLink))
if ( ! CalcBoundedLink( ptEOriginal, ptSOriginal, vOffsFirstCurve, pCrvCoBackLink))
return false ;
// se ho trovato dei centroidi li unisco nei punti più vicini a questo percorso
for ( int i = 0 ; i < int( vPtCentroid.size()) ; ++ i) {
// 1) cerco il punto sulla curva più vicino al centroide i
Point3d ptClosestOnPath ; int nFlag ;
if ( ! DistPointCurve( vPtCentroid[i], *pCrvPath).GetMinDistPoint( EPS_SMALL, ptClosestOnPath, nFlag))
return false ;
// 2) spezzo la curva al paramtro del punto più vicino
double dU ;
if ( ! pCrvPath->GetParamAtPoint( ptClosestOnPath, dU))
return false ;
PtrOwner<ICurveComposite> pCrvA( GetCurveComposite( pCrvPath->CopyParamRange( 0, dU))) ;
if ( IsNull( pCrvA))
return false ;
PtrOwner<ICurveComposite> pCrvB( GetCurveComposite( pCrvPath->CopyParamRange( dU, pCrvPath->GetCurveCount()))) ;
if ( IsNull( pCrvB))
return false ;
// 3) prendo il vettore tangente al percorso nel punto trovato nel pCrvPath
Vector3d vtTanCpt ; Point3d ptH ;
if ( ! pCrvPath->GetPointTang( dU, ICurve::FROM_MINUS, ptH, vtTanCpt))
return false ;
// 4) collego i due punti (centroide e punto più vicino alla curva)
PtrOwner<ICurveComposite> pCrvPath1( CreateCurveComposite()) ;
if ( IsNull( pCrvPath1))
return false ;
if ( ! CalcBoundedSmootedLink( ptClosestOnPath, vtTanCpt, vPtCentroid[i], vtTanCpt, 0, vOffsFirstCurve, pCrvPath1))
if ( ! CalcBoundedLink( ptClosestOnPath, vPtCentroid[i], vOffsFirstCurve, pCrvPath1))
return false ;
pCrvPath->Clear() ;
pCrvPath->AddCurve( Release( pCrvA)) ;
if( ! pCrvPath->AddCurve( Release( pCrvPath1)))
return false ;
pCrvPath->AddCurve( Release( pCrvB)) ;
}
// la curva resitituita è una curva aperta che ha come primo punto il punto iniziale del primo medialAxis
// la curva restituita collega tutti i medial Axis tra di loro
// la curva restitutita collega tutti i centroidi con delle circonferenze
// la curva restituita ha come punto finale l'ultimo punto dell'ultimo medial Axis
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::CalcBoundedLink( const Point3d& ptStart, const Point3d& ptEnd, ICRVCOMPOPOVECTOR& vOffIslands, ICurveComposite* pCrvLink)
{
pCrvLink->Clear() ;
// recupero il vettore estrusione dal bordo esterno offsettato della superficie
Vector3d vtExtr ;
vOffIslands[0]->GetExtrusion( vtExtr) ;
// determino il riferimento naturale della svuotatura (OCS con il vettore estrusione come asse Z)
Frame3d frLoc ;
frLoc.Set( ORIG, vtExtr) ;
// non serve collegare ( può capitare nel tagliare percorsi con isole complesse)
if ( AreSamePointApprox( ptStart, ptEnd))
return true ;
// porto la curva di contenimento in locale a questo riferimento
vector<CurveLocal> vOffsExtr ;
for ( int i = 0 ; i < int( vOffIslands.size()) ; ++ i) {
CurveLocal CrvOutLoc( vOffIslands[i], GLOB_FRM, frLoc) ;
vOffsExtr.push_back( CrvOutLoc) ;
}
// creo la retta che li unisce
PtrOwner<ICurveComposite> pLine( CreateCurveComposite()) ;
if ( ! pLine->AddPoint( ptStart) || ! pLine->AddLine( ptEnd))
return false ;
pLine->SetExtrusion( vtExtr) ;
// la porto in locale al riferimento della svuotatura
CurveLocal LineLoc( pLine, GLOB_FRM, frLoc) ; // ... per le intersezioni
// creo la nuova curva formata dai tratti di linee INTERNI alle isole e dai tratti sul bordo degli offset
PtrOwner<ICurveComposite> pCompo( pLine->Clone()) ;
if ( IsNull( pCompo) )
return false ;
if ( ! pCompo->LocToLoc( GLOB_FRM, frLoc) )
return false;
PtrOwner<ICurveComposite> pCompoHelp( pLine->Clone()) ;
if ( IsNull( pCompoHelp))
return false ;
if ( ! pCompoHelp->LocToLoc( GLOB_FRM, frLoc))
return false ;
// scorro il vettore degli indici degli offset delle isole intersecati
for ( int i = 0 ; i < int( vOffIslands.size()) ; i++) {
CRVCVECTOR ccClass ;
IntersCurveCurve intCC( *pCompo, *vOffIslands[i]) ;
intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ;
if ( ! pCompoHelp->Clear())
return false ;
for ( int j = 0 ; j < int( ccClass.size()) ; ++j ) { // per ogni intersezione j con l'offset dell'isola i
if ( ccClass[j].nClass == CRVC_OUT) { // se ho intersezione spezzo il segmento
Point3d ptS ;
pCompo->GetPointD1D2( ccClass[j].dParS, ICurve::FROM_PLUS, ptS) ;
double dOffS ;
vOffIslands[i]->GetParamAtPoint( ptS, dOffS) ;
Point3d ptE ;
pCompo->GetPointD1D2( ccClass[j].dParE, ICurve::FROM_MINUS, ptE) ;
double dOffE ;
vOffIslands[i]->GetParamAtPoint( ptE, dOffE) ;
// recupero i due possibili percorsi e uso il più corto
PtrOwner<ICurve> pCrvA( GetCurve( vOffIslands[i]->CopyParamRange( dOffS, dOffE))) ;
PtrOwner<ICurve> pCrvB( GetCurve( vOffIslands[i]->CopyParamRange( dOffE, dOffS))) ;
if ( IsNull( pCrvA) || IsNull( pCrvB) )
return false ;
double dLenA ; pCrvA->GetLength( dLenA) ;
double dLenB ; pCrvB->GetLength( dLenB) ;
if ( dLenA < dLenB ) {
pCompoHelp->AddCurve( Release( pCrvA)) ;
}
else {
pCrvB->Invert() ;
pCompoHelp->AddCurve( Release( pCrvB)) ;
}
}
else { // se non interseco
pCompoHelp->AddCurve( pCompo->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ;
}
}
pCompo->Clear() ;
pCompo->AddCurve( pCompoHelp->Clone()) ;
}
// riporto pCompo nel sistema di riferimento originale
if ( ! pCompo->LocToLoc( frLoc, GLOB_FRM))
return false ;
pCrvLink->AddCurve( Release( pCompo)) ;
return true ;
}
//------------------------------------------------------------------------------
bool
Pocketing::CalcBoundedSmootedLink( const Point3d& ptStart, const Vector3d& vtStart, const Point3d& ptEnd,
const Vector3d& vtEnd, double dParMeet, ICRVCOMPOPOVECTOR& vOffIslands,
ICurveComposite* pCrvLink)
{
// creo il BiArc che unisce i due punti
double dAngStart, dAngEnd ;
vtStart.GetAngleXY( X_AX, dAngStart) ;
vtEnd.GetAngleXY( X_AX, dAngEnd) ;
PtrOwner<ICurve> pBiArcLink ;
if ( dParMeet != 0)
pBiArcLink.Set( GetBiArc( ptStart, -dAngStart, ptEnd, -dAngEnd, dParMeet)) ;
else {
PtrOwner<ICurveArc> pCrvCir( CreateCurveArc()) ;
if ( IsNull( pCrvCir))
return false ;
pCrvCir->SetCPAN( Media( ptStart, ptEnd), ptStart, m_Params.m_bInvert ? 360 : - 360, 0, Z_AX) ;
pBiArcLink.Set( pCrvCir->Clone()) ;
pCrvLink->AddCurve( pBiArcLink->Clone()) ;
return true ;
}
if ( IsNull( pBiArcLink))
return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ;
// se BiArco troppo grande allora lo modifico
double dLenBiArc ;
pBiArcLink->GetLength( dLenBiArc) ;
if ( dLenBiArc > 200 * 1000 * EPS_SMALL) {
PtrOwner<ICurveComposite> pCrvNewBiArcS( CreateCurveComposite()) ;
ModifyBiArc( pBiArcLink, 0.2, pCrvNewBiArcS) ;
pBiArcLink.Set( pCrvNewBiArcS) ;
}
// creo la nuova curva formata inizialmente dai tratti di archi
PtrOwner<ICurveComposite> pCompo( GetCurveComposite( pBiArcLink->Clone())) ;
if ( IsNull( pCompo))
return false ;
PtrOwner<ICurveComposite> pCompoHelp( GetCurveComposite( pBiArcLink->Clone())) ;
if ( IsNull( pCompoHelp))
return false ;
// scorro tutte le curve per controllare le intersezioni ...
for ( int i = 0 ; i < int( vOffIslands.size()) ; ++ i) {
CRVCVECTOR ccClass ;
IntersCurveCurve intCC( *pCompo, *vOffIslands[i]) ;
intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ;
if ( ! pCompoHelp->Clear())
return false ;
for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) { // per ogni intersezione j con l'offset dell'isola i
if ( ccClass[j].nClass == CRVC_OUT && ccClass.size() > 1) { // se ho intersezione spezzo il segmento
Point3d ptS ;
pCompo->GetPointD1D2( ccClass[j].dParS, ICurve::FROM_PLUS, ptS) ;
double dOffS ;
vOffIslands[i]->GetParamAtPoint( ptS, dOffS, 1500 * EPS_SMALL) ;
Point3d ptE ;
pCompo->GetPointD1D2( ccClass[j].dParE, ICurve::FROM_MINUS, ptE) ;
double dOffE ;
vOffIslands[i]->GetParamAtPoint( ptE, dOffE, 1500 * EPS_SMALL) ;
// recupero i due possibili percorsi e uso il più corto
PtrOwner<ICurve> pCrvA( GetCurve( vOffIslands[i]->CopyParamRange( dOffS, dOffE))) ;
PtrOwner<ICurve> pCrvB( GetCurve( vOffIslands[i]->CopyParamRange( dOffE, dOffS))) ;
if ( IsNull( pCrvA) || IsNull( pCrvB))
return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ;
double dLenA ; pCrvA->GetLength( dLenA) ;
double dLenB ; pCrvB->GetLength( dLenB) ;
if ( j != 0) {
if ( dLenA < dLenB) {
if ( ! pCompoHelp->AddCurve( Release( pCrvA)))
return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ;
}
else {
pCrvB->Invert() ;
if ( ! pCompoHelp->AddCurve( Release( pCrvB)))
return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ;
}
}
else {
pCrvB->Invert() ;
if ( ! pCompoHelp->AddCurve( Release( pCrvB)))
return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ;
}
}
else { // se non interseco
if ( ! pCompoHelp->AddCurve( pCompo->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)))
return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ;
}
}
pCompo->Clear() ;
if ( ! pCompo->AddCurve( pCompoHelp->Clone()))
if ( ! CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink))
return false ;
}
// se il BiArco è troppo piccolo allora lo approssimo con un segmento
BBox3d bBox3 ;
if ( pCompo->GetLocalBBox( bBox3)) {
double dRadBB ;
if ( bBox3.GetRadius( dRadBB) && dRadBB < 500 * EPS_SMALL) {
if ( ! CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink))
return false ;
return true ;
}
}
ModifyCurveToSmoothed( pCompo, 0.05, 0.05) ;
pCrvLink->AddCurve( Release( pCompo)) ;
return true ;
}
//-----------------------------------------------------------------------------
bool
Pocketing::ModifyBiArc( ICurve* pBiArcLink, double dToll, ICurveComposite* pNewBiArc) {
if ( pBiArcLink == nullptr)
return false ;
if ( dToll > 0.99 || dToll < 0.01)
return false ;
pNewBiArc->Clear() ;
double dUS, dUE ;
pBiArcLink->GetDomain( dUS, dUE) ;
PtrOwner<ICurve> pArc1( GetCurve( pBiArcLink->CopyParamRange( dUS, (dUS + dUE) / 2))) ;
PtrOwner<ICurve> pArc2( GetCurve( pBiArcLink->CopyParamRange(( dUS + dUE ) / 2, dUE))) ;
if ( IsNull(pArc1) || ! pArc1->IsValid() || IsNull( pArc2) || ! pArc2->IsValid())
return false ;
// primo pezzo
pArc1->GetDomain( dUS, dUE) ;
PtrOwner<ICurve> pArc1A( GetCurve( pArc1->CopyParamRange( dUS, dUS + ( dUE - dUS ) * dToll))) ; // Arc1
PtrOwner<ICurve> pArc1B( GetCurve( pArc1->CopyParamRange( dUE - ( dUE - dUS ) * dToll, dUE))) ; // Arc2
Point3d pt1A, pt1B ;
pArc1A->GetEndPoint( pt1A) ;
pArc1B->GetStartPoint( pt1B) ;
PtrOwner<ICurveLine> pLine1( CreateCurveLine()) ;
pLine1->Set( pt1A, pt1B) ; // Linea
// secondo pezzo
pArc2->GetDomain( dUS, dUE) ;
PtrOwner<ICurve> pArc2A( GetCurve( pArc2->CopyParamRange( dUS, dUS + ( dUE - dUS ) * dToll))) ; // Arc1
PtrOwner<ICurve> pArc2B( GetCurve( pArc2->CopyParamRange( dUE - ( dUE - dUS ) * dToll, dUE))) ; // Arc2
Point3d pt2A, pt2B ;
pArc2A->GetEndPoint( pt2A) ;
pArc2B->GetStartPoint( pt2B) ;
PtrOwner<ICurveLine> pLine2( CreateCurveLine()) ;
pLine2->Set( pt2A, pt2B) ; // Linea
if ( ! pNewBiArc->AddCurve( Release( pArc1A)) ||
! pNewBiArc->AddCurve( Release( pLine1)) ||
! pNewBiArc->AddCurve( Release( pArc1B)) ||
! pNewBiArc->AddCurve( Release( pArc2A)) ||
! pNewBiArc->AddCurve( Release( pLine2)) ||
! pNewBiArc->AddCurve( Release( pArc2B)))
return false ;
return true ;
}
//------------------------------------------------------------------------------
bool
Pocketing::CutCurveByOffsets( ICurveComposite* pCurve, ICRVCOMPOPOVECTOR& vOffs) {
// controllo parametri ingresso
if (( int)vOffs.size() == 0)
return true ;
ICRVCOMPOPOVECTOR vOffOrig( vOffs.size()) ;
for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) {
vOffOrig[i].Set( vOffs[i]->Clone()) ;
}
Point3d ptStart ;
if ( ! pCurve->GetStartPoint( ptStart))
return false ;
PtrOwner<ICurveComposite> pCompo( pCurve->Clone()) ;
PtrOwner<ICurveComposite> pCompoHelp( pCurve->Clone()) ;
PtrOwner<ICurveComposite> pOffCheck( CreateCurveComposite()) ;
if ( IsNull( pCompoHelp) || IsNull( pCompo) || IsNull( pOffCheck))
return false ;
int nTypeOfCut = -1 ;
for ( int i = 0; i < int( vOffOrig.size()) ; ++ i) {
if ( vOffOrig[i]->IsPointOn( ptStart))
pOffCheck.Set( vOffOrig[i]->Clone()) ;
CRVCVECTOR ccClass ;
IntersCurveCurve intCC( *pCompo, *vOffOrig[i]) ;
intCC.GetCurveClassification( 0, 10 * EPS_SMALL, ccClass) ;
if ( ! pCompoHelp->Clear())
return false ;
if ( ccClass.size() > 1) {
if ( ccClass[0].nClass == CRVC_IN)
nTypeOfCut = CRVC_OUT ;
else
nTypeOfCut = CRVC_IN ;
for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) {
if ( ccClass[j].nClass == nTypeOfCut) {
Point3d ptS ; pCompo->GetPointD1D2( ccClass[j].dParS, ICurve::FROM_PLUS, ptS) ;
double dOffS ; vOffOrig[i]->GetParamAtPoint( ptS, dOffS) ;
Point3d ptE ; pCompo->GetPointD1D2( ccClass[j].dParE, ICurve::FROM_MINUS, ptE) ;
double dOffE ; vOffOrig[i]->GetParamAtPoint( ptE, dOffE) ;
// recupero i due possibili percorsi e uso il più corto
PtrOwner<ICurve> pCrvA( GetCurve( vOffOrig[i]->CopyParamRange( dOffS, dOffE))) ;
PtrOwner<ICurve> pCrvB( GetCurve( vOffOrig[i]->CopyParamRange( dOffE, dOffS))) ;
if ( IsNull( pCrvA) || IsNull( pCrvB))
return false ;
double dLenA ; pCrvA->GetLength( dLenA) ;
double dLenB ; pCrvB->GetLength( dLenB) ;
if ( dLenA < dLenB) {
CRVCVECTOR ccClassA ;
IntersCurveCurve intCCA( *pCrvA, *pOffCheck) ;
intCCA.GetCurveClassification( 0, 10 * EPS_SMALL, ccClassA) ;
if ( ccClassA.size() > 0 && i == vOffOrig.size() - 1 && ccClassA[0].nClass == CRVC_ON_M) {
if ( ! pCompoHelp->AddCurve( pCompo->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)))
return false ;
continue ;
}
if ( ! pCompoHelp->AddCurve( Release( pCrvA)))
return false ;
}
else {
pCrvB->Invert() ;
CRVCVECTOR ccClassB ;
IntersCurveCurve intCCB( *pCrvB, *pOffCheck) ;
intCCB.GetCurveClassification( 0, 10 * EPS_SMALL, ccClassB) ;
if ( ccClassB.size() > 0 && i == vOffOrig.size() - 1 && ccClassB[0].nClass == CRVC_ON_M) {
if ( ! pCompoHelp->AddCurve( pCompo->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)))
return false ;
continue ;
}
if ( ! pCompoHelp->AddCurve( Release( pCrvB)))
return false ;
}
}
else {
if ( ! pCompoHelp->AddCurve( pCompo->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)))
return false ;
}
}
pCompo->Clear() ;
pCompo->AddCurve( pCompoHelp->Clone()) ;
}
}
pCurve->Clear() ;
pCurve->AddCurve( Release( pCompo)) ;
return true ;
}
//------------------------------------------------------------------------------
bool
Pocketing::CalcBoundedLinkWithBiArcs( const Point3d& ptStart, const Vector3d& vtStart, const Point3d& ptEnd, const Vector3d& vtEnd,
const ICurve* pCrvBound, ICurveComposite* pCrvLink)
{
double dAngStart, dAngEnd ;
vtStart.GetAngleXY( X_AX, dAngStart) ;
vtEnd.GetAngleXY( X_AX, dAngEnd) ;
PtrOwner<ICurve> pBiArcLink( GetBiArc( ptStart, -dAngStart, ptEnd, -dAngEnd, 0.5)) ;
if ( IsNull( pBiArcLink))
return false ;
// verifico se esce dalla svuotatura
CRVCVECTOR ccClass ;
IntersCurveCurve intCC( *pBiArcLink, *pCrvBound) ;
intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ;
// se nessuno o un solo tratto e interno, il biarco è il collegamento
if ( ccClass.empty() || ( ccClass.size() == 1 && ccClass[0].nClass == CRVC_IN)) {
pCrvLink->AddCurve( Release( pBiArcLink)) ;
}
// altrimenti creo un percorso con biarchi e opportuni tratti della curva di contenimento
else {
PtrOwner<ICurveComposite> pCompo( CreateCurveComposite()) ;
if ( IsNull( pCompo))
return false ;
double dPar1, dPar2 ;
Point3d ptMinDist1, ptMinDist2 ;
Vector3d vtDir1, vtDir2 ;
double dAng1, dAng2 ;
int nFlag ;
DistPointCurve distPtSCrv( ptStart, *pCrvBound) ;
distPtSCrv.GetParamAtMinDistPoint( 0, dPar1, nFlag) ;
pCrvBound->GetPointTang( dPar1, ICurve::FROM_MINUS, ptMinDist1, vtDir1) ;
vtDir1.GetAngleXY( X_AX, dAng1) ;
DistPointCurve distPtECrv( ptEnd, *pCrvBound) ;
distPtECrv.GetParamAtMinDistPoint( 0, dPar2, nFlag) ;
pCrvBound->GetPointTang( dPar2, ICurve::FROM_MINUS, ptMinDist2, vtDir2) ;
vtDir2.GetAngleXY( X_AX, dAng2) ;
pCompo->AddCurve( GetBiArc( ptStart, -dAngStart, ptMinDist1, -dAng1, 0.5)) ; // primo biarco
pCompo->AddCurve( pCrvBound->CopyParamRange( dPar1, dPar2)) ; // tratto di pCrvBound
pCompo->AddCurve( GetBiArc( ptMinDist2, -dAng2, ptEnd, -dAngEnd, 0.5)) ; // secondo biarco
pCrvLink->AddCurve( Release( pCompo)) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::CalcCircleSpiral( const Point3d& ptCen, const Vector3d& vtN, double dOutRad, double dIntRad,
bool bSplitArcs, ICurveComposite* pMCrv, ICurveComposite* pRCrv)
{
// raggio della circonferenza esterna
if ( dOutRad < 10 * EPS_SMALL) {
m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ;
return false ;
}
// imposto versore estrusione sulle curve composite
pMCrv->SetExtrusion( vtN) ;
pRCrv->SetExtrusion( vtN) ;
// creo e inserisco la circonferenza esterna
PtrOwner<ICurveArc> pArc( CreateCurveArc()) ;
if ( IsNull( pArc) || ! pArc->Set( ptCen, vtN, dOutRad)) {
m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ;
return false ;
}
// creo la superificie per la Feed
PtrOwner<ISurfFlatRegion> pSrfRemoved( CreateSurfFlatRegion()) ;
if ( IsNull( pSrfRemoved))
return false ;
ICRVCOMPOPOVECTOR vLinksDone ;
Vector3d vtDir = pArc->GetStartVersor() ;
pMCrv->AddCurve( Release( pArc)) ;
// se richiesta percorrenza invertita
if ( m_Params.m_bInvert)
pMCrv->Invert() ;
// se raggio esterno maggiore dell'interno
if ( dOutRad > dIntRad + 10 * EPS_SMALL) {
// aggiungo le semicirconferenze della spirale ( devono essere in numero dispari)
int nStep = int( ceil( ( dOutRad - dIntRad) / ( 0.5 * GetSideStep()))) ;
if ( IsEven( nStep))
nStep += 1 ;
double dStep = ( dOutRad - dIntRad) / nStep ;
for ( int i = 1 ; i <= nStep ; ++ i) {
if ( ! IsEven( i))
pMCrv->AddArcTg( ptCen - vtDir * ( dOutRad - i * dStep)) ;
else
pMCrv->AddArcTg( ptCen + vtDir * ( dOutRad - i * dStep)) ;
}
// aggiungo la circonferenza interna
pMCrv->AddArcTg( ptCen + vtDir * dIntRad) ;
pMCrv->AddArcTg( ptCen - vtDir * dIntRad) ;
}
// verifico il percorso di lavoro
if ( pMCrv->GetCurveCount() == 0) {
m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ;
return false ;
}
// se necessario, approssimo con rette
if ( bSplitArcs && ! ApproxWithLines( pMCrv)) {
m_pMchMgr->SetLastError( 2421, "Error in Pocketing : Linear Approx not computable") ;
return false ;
}
// Assegno la Feed al percorso
AssignFeedSpiralOpt( 0, pMCrv) ;
// eventuale sistemazione archi
VerifyArcs( pMCrv) ;
// calcolo l'eventuale percorso di ritorno
Point3d ptStart ; pMCrv->GetStartPoint( ptStart) ;
Point3d ptEnd ; pMCrv->GetEndPoint( ptEnd) ;
Vector3d vtStart ; pMCrv->GetStartDir( vtStart) ;
if ( ! AreSamePointApprox( ptStart, ptEnd)) {
PtrOwner<ICurveArc> pArc2( CreateCurveArc()) ;
if ( IsNull( pArc2) || ! pArc2->Set2PVN( ptStart, ptEnd, - vtStart, vtN)) {
m_pMchMgr->SetLastError( 2420, "Error in Pocketing : Return toolpath not computable") ;
return false ;
}
pRCrv->AddCurve( Release( pArc2)) ;
// inverto e eventualmente sistemo archi
pRCrv->Invert() ;
// setto la feed per il percorso di ritorno
AssignFeedForReturnPath( pRCrv) ;
VerifyArcs( pRCrv) ;
}
return true ;
}
//----------------------------------------------------
bool
Pocketing::CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double dPocketSize, int nBase,
int nSecondBase, ICurveComposite* pMCrv, ICurveComposite* pRCrv, bool& bOptimizedTrap)
{
// parametri
double dDiam = m_dDiam_Prec > 0 ? m_dDiam_Prec : m_TParams.m_dDiam ;
double dOffsR = m_dDiam_Prec > 0 ? m_dOffsetR_Prec : GetOffsR() ;
double dRad = 0.5 * dDiam + dOffsR ;
const double TOLL = 50 * EPS_SMALL ;
bOptimizedTrap = false ;
Vector3d vtExtr ; pCrvPocket->GetExtrusion( vtExtr) ;
// recupero le temp prop
INTVECTOR vnProp( 4, 0) ;
if ( pCrvPocket->GetCurveCount() == 4) {
for ( int i = 0 ; i < 4 ; i++)
pCrvPocket->GetCurveTempProp( i, vnProp[i]) ;
}
else {
vnProp[1] = pCrvPocket->GetCurve( 1)->GetTempProp() ;
vnProp[3] = pCrvPocket->GetCurve( nSecondBase + 1)->GetTempProp() ;
}
// passo in un sistema di riferimento locale avente asse X allineato con uno dei due lati paralleli (possibilmente aperto) e centro nel
// punto iniziale del lato
pCrvPocket->ToLoc( frTrap) ;
// calcolo la larghezza massima della svuotatura (riferimento con X parallelo a primo lato chiuso)
double dLen0, dLen1, dLen2, dLen3 ;
pCrvPocket->GetCurve( nBase)->GetLength( dLen0) ;
pCrvPocket->GetCurve( nSecondBase)->GetLength( dLen2) ;
bool bRealTrap = pCrvPocket->GetCurveCount() == 4 ;
for ( int i = 0 ; i < 4 && bRealTrap ; ++ i)
bRealTrap = pCrvPocket->GetCurve( i)->GetType() == CRV_LINE ;
if ( bRealTrap) {
pCrvPocket->GetCurve( nBase + 1)->GetLength( dLen1) ;
pCrvPocket->GetCurve( nSecondBase + 1)->GetLength( dLen3) ;
}
// calcolo percorso di svuotatura
// se lati obliqui sono entrambi chiusi e dimensione svuotatura è maggiore di diametro fresa e minore del doppio gestione speciale
if ( bRealTrap &&
( vnProp[0] != 0 && vnProp[2] != 0 && vnProp[3] == 0 && vnProp[1] == 0 && max( dLen0, dLen2) < 2 * dDiam + EPS_SMALL) ||
vnProp[1] != 0 && vnProp[3] != 0 && vnProp[0] == 0 && vnProp[2] == 0 && max( dLen1, dLen3) < 2 * dDiam + EPS_SMALL) {
if ( ! SpecialAdjustTrapezoidSpiralForAngles( pMCrv, vnProp[0] == 0, pCrvPocket)) {
pMCrv->Clear() ;
return false ;
}
}
else {
// trovo la quota Y per centro del Tool
double dYCoord ;
if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == 0) // se base principale chiusa
dYCoord = 0.5 * dDiam + dOffsR ;
else if ( pCrvPocket->GetCurve( nSecondBase)->GetTempProp( 0) == 0) // se base principale aperta e secondaria chiusa
dYCoord = dPocketSize - 0.5 * dDiam - dOffsR ;
else // se entrambi i lati paralleli sono aperti mi posiziono a metà della svuotatura
dYCoord = 0.5 * dPocketSize ;
double dXCoordStart, dXCoordEnd ;
if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, nBase, nSecondBase, true, dYCoord, dXCoordStart, dPocketSize))
return false ;
if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, nBase, nSecondBase, false, dYCoord, dXCoordEnd, dPocketSize))
return false ;
if ( dXCoordStart > dXCoordEnd + 500 * EPS_SMALL)
return false ;
Point3d ptStart( dXCoordStart, dYCoord) ;
Point3d ptEnd( dXCoordEnd, dYCoord) ;
//if ( AreSamePointEpsilon( ptStart, ptEnd, 500 * EPS_SMALL) && vnProp[0] != 0) {
// Vector3d vtDir1, vtDir3 ;
// pCrvPocket->GetCurve( 1)->GetStartDir( vtDir1) ;
// pCrvPocket->GetCurve( 3)->GetStartDir( vtDir3) ;
// // gestisco il caso speciale di un parallelogramma in cui anche l'altra dimensione della svuotatura è pari al diametro utensile
// if ( AreOppositeVectorApprox( vtDir1, vtDir3)) {
// PtrOwner<ICurveLine> pLine1( GetCurveLine( pCrvPocket->GetCurve( 1)->Clone())) ;
// PtrOwner<ICurveLine> pLine3( GetCurveLine( pCrvPocket->GetCurve( 3)->Clone())) ;
// if ( IsNull( pLine1) || IsNull( pLine3))
// return true ;
// if ( ! pLine1->SimpleOffset( - 0.5 * m_TParams.m_dDiam - GetOffsR()) ||
// ! pLine3->SimpleOffset( - 0.5 * m_TParams.m_dDiam - GetOffsR()))
// return true ;
// Point3d ptS, ptE ;
// if ( vtDir3 * X_AX > EPS_SMALL) {
// pLine1->GetStartPoint( ptS) ;
// pLine3->GetStartPoint( ptE) ;
// }
// else {
// pLine1->GetEndPoint( ptE) ;
// pLine3->GetEndPoint( ptS) ;
// }
// pMCrv->AddPoint( ptS) ;
// if ( vnProp[2] != 0)
// pMCrv->AddLine( ptE) ;
// else
// pMCrv->AddLine( ptStart) ;
// pMCrv->SetCurveTempProp( 0, 1) ;
// }
//}
//else {
if ( ! pMCrv->AddPoint( ptStart))
return true ;
if ( ! pMCrv->AddLine( ptEnd))
return true ;
// aggiustamenti al percorso per rimuovere materiale residuo negli angoli
if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == 1 ||
pCrvPocket->GetCurve( nSecondBase)->GetTempProp( 0) == 1) {
Frame3d frOpen ;
bool bSwitch = false ;
// Base principale chiusa e base Secondaria aperta
if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == 0) {
pCrvPocket->ChangeStartPoint( nSecondBase) ;
// oriento il Frame ( ho sempre l'origine nell'estremo superiore del lato aperto)
Vector3d vtDir ; pCrvPocket->GetStartDir( vtDir) ;
Point3d ptORIG ;
if ( vtDir.y > 0)
pCrvPocket->GetCurve( nBase)->GetEndPoint( ptORIG) ;
else
pCrvPocket->GetCurve( nBase)->GetStartPoint( ptORIG) ;
frOpen.Set( ptORIG, Z_AX, -X_AX) ;
if ( ! frOpen.IsValid())
return false ;
pCrvPocket->ToLoc( frOpen) ;
pMCrv->ToLoc( frOpen) ;
pMCrv->Invert() ;
bSwitch = true ;
}
if ( pCrvPocket->GetCurve( 3)->GetTempProp( 0) == 0 &&
! AdjustTrapezoidSpiralForAngles( pMCrv, pCrvPocket, true)) {
pMCrv->Clear() ;
return false ;
}
if ( pCrvPocket->GetCurve( 1)->GetTempProp( 0) == 0 &&
! AdjustTrapezoidSpiralForAngles( pMCrv, pCrvPocket, false)) {
pMCrv->Clear() ;
return false ;
}
if ( bSwitch) {
pCrvPocket->ToGlob( frOpen) ;
pMCrv->ToGlob( frOpen) ;
pMCrv->Invert() ;
}
}
//}
}
if ( pMCrv->GetCurveCount() == 0)
return true ;
pMCrv->ToGlob( frTrap) ;
if ( ! m_Params.m_bInvert) {
pMCrv->Invert() ;
// inverto le proprietà in modo che nProp3 sia sempre legata al punto iniziale e nProp1 a quello finale
swap( vnProp[1], vnProp[3]) ;
}
// segno i lati aperti come temp prop della curva
int nOpenEdges = vnProp[0] + vnProp[1] * 2 + vnProp[3] * 8 ;
pMCrv->SetTempProp( nOpenEdges, 0) ;
pMCrv->SetExtrusion( vtExtr) ;
bOptimizedTrap = true ;
return true ;
}
//----------------------------------------------------
bool
Pocketing::CalcTrapezoidSpiralLocalFrame( ICurveComposite* pCrvTrap, const Vector3d& vtDir, Frame3d& frLoc)
{
// cerco i lati paralleli a vtDir
int nBaseId = -1 ;
for ( int i = 0 ; i < pCrvTrap->GetCurveCount() ; i ++) {
Vector3d vtEdge ;
pCrvTrap->GetCurve( i)->GetStartDir( vtEdge) ;
if ( AreSameOrOppositeVectorApprox( vtEdge, vtDir)) {
nBaseId = i ;
break ;
}
}
if ( nBaseId != 0 && nBaseId != 1)
return false ;
// imposto come lato iniziale per la curva uno dei lati paralleli a vtDir
pCrvTrap->ChangeStartPoint( nBaseId) ;
Point3d ptOrig ; pCrvTrap->GetStartPoint( ptOrig) ;
Vector3d vtX ; pCrvTrap->GetStartDir( vtX) ;
return frLoc.Set( ptOrig, Z_AX, vtX) ;
}
//------------------------------------------------------
bool
Pocketing::CalcTrapezoidSpiralXCoord( const ICurveComposite* pCrvPocket, int nBase, int nSecondBase,
bool bStart, double dYCoord, double& dXCoord, double dPocketSize)
{
// parametri
double dDiam = m_dDiam_Prec > 0 ? m_dDiam_Prec : m_TParams.m_dDiam ;
double dOffsR = m_dDiam_Prec > 0 ? m_dOffsetR_Prec : GetOffsR() ;
double dRad = 0.5 * dDiam + dOffsR ;
const double TOLL = 50 * EPS_SMALL ;
// recupero la curva di interesse
int nCrvId = ( bStart ? nSecondBase : nBase) + 1 ;
int nProp = - 1 ;
if ( ! pCrvPocket->GetCurveTempProp( nCrvId, nProp))
return false ;
// se open
if ( nProp == 1) {
Point3d pt1, pt2 ;
pCrvPocket->GetCurve( nCrvId)->GetStartPoint( pt1) ;
pCrvPocket->GetCurve( nCrvId)->GetEndPoint( pt2) ;
if ( bStart)
dXCoord = min( pt1.x, pt2.x) ;
else
dXCoord = max( pt1.x, pt2.x) ;
}
// se closed
else {
// creo la curva destra/sinistra
int nLast = bStart ? pCrvPocket->GetCurveCount() : nSecondBase ;
PtrOwner<ICurveComposite> pCrvSide( ConvertCurveToComposite( pCrvPocket->CopyParamRange( nCrvId, nLast))) ;
if ( IsNull( pCrvSide))
return false ;
// Offsetto la curva
OffsetCurve OffsCrv ;
if ( ! OffsCrv.Make( pCrvSide, - dRad, ICurve::OFF_FILLET)) {
m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ;
return false ;
}
if ( OffsCrv.GetCurveCount() == 0) {
// controllo se avevo una circonferenza
if ( pCrvSide->GetCurveCount() == 1 && pCrvSide->GetFirstCurve()->GetType() == CRV_ARC) {
Point3d ptS ; pCrvSide->GetStartPoint( ptS) ;
dXCoord = ptS.x ;
}
else {
Point3d ptS ; pCrvSide->GetStartPoint( ptS) ;
Point3d ptE ; pCrvSide->GetEndPoint( ptE) ;
dXCoord = bStart ? max( ptS.x, ptE.x) + dRad : min( ptS.x, ptE.x) - dRad ;
}
}
else if ( OffsCrv.GetCurveCount() == 1) {
// controllo se la curva interseca la linea di svuotatura a YCoord
PtrOwner<ICurve> pCrvOffs( OffsCrv.GetLongerCurve()) ;
if ( IsNull( pCrvOffs))
return false ;
PtrOwner<ICurveLine> pLineMid( CreateCurveLine()) ;
if ( IsNull( pLineMid))
return false ;
pLineMid->Set( Point3d( -3000, dYCoord, 0), Point3d( 3000, dYCoord, 0)) ;
IntersCurveCurve intCC( *pLineMid, *pCrvOffs) ;
IntCrvCrvInfo ccClass ;
if ( intCC.GetIntersCount() != 0) {
// se ho almeno una intersezione
if ( intCC.GetIntCrvCrvInfo( 0, ccClass))
dXCoord = ccClass.IciA[0].ptI.x ;
else
return false ;
}
else {
// se non ho intersezioni...
// prendo il box della curva
BBox3d Box3d ;
pCrvSide->GetLocalBBox( Box3d) ;
// creo la linea limitie verticale
PtrOwner<ICurveLine> pCrvVertLine( CreateCurveLine()) ;
if ( IsNull( pCrvVertLine))
return false ;
if ( bStart)
pCrvVertLine->SetPDL( Box3d.GetMax() + 5 * TOLL * Y_AX, - 90 , 2 * dPocketSize) ;
else
pCrvVertLine->SetPDL( Box3d.GetMin() - 5 * TOLL * Y_AX, 90, 2 * dPocketSize) ;
// intersechiamo
IntersCurveCurve intCC2( *pCrvVertLine, *pCrvSide) ;
if ( intCC2.GetOverlaps()) {
if ( bStart)
dXCoord = Box3d.GetMax().x + dRad ;
else
dXCoord = Box3d.GetMin().x - dRad ;
}
else {
dXCoord = bStart ? -INFINITO : INFINITO ;
for ( int i = 0 ; i < intCC2.GetIntersCount() ; ++ i) {
IntCrvCrvInfo ccClass2 ;
if ( intCC2.GetIntCrvCrvInfo( i, ccClass2)) {
if ( bStart)
dXCoord = max( dXCoord, Box3d.GetMax().x + sqrt( dRad * dRad - pow(( ccClass2.IciA[0].ptI.y - dYCoord), 2))) ;
else
dXCoord = min( dXCoord, Box3d.GetMin().x - sqrt( dRad * dRad - pow(( ccClass2.IciA[0].ptI.y - dYCoord), 2))) ;
}
}
}
}
}
else
return false ;
}
return true ;
}
//----------------------------------------------------
bool
Pocketing::AdjustTrapezoidSpiralForAngles( ICurveComposite* pMCrv, const ICurveComposite* pCrvPocket,
bool bStart)
{
// parametri
double dDiam = m_dDiam_Prec > 0 ? m_dDiam_Prec : m_TParams.m_dDiam ;
double dOffsR = m_dDiam_Prec > 0 ? m_dOffsetR_Prec : GetOffsR() ;
double dRad = 0.5 * dDiam + dOffsR ;
const double TOLL = 50 * EPS_SMALL ;
PtrOwner<ICurveComposite> pCompo( CreateCurveComposite()) ;
if ( ! bStart)
pMCrv->Invert() ;
Point3d ptTmp ;
pMCrv->GetStartPoint( ptTmp) ;
double dYCoord = ptTmp.y ; // quota verticale del percorso di svuotatura
pCrvPocket->GetCurve( 2)->GetStartPoint( ptTmp) ;
double dPocketSize = ptTmp.y ;
int nCrvId = ( bStart ? 3 : 1) ;
PtrOwner<ICurveLine> pLine( GetCurveLine( pCrvPocket->GetCurve( nCrvId)->Clone())) ;
pLine->SimpleOffset( - dRad) ;
Point3d ptP1, ptP2 ;
pLine->GetStartPoint( ptP1) ;
pLine->GetEndPoint( ptP2) ;
if ( ! bStart)
swap( ptP1, ptP2) ;
int nProp2 ;
// lato opposto a quello di riferimento aperto
if ( pCrvPocket->GetCurveTempProp( 2, nProp2) && nProp2 != 0) {
// caso 1 : pLine ha un estremo sopra e uno sotto il percorso di svuotatura pMCrv
if ( ptP2.y < dYCoord && dYCoord < ptP1.y) {
// creo tratto da ptP2 a ptP1
pCompo->AddPoint( ptP2) ;
pCompo->AddLine( ptP1) ;
// trovo il punto di pMCrv da cui ripartire per non lasciare aree residue
pLine->SimpleOffset( - 0.5 * dDiam) ;
pLine->ExtendStartByLen( EPS_SMALL) ;
pLine->ExtendEndByLen( EPS_SMALL) ;
IntersCurveCurve intCC( *pLine, *pCrvPocket) ;
if ( intCC.GetIntersCount() == 0)
return false ;
IntCrvCrvInfo aInfo ;
intCC.GetIntCrvCrvInfo( 0, aInfo) ;
double dDeltaX = sqrt( max( 0., dDiam * dDiam / 4 - dYCoord * dYCoord)) ;
if ( ! bStart)
dDeltaX *= -1 ;
Point3d ptCrv( aInfo.IciA[0].ptI.x + dDeltaX, dYCoord) ;
double dPar = 0 ;
if ( ! pMCrv->GetParamAtPoint( ptCrv, dPar)) {
dPar = 0.5 ;
pMCrv->GetPointD1D2( dPar, ICurve::FROM_MINUS, ptCrv) ;
}
if ( ! pMCrv->TrimStartAtParam( dPar))
pMCrv->Clear() ;
if ( ptP1.y > dPocketSize) {
// se ptP1 è esterno alla svuotatura scambio i punti in modo da usare ptP2 per il biarco ( così da non farlo fuoriuscire troppo)
swap( ptP1, ptP2) ;
pCompo->Invert() ;
}
// creo biarco fra ptP1 e ptCrv
Vector3d vtDir ;
pCompo->GetStartDir( vtDir) ;
double dAng ;
vtDir.GetAngleXY( X_AX, dAng) ;
PtrOwner<ICurve> pBiArc( GetBiArc( ptP1, - dAng, ptCrv, bStart ? 0 : 180, 0.8)) ;
bool bUseBiArc = false ;
if ( ! IsNull( pBiArc)) {
// verifico che con il biarco non si oltrepassi il lato obliquo chiuso della svuotatura
IntersCurveCurve intCC2( *pBiArc, *pCompo) ;
if ( intCC2.GetIntersCount() == 1)
bUseBiArc = true ;
}
if ( bUseBiArc)
pCompo->AddCurve( Release( pBiArc)) ;
else {
double dParLine = ( dYCoord - ptP2.y) / ( ptP1.y - ptP2.y) ;
Point3d ptOnLine = Media( ptP2, ptP1, dParLine) ;
pCompo->AddLine( ptOnLine) ;
pCompo->AddLine( ptCrv) ;
}
}
// caso 2 : pLine è completamente sopra/sotto la linea di svuotatura
else {
// se è sopra modifiche per ricondurmi al caso in cui è sotto
if ( ptP2.y > dYCoord) {
pLine->Invert() ;
swap( ptP1, ptP2) ;
}
// trovo l'intersezione fra il prolungamento della linea e pMCrv
if ( bStart)
pLine->ExtendStartByLen( 1000) ;
else
pLine->ExtendEndByLen( 1000) ;
IntersCurveCurve intCC ( *pLine, *pMCrv) ;
if ( intCC.GetIntersCount() == 0)
return false ;
IntCrvCrvInfo aInfo ;
intCC.GetIntCrvCrvInfo( 0, aInfo) ;
Point3d ptInt ;
ptInt = aInfo.IciA[0].ptI ;
double dPar = 0 ;
pMCrv->GetParamAtPoint( ptInt, dPar) ;
if ( ! pMCrv->TrimStartAtParam( dPar))
pMCrv->Clear() ;
pCompo->AddPoint( ptP2) ;
pCompo->AddLine( ptInt) ;
}
}
// se il lato opposto a quello di riferimento chiuso bisogna distinguere i casi
else {
bool bStartPnt = false ;
if ( ptP2.y < dYCoord) {
bStartPnt = pCompo->AddPoint( ptP2) ;
}
else {
Vector3d vtDir ;
pLine->GetStartDir( vtDir) ;
if ( bStart)
vtDir.Invert() ;
Point3d ptP2N = ptP2 - dDiam / 2 * abs( vtDir.x / vtDir.y) * vtDir ;
if ( ptP2N.y < dYCoord)
bStartPnt = pCompo->AddPoint( ptP2N) ;
}
if ( bStartPnt) {
Point3d ptCrv ;
pMCrv->GetStartPoint( ptCrv) ;
pCompo->AddLine( ptCrv) ;
}
}
// setto temp prop per ricordare che è curva aggiuntiva per pulire angoli
for ( int i = 0 ; i < pCompo->GetCurveCount() ; i++)
pCompo->SetCurveTempProp( i, 1) ;
pMCrv->AddCurve( Release( pCompo), false) ;
if ( ! bStart)
pMCrv->Invert() ; // ripristino la direzione originaria
return true ;
}
//----------------------------------------------------
bool
Pocketing::SpecialAdjustTrapezoidSpiralForAngles( ICurveComposite* pMCrv, const bool bEvenClosed, const ICurveComposite* pCrvPocket)
{
// parametri
double dDiam = m_dDiam_Prec > 0 ? m_dDiam_Prec : m_TParams.m_dDiam ;
double dOffsR = m_dDiam_Prec > 0 ? m_dOffsetR_Prec : GetOffsR() ;
double dRad = 0.5 * dDiam + dOffsR ;
// calcolo gli offset dei lati obliqui
PtrOwner<ICurveLine> pLineS( GetCurveLine( pCrvPocket->GetCurve( bEvenClosed ? 0 : 3)->Clone())) ;
pLineS->SimpleOffset( - dRad) ;
pLineS->Invert() ;
PtrOwner<ICurveLine> pLineE( GetCurveLine( pCrvPocket->GetCurve( bEvenClosed ? 2 : 1)->Clone())) ;
pLineE->SimpleOffset( - dRad) ;
pLineE->Invert() ;
Point3d ptS, ptE ;
pLineS->GetEndPoint( ptS) ;
pLineE->GetStartPoint( ptE) ;
Vector3d vtS, vtE ;
pLineS->GetStartDir( vtS) ;
pLineE->GetStartDir( vtE) ;
PtrOwner<ICurveLine> pLineLink( CreateCurveLine()) ;
pLineLink->Set( ptS, ptE) ;
pMCrv->Clear() ;
if ( ! pMCrv->AddCurve( Release( pLineS)))
return false ;
// creo raccordi
bool bUseBiArcs = false ;
Vector3d vtDir, vtDir2 ;
pLineLink->GetStartDir( vtDir) ;
pCrvPocket->GetCurve( bEvenClosed ? 1 : 0)->GetStartDir( vtDir2) ;
if ( Dist( ptS, ptE) > 500 * EPS_SMALL && AreSameOrOppositeVectorApprox( vtDir, vtDir2)) {
Point3d ptCrv1, ptCrv2 ;
pLineLink->GetPointD1D2( 0.3, ICurve::FROM_MINUS, ptCrv1) ;
pLineLink->GetPointD1D2( 0.7, ICurve::FROM_MINUS, ptCrv2) ;
// primo raccordo
double dAng ;
vtS.GetAngleXY( X_AX, dAng) ;
PtrOwner<ICurve> pBiArc1( GetBiArc( ptS, - dAng, ptCrv1, bEvenClosed ? 90 : 0, 0.5)) ;
// secondo raccordo
vtE.Invert() ;
vtE.GetAngleXY( X_AX, dAng) ;
PtrOwner<ICurve> pBiArc2( GetBiArc( ptE, - dAng, ptCrv2, bEvenClosed ? - 90 : 180, 0.5)) ;
pBiArc2->Invert() ;
if ( ! IsNull( pBiArc1) && ! IsNull( pBiArc2)) {
bUseBiArcs = true ;
pMCrv->AddCurve( Release( pBiArc1)) ;
pMCrv->AddLine( ptCrv2) ;
pMCrv->AddCurve( Release( pBiArc2)) ;
}
}
// se non è stato possibile creare raccordo, unisco linearmente
if ( ! bUseBiArcs)
pMCrv->AddCurve( Release( pLineLink)) ;
if ( ! pMCrv->AddCurve( Release( pLineE)))
return false ;
// setto temp prop per ricordare curve aggiuntive per pulire angoli
pMCrv->SetCurveTempProp( 0, 1) ;
pMCrv->SetCurveTempProp( pMCrv->GetCurveCount() - 1, 1) ;
return true ;
}
//----------------------------------------------------
bool
Pocketing::AdjustTrapezoidSpiralForLeadInLeadOut( ICurveComposite* pCompo, ICurveComposite* pRCrv, const Vector3d& vtTool, double dDepth,
int& nOutsideRaw)
{
// recupero la direzione principale della svuotatura
Vector3d vtMainDir ;
for ( int i = 0 ; i < pCompo->GetCurveCount() ; i++) {
int nProp ;
if ( pCompo->GetCurveTempProp( i, nProp) && nProp == 0) {
// se non è lato aggiuntivo per la pulitura angoli recupero la sua direzione
pCompo->GetCurve( i)->GetStartDir( vtMainDir) ;
break ;
}
}
// start point
bool bStartOutside = false ;
ComputeTrapezoidSpiralLeadInLeadOut( pCompo, vtMainDir, true, vtTool, dDepth, bStartOutside) ;
// end point
bool bEndOutside = false ;
ComputeTrapezoidSpiralLeadInLeadOut( pCompo, vtMainDir, false, vtTool, dDepth, bEndOutside) ;
// eventuale inversione della curva per partire sempre dall'esterno del grezzo
if ( bEndOutside && ! bStartOutside)
pCompo->Invert() ;
nOutsideRaw = 0 ;
if ( bStartOutside && bEndOutside)
nOutsideRaw = 2 ;
else if ( bStartOutside || bEndOutside) {
nOutsideRaw = 1 ;
// calcolo percorso di ritorno
pRCrv->Clear() ;
pRCrv->AddCurve( pCompo->Clone()) ;
pRCrv->Invert() ;
}
return true ;
}
//----------------------------------------------------
bool
Pocketing::ComputeTrapezoidSpiralLeadInLeadOut( ICurveComposite* pCompo, const Vector3d& vtMainDir, bool bLeadIn, const Vector3d& vtTool, double dDepth, bool& bIsOutsideRaw)
{
bIsOutsideRaw = false ;
Point3d ptP ;
Vector3d vtDir ;
if ( bLeadIn) {
pCompo->GetStartPoint( ptP) ;
pCompo->GetStartDir( vtDir) ;
}
else {
pCompo->GetEndPoint( ptP) ;
pCompo->GetEndDir( vtDir) ;
}
// per non farlo coincedere esttamente con la faccia del grezzo ( per CalcElev)
//ptP += 20 * EPS_SMALL *vtDir ;
Vector3d vtExtr ; pCompo->GetExtrusion( vtExtr) ;
// recupero info sui lati aperti
int nPropOpen = pCompo->GetTempProp( 0) ;
bool bEdgeOpen = (( nPropOpen & ( bLeadIn ? 8 : 2)) > 0) ;
bool bBaseOpen = (( nPropOpen & 1) > 0) ;
// recupero info per capire se sto considerando un lato aggiuntivo per pulire angoli
int nIdCrv = ( bLeadIn ? 0 : pCompo->GetCurveCount() - 1) ;
int nExtraEdge ;
pCompo->GetCurveTempProp( nIdCrv, nExtraEdge) ;
double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ;
// tento con allungamento se lato inclinato è aperto oppure se sto considerando un lato aggiuntivo per pulire angoli
if ( bEdgeOpen || nExtraEdge == 1) {
Vector3d vtDirP = ( bLeadIn ? -vtDir : vtDir) ;
// se forzato come fuori dal grezzo
if ( m_bOpenOutRaw) {
Point3d ptNewStart = ptP + vtDirP * ( m_TParams.m_dDiam / 2 + max( dSafeZ, m_dOpenMinSafe)) ;
pCompo->AddLine( ptNewStart, ! bLeadIn) ;
bIsOutsideRaw = true ;
return true ;
}
// recupero la distanza dal bordo del grezzo lungo la direzione di allungamento
double dDist ;
Vector3d vtNorm ;
if ( ! GetSignedDistFromRealDirection( ptP, vtDirP, dDist, vtNorm))
return false ;
// calcolo eventuali fattori correttivi (se uscita approx. con fianco utensile)
double dCorr = 1 ;
double dDistRef = dDist ;
double dDistMin ;
Vector3d vtNormMin ;
if ( abs( vtTool * vtNorm) < 0.5 && GetSignedDistFromRealDirection( ptP, vtNorm, dDistMin, vtNormMin)) {
if ( abs( dDistMin) < abs( dDist) && abs( dDistMin) > EPS_SMALL) {
dDistRef = dDistMin ;
dCorr = dDist / dDistMin ;
}
}
// ( se sono dentro al grezzo e se sono vicino al bordo del grezzo) oppure sono fuori ( circa sul bordo)
if (( dDistRef < EPS_SMALL && abs( dDistRef) < m_TParams.m_dDiam / 2 + EPS_SMALL ) || dDistRef > - EPS_SMALL) {
Point3d ptTest = ptP + vtDirP * ( - dDist + ( m_TParams.m_dDiam / 2 + max( dSafeZ, m_dOpenMinSafe)) * dCorr) ;
ptTest += - vtTool * dDepth ;
double dTestElev ;
// se è fuori dal grezzo
if ( ! GetElevation( m_nPhase, ptTest, vtTool, m_TParams.m_dDiam / 2, vtTool, dTestElev) || dTestElev < EPS_SMALL) {
Point3d ptNewStart = ptP + vtDirP * ( - dDist + ( m_TParams.m_dDiam / 2 + max( dSafeZ, m_dOpenMinSafe)) * dCorr) ;
pCompo->AddLine( ptNewStart, ! bLeadIn) ;
bIsOutsideRaw = true ;
}
}
}
// tento con attacco ruotato di 90° se non sto considerando un tratto aggiuntivo per pulire angoli
if ( bBaseOpen && ! bIsOutsideRaw && nExtraEdge == 0) {
Vector3d vtDirO = vtDir ;
vtDirO.Rotate( vtExtr, ( m_Params.m_bInvert ? -90 : 90)) ;
// calcolo distanza dal bordo del grezzo lungo vtDirO
double dDist ;
Vector3d vtNorm ;
if ( ! GetSignedDistFromRealDirection( ptP, vtDirO, dDist, vtNorm))
return false ;
// se vicino al bordo del grezzo
if ( abs( dDist) < m_TParams.m_dDiam / 2 + EPS_SMALL) {
Point3d ptTestO = ptP + vtDirO * ( - dDist + m_TParams.m_dDiam / 2 + max( dSafeZ, m_dOpenMinSafe)) ;
ptTestO += - vtTool * dDepth ;
double dTestElevO ;
// se è fuori dal grezzo uso inizio ruotato
if ( ! GetElevation( m_nPhase, ptTestO, vtTool, m_TParams.m_dDiam / 2, vtTool, dTestElevO) || dTestElevO < EPS_SMALL) {
Point3d ptNewStart = ptP + vtDirO * ( - dDist + m_TParams.m_dDiam / 2 + max( dSafeZ, m_dOpenMinSafe)) ;
pCompo->AddLine( ptNewStart, ! bLeadIn) ;
bIsOutsideRaw = true ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetSignedDistFromRealDirection( const Point3d ptP, const Vector3d vtDir, double& dDist, Vector3d& vtNorm)
{
// calcolo la distanza lungo vtDir...
if ( ! GetSignedDistFromStmRaw( m_nPhase, ptP, vtDir, dDist, vtNorm))
return false ;
// se risulta infinita, allora sono fuori dal grezzo, quindi inverto vtDir e ricalcolo la distanza
if ( dDist > INFINITO - 1) {
if ( ! GetSignedDistFromStmRaw( m_nPhase, ptP, -vtDir, dDist, vtNorm))
return false ;
// se ancora infinita, errore
else if ( dDist > INFINITO - 1)
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::ComputePolishingPath( ICurveComposite* pMCrv, ICurveComposite* pRCrv, bool bSplitArcs)
{
PtrOwner<ICurveComposite> pCompo( CreateCurveComposite()) ;
PtrOwner<ICurveComposite> pCrvBound( CreateCurveComposite()) ; // curva bound da usare per CalcBoundedLink
ICRVCOMPOPOVECTOR vpCrvsEp ;
Frame3d frLoc ;
Vector3d vtExtr ; pMCrv->GetExtrusion( vtExtr) ;
frLoc.Set( ORIG, vtExtr) ;
pMCrv->ToLoc( frLoc) ;
for ( int i = 0 ; i < pMCrv->GetCurveCount() ; i ++) {
int nProp = 0 ;
if ( ! pMCrv->GetCurveTempProp( i, nProp))
return false ;
// se è un tratto di collegamento ho concluso percorso su cui aggiungere epicicli
if ( nProp == LINK_CURVE_PROP) {
if ( pCompo->IsValid()) {
PtrOwner<ICurveComposite> pCrvEp( CreateCurveComposite()) ;
// la curva di bound è l'offset che calcolo in AddEpicycles per la prima curva compo trovata in pMCrv
bool bAddEp = ( ! pCrvBound->IsValid()) ? AddEpicycles( pCompo, pCrvEp, pCrvBound) : AddEpicycles( pCompo, pCrvEp) ;
if ( ! bAddEp)
return false ;
vpCrvsEp.emplace_back( Release( pCrvEp)) ;
pCompo.Set( CreateCurveComposite()) ;
}
}
// se non è tratto di collegamento lo aggiungo alla curva
else {
if ( ! pCompo->AddCurve( pMCrv->GetCurve(i)->Clone()))
return false ;
}
}
// ultima curva
if ( ! IsNull( pCompo)) {
PtrOwner<ICurveComposite> pCrvEp( CreateCurveComposite()) ;
if ( ! AddEpicycles( pCompo, pCrvEp))
return false ;
vpCrvsEp.emplace_back( Release( pCrvEp)) ;
}
// calcolo i collegamenti
ICURVEPOVECTOR vLinks( vpCrvsEp.size()) ;
for ( int i = 1 ; i < int( vpCrvsEp.size()) ; ++ i) {
// punti e direzioni di inizio e fine
Point3d ptStart ; Vector3d vtStart ;
vpCrvsEp[i-1]->GetEndPoint( ptStart) ;
vpCrvsEp[i-1]->GetEndDir( vtStart) ;
Point3d ptEnd ; Vector3d vtEnd ;
vpCrvsEp[i]->GetStartPoint( ptEnd) ;
vpCrvsEp[i]->GetStartDir( vtEnd) ;
// calcolo il collegamento con biarchi (garantendo che non esca dalla svuotatura)
PtrOwner<ICurveComposite> pCrvLink( CreateCurveComposite()) ;
if ( CalcBoundedLinkWithBiArcs( ptStart, vtStart, ptEnd, vtEnd, pCrvBound, pCrvLink)) {
vLinks[i].Set( pCrvLink) ;
}
else {
m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ;
return false ;
}
}
// calcolo il percorso di ritorno
pRCrv->Clear() ;
if ( vpCrvsEp.size() >= 2) {
// punti di inizio e fine
Point3d ptStart ; Vector3d vtStart ;
vpCrvsEp.back()->GetEndPoint( ptStart) ;
vpCrvsEp.back()->GetEndDir( vtStart) ;
Point3d ptEnd ; Vector3d vtEnd ;
vpCrvsEp.front()->GetStartPoint( ptEnd) ;
vpCrvsEp.front()->GetStartDir( vtEnd) ;
// calcolo il ritorno con biarchi (garantendo che non esca dalla svuotatura)
PtrOwner<ICurveComposite> pCrvLink( CreateCurveComposite()) ;
if ( CalcBoundedLinkWithBiArcs( ptStart, vtStart, ptEnd, vtEnd, pCrvBound, pCrvLink)) {
pRCrv->AddCurve( Release( pCrvLink)) ;
pRCrv->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, false) ;
// se necessario, approssimo archi con rette
if ( bSplitArcs && ! ApproxWithLines( pRCrv)) {
m_pMchMgr->SetLastError( 2421, "Error in Pocketing : Linear Approx not computable") ;
return false ;
}
VerifyArcs( pRCrv) ;
}
else {
m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ;
return false ;
}
}
// creo il percorso di lavoro a partire dalla raccolta delle curve con epicicli e dei collegamenti
pMCrv->Clear() ;
for ( int i = 0 ; i < int( vpCrvsEp.size()) ; ++ i) {
// se collegamento da aggiungere
if ( ! IsNull( vLinks[i])) {
// accodo nel percorso di lavorazione
pMCrv->AddCurve( Release( vLinks[i])) ;
}
// aggiungo la curva
pMCrv->AddCurve( Release( vpCrvsEp[i])) ;
}
// se necessario, approssimo archi con rette
if ( bSplitArcs && ! ApproxWithLines( pMCrv)) {
m_pMchMgr->SetLastError( 2421, "Error in Pocketing : Linear Approx not computable") ;
return false ;
}
VerifyArcs( pMCrv) ;
pMCrv->ToGlob( frLoc) ;
pRCrv->ToGlob( frLoc) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AddEpicycles( ICurveComposite* pCompo, ICurveComposite * pCrv, ICurveComposite * pCrvBound)
{
if ( m_Params.m_bInvert)
pCompo->Invert() ; // oriento la curva in senso antiorario
OffsetCurve OffsCrv ;
double dOffs = m_Params.m_dEpicyclesRad ;
if ( ! OffsCrv.Make( pCompo, dOffs, ICurve::OFF_FILLET)) {
m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ;
return false ;
}
if ( OffsCrv.GetCurveCount() > 1)
return false ;
PtrOwner<ICurveComposite> pCrvOffs( GetCurveComposite( OffsCrv.GetCurve())) ;
if ( IsNull( pCrvOffs))
return false ;
// verifico se devo resitituire la curva offsettata
if ( pCrvBound)
pCrvBound->AddCurve( pCrvOffs->Clone()) ;
pCrv->Clear() ;
double dParPrec = 0 ;
for ( int i = 0 ; i < pCompo->GetCurveCount() ; i++) {
// calcolo distanza epicili specifica per quel tratto
double dLen ;
pCompo->GetCurve( i)->GetLength( dLen) ;
int nStep = max( 1, static_cast<int>( ceil( ( dLen) / m_Params.m_dEpicyclesDist))) ;
double dStep = 1.0 / nStep ;
for ( int k = 1 ; k <= nStep ; k ++) {
// creo epiciclo
PtrOwner<ICurveArc> pCrvArc( CreateCurveArc()) ;
Point3d ptCen ;
Vector3d vtDir ;
pCompo->GetCurve( i)->GetPointD1D2( k * dStep, ICurve::FROM_MINUS, ptCen, &vtDir) ;
vtDir.Normalize() ;
vtDir.Rotate( Z_AX, - 90) ;
Point3d pt = ptCen + vtDir * m_Params.m_dEpicyclesRad ;
pCrvArc->Set( ptCen, Z_AX, m_Params.m_dEpicyclesRad) ;
double dU ;
pCrvArc->GetParamAtPoint( pt, dU) ;
pCrvArc->ChangeStartPoint( dU) ;
// aggiungo tratto della curva offsettata
double dPar ;
pCrvOffs->GetParamAtPoint( pt, dPar) ;
bool bAdd = pCrv->AddCurve( pCrvOffs->CopyParamRange( dParPrec, dPar)) ;
// aggiungo epiciclo
if ( ! pCrv->AddCurve( Release( pCrvArc))) {
// se fallisco nell'aggiungere l'epiciclo tento nuovamente spostandolo di EPS_SMALL
if ( bAdd)
PtrOwner<ICurve> pCrvErased( pCrv->RemoveFirstOrLastCurve( true)) ;
k -- ;
dStep -= EPS_SMALL ;
if ( dStep < EPS_SMALL)
return false ;
}
else
dParPrec = dPar ;
}
}
// se necessario ripristino orientamento originale
if ( m_Params.m_bInvert)
pCrv->Invert() ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AddApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ,
double dElev, double dAppr, bool bOutStart)
{
SetFlag( 1) ;
// se con aggregato da sotto o equivalente (rinvio a 90 gradi su testa 5 assi)
bool bBottomOutStart = false ;
if ( m_bAggrBottom) {
// distanza dal bordo del pezzo (se negativa il punto è fuori dal grezzo)
double dDistBottom ;
if ( ! GetDistanceFromRawSide( m_nPhase, ptP, m_vtAggrBottom, dDistBottom))
dDistBottom = 0 ;
bBottomOutStart = ( dDistBottom < - 10 * EPS_SMALL) ;
// aggiuntivo in Z
double dAggZ = ( bBottomOutStart ? 0. : max( dElev + max( dSafeAggrBottZ, dAppr), 0.)) ;
// pre-approccio
Point3d ptP0 = ptP - Z_AX * dAggZ + m_vtAggrBottom * ( dDistBottom + m_AggrBottom.dEncH + dSafeZ) ;
Point3d ptP00 = ptP0 + Z_AX * ( m_AggrBottom.dEncV + m_TParams.m_dLen + dAggZ - dElev) ;
// se rinvio da sotto che richiede speciale rotazione
if ( m_AggrBottom.nType == 1) {
Vector3d vtAux = m_vtAggrBottom ;
vtAux.Rotate( Z_AX, 0, 1) ;
SetAuxDir( vtAux) ;
if ( AddRapidStart( ptP00, MCH_CL_AGB_DWN) == GDB_ID_NULL)
return false ;
SetAuxDir( m_vtAggrBottom) ;
SetFlag( 0) ;
if ( AddRapidMove( ptP0, MCH_CL_AGB_IN) == GDB_ID_NULL)
return false ;
}
// altrimenti rinvio normale
else {
SetAuxDir( m_vtAggrBottom) ;
if ( AddRapidStart( ptP0, MCH_CL_AGB_IN) == GDB_ID_NULL)
return false ;
SetFlag( 0) ;
}
}
// se sopra attacco c'è spazio per sicurezza o approccio
double dSafeDist = ( m_bAggrBottom ? dSafeAggrBottZ : dSafeZ) ;
if ( ! bBottomOutStart && 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 ( ( ! m_bAggrBottom && AddRapidStart( ptP1) == GDB_ID_NULL) ||
( m_bAggrBottom && AddRapidMove( ptP1) == GDB_ID_NULL))
return false ;
}
else {
// 1a -> punto sopra inizio
Point3d ptP1b = ptP + vtTool * ( dElev + dAppr) ;
Point3d ptP1a = ptP1b + vtTool * ( dSafeDist - dAppr) ;
if ( ( ! m_bAggrBottom && AddRapidStart( ptP1a) == GDB_ID_NULL) ||
( m_bAggrBottom && AddRapidMove( ptP1a) == GDB_ID_NULL))
return false ;
// 1b -> punto appena sopra inizio
if ( ( dElev + dAppr) > EPS_SMALL) {
SetFlag( 0) ;
if ( AddRapidMove( ptP1b) == GDB_ID_NULL)
return false ;
}
}
// affondo al punto iniziale
SetFlag( 0) ;
SetFeed( bOutStart ? GetStartFeed() : GetTipFeed()) ;
if ( AddLinearMove( ptP) == GDB_ID_NULL)
return false ;
}
else {
// affondo diretto al punto iniziale
SetFlag( 0) ;
if ( ( ! m_bAggrBottom && AddRapidStart( ptP) == GDB_ID_NULL) ||
( m_bAggrBottom && AddRapidMove( ptP) == GDB_ID_NULL))
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AddLinkApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ,
double dElev, double dAppr, bool bOutStart)
{
// 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( bOutStart ? 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
Pocketing::AddLinkRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ,
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
Pocketing::AddRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ,
double dElev, double dAppr)
{
// se con aggregato da sotto o equivalente (rinvio a 90 gradi su testa 5 assi)
bool bBottomOutStart = false ;
double dDistBottom ;
if ( m_bAggrBottom) {
// distanza dal bordo del pezzo
if ( ! GetDistanceFromRawSide( m_nPhase, ptP, m_vtAggrBottom, dDistBottom))
dDistBottom = 0 ;
bBottomOutStart = ( dDistBottom < - 10 * EPS_SMALL) ;
}
// se sopra uscita c'è spazio per sicurezza o approccio
double dSafeDist = ( m_bAggrBottom ? dSafeAggrBottZ : dSafeZ) ;
if ( ! bBottomOutStart && 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 ;
}
}
// se con aggregato da sotto o equivalente (rinvio a 90 gradi su testa 5 assi)
if ( m_bAggrBottom) {
// aggiuntivo in Z
double dAggZ = ( bBottomOutStart ? 0. : max( dElev + max( dSafeAggrBottZ, dAppr), 0.)) ;
// post-retract
Point3d ptP0 = ptP - Z_AX * dAggZ + m_vtAggrBottom * ( dDistBottom + m_AggrBottom.dEncH + dSafeZ) ;
Point3d ptP00 = ptP0 + Z_AX * ( m_AggrBottom.dEncV + m_TParams.m_dLen + dAggZ - dElev) ;
if ( AddRapidMove( ptP0, MCH_CL_AGB_OUT) == GDB_ID_NULL)
return false ;
// se rinvio da sotto che richiede speciale rotazione
if ( m_AggrBottom.nType == 1) {
Vector3d vtAux = m_vtAggrBottom ;
vtAux.Rotate( Z_AX, 0, 1) ;
SetAuxDir( vtAux) ;
if ( AddRapidMove( ptP00, MCH_CL_AGB_UP) == GDB_ID_NULL)
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::CalcLeadInStart( const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtN,
const ICurveComposite* pRCrv, Point3d& ptP1) const
{
// Assegno tipo e parametri
int nType = GetLeadInType() ;
if ( nType == POCKET_LI_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0))
nType = POCKET_LI_NONE ;
// Calcolo punto iniziale
switch ( nType) {
case POCKET_LI_NONE :
case POCKET_LI_ZIGZAG :
case POCKET_LI_HELIX :
ptP1 = ptStart ;
return true ;
case POCKET_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 += vtN * ( vtN * ( ptStart - ptP1)) ;
return true ;
}
default :
return false ;
}
}
//----------------------------------------------------------------------------
bool
Pocketing::AddLeadIn( const Point3d& ptP1, const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtN,
ISurfFlatRegion* pSrfChunk, 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 == POCKET_LI_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0)))
nType = POCKET_LI_NONE ;
// Se elica e fattibile lo creo
if ( nType == POCKET_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( pSrfChunk, ptCen, dRad)) {
// creo l'elica
PtrOwner<ICurveArc> pArc( CreateCurveArc()) ;
if ( IsNull( pArc) || ! pArc->Set( ptCen, vtN, dRad, - vtCen, dAngCen, dDeltaN))
return false ;
// eventuale spezzatura
if ( bSplitArcs) {
PtrOwner<ICurveComposite> pCompo ;
if ( ! pCompo.Set( ConvertCurveToComposite( Release( pArc))) || ! ApproxWithLines( pCompo))
return false ;
return ( AddCurveMove( pCompo, MCH_CL_LEADIN) != GDB_ID_NULL) ;
}
else {
// emetto l'elica
return ( AddCurveMove( pArc, MCH_CL_LEADIN) != GDB_ID_NULL) ;
}
}
// altrimenti zigzag
else
nType = POCKET_LI_ZIGZAG ;
}
// Se zigzag e fattibile lo creo
if ( nType == POCKET_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) ;
// verifico se fattibile
if ( bSkipControl || VerifyLeadInZigZag( pSrfChunk, ptPa, ptPb)) {
for ( int i = 1 ; i <= nStep ; ++ i) {
if ( AddLinearMove( ptPa - vtN * ( i - 0.75) * dStep, MCH_CL_LEADIN) == GDB_ID_NULL)
return false ;
if ( AddLinearMove( ptPb - vtN * ( i - 0.25) * dStep, MCH_CL_LEADIN) == GDB_ID_NULL)
return false ;
}
return ( AddLinearMove( ptStart, MCH_CL_LEADIN) != GDB_ID_NULL) ;
}
// altrimenti diretto
else {
nType = POCKET_LI_NONE ;
if ( m_TParams.m_nType == TT_MILL_NOTIP)
return false ;
}
}
// Se a scivolo e fattibile
if ( nType == POCKET_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) ;
// eventuale spezzatura
if ( bSplitArcs && ! ApproxWithLines( pCrv))
return false ;
// emetto
return ( AddCurveMove( pCrv) != GDB_ID_NULL) ;
}
// altrimenti diretto
else
nType = POCKET_LI_NONE ;
}
// Se diretto
if ( nType == POCKET_LI_NONE) {
Point3d ptCurr = ptP1 ;
GetCurrPos( ptCurr) ;
if ( ! AreSamePointApprox( ptCurr, ptStart)) {
if ( AddLinearMove( ptStart, MCH_CL_LEADIN) == GDB_ID_NULL)
return false ;
}
return true ;
}
// Altrimenti errore
return false ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AddLeadOut( const Point3d& ptEnd, const Vector3d& vtEnd, const Vector3d& vtN,
const ICurveComposite* pRCrv, bool bSplitArcs, bool bNoneForced,
Point3d& ptP1, double& dElev, bool bRecalcElev)
{
bool bOppositeHome ;
return AddLeadOut( ptEnd, vtEnd, vtN, pRCrv, bSplitArcs, bNoneForced, ptP1, dElev, bOppositeHome, bRecalcElev) ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AddLeadOut( const Point3d& ptEnd, const Vector3d& vtEnd, const Vector3d& vtN,
const ICurveComposite* pRCrv, bool bSplitArcs, bool bNoneForced,
Point3d& ptP1, double& dElev, bool& bOppositeHome, bool bRecalcElev)
{
// assegno i parametri
int nType = GetLeadOutType() ;
if ( bNoneForced ||
( nType == POCKET_LO_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0)))
nType = POCKET_LO_NONE ;
// eseguo a seconda del tipo
switch ( nType) {
case POCKET_LO_NONE :
{
// nessuna uscita
ptP1 = ptEnd ;
// determino elevazione su fine uscita
if ( bRecalcElev) {
double dEndElev ;
if ( GetElevation( m_nPhase, ptP1 - 10 * EPS_SMALL * vtN, vtN, GetRadiusForStartEndElevation(), vtN, dEndElev))
dElev = dEndElev ;
}
// correzione per punto sotto il grezzo con testa normale da sopra
double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ;
bool bAhUnderRaw = m_bAboveHead && ! m_bAggrBottom && ! m_bTiltingTab &&
GetAhPointUnderRaw( ptP1, vtN, 0, GetRadiusForStartEndElevation(),
m_TParams.m_dLen, false, dSafeZ, vtN, dElev) ;
bool bUhAboveRaw = ! m_bAboveHead &&
GetUhPointAboveRaw( ptP1, vtN, 0, GetRadiusForStartEndElevation(),
m_TParams.m_dLen, false, dSafeZ, vtN, dElev) ;
bOppositeHome = ( bAhUnderRaw || bUhAboveRaw) ;
return true ;
}
case POCKET_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) ;
// eventuale spezzatura
if ( bSplitArcs && ! ApproxWithLines( pCrv))
return false ;
// emetto
AddCurveMove( pCrv) ;
// determino elevazione su fine uscita
ptP1 = ptFin ;
if( bRecalcElev) {
double dEndElev ;
if ( GetElevation( m_nPhase, ptP1 - 10 * EPS_SMALL * vtN, vtN, GetRadiusForStartEndElevation(), vtN, dEndElev))
dElev = dEndElev ;
}
// correzione per punto sotto il grezzo con testa normale da sopra
double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ;
bool bAhUnderRaw = m_bAboveHead && ! m_bAggrBottom && ! m_bTiltingTab &&
GetAhPointUnderRaw( ptP1, vtN, 0, GetRadiusForStartEndElevation(),
m_TParams.m_dLen, false, dSafeZ, vtN, dElev) ;
bool bUhAboveRaw = ! m_bAboveHead &&
GetUhPointAboveRaw( ptP1, vtN, 0, GetRadiusForStartEndElevation(),
m_TParams.m_dLen, false, dSafeZ, vtN, dElev) ;
bOppositeHome = ( bAhUnderRaw || bUhAboveRaw) ;
return true ;
}
default :
bOppositeHome = false ;
return false ;
}
}
//----------------------------------------------------------------------------
double
Pocketing::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
Pocketing::GetParamOnOpenSide( const ICurveComposite* pCompo, const ICRVCOMPOPOVECTOR& vOtherCrv,
Point3d& ptMid, Vector3d& vtMidOrt)
{
// recupero il vettore estrusione
Vector3d vtExtr = Z_AX ;
pCompo->GetExtrusion( vtExtr) ;
// verifico se tutti i lati sono aperti
bool bAllOpen = true ;
const ICurve* pMyCrv = pCompo->GetFirstCurve() ;
while ( pMyCrv != nullptr) {
if ( pMyCrv->GetTempProp() != 1) {
bAllOpen = false ;
break ;
}
pMyCrv = pCompo->GetNextCurve() ;
}
// richiedo lunghezza superiore a diametro utensile più doppio offset radiale
double dRefLen = ( bAllOpen ? 0 : m_TParams.m_dDiam + 2 * GetOffsR() - EPS_SMALL) ;
double dMaxLen = dRefLen ;
// ciclo sulle singole curve
bool bFound = false ;
const ICurve* pPrevCrv = pCompo->GetLastCurve() ;
double dLenPrev = 0 ;
if ( pPrevCrv != nullptr && pPrevCrv->GetTempProp() == 1)
pPrevCrv->GetLength( dLenPrev) ;
const ICurve* pCrv = pCompo->GetFirstCurve() ;
int nPriorityOpenEdge = -1 ;
while ( pCrv != nullptr) {
// analizzo la curva successiva
const ICurve* pNextCrv = pCompo->GetNextCurve() ;
bool bNextOk = ( pNextCrv != nullptr) ;
if ( ! bNextOk)
pNextCrv = pCompo->GetFirstCurve() ;
double dLenNext = 0 ;
if ( pNextCrv != nullptr && pNextCrv->GetTempProp() == 1)
pNextCrv->GetLength( dLenNext) ;
++ nPriorityOpenEdge ;
// verifico la curva corrente
if ( pCrv->GetTempProp() == 1) {
// contributo dalle entità adiacenti (se non tutte aperte)
double dLenAgg = 0 ;
if ( ! bAllOpen) {
if ( pPrevCrv != nullptr && pPrevCrv->GetTempProp() == 1) {
Vector3d vtPrevEnd ; pPrevCrv->GetEndDir( vtPrevEnd) ;
Vector3d vtStart ; pCrv->GetStartDir( vtStart) ;
dLenAgg += max( 0.4, vtPrevEnd * vtStart) * dLenPrev ;
}
if ( pNextCrv != nullptr && pNextCrv->GetTempProp() == 1) {
Vector3d vtEnd ; pCrv->GetEndDir( vtEnd) ;
Vector3d vtNextStart ; pNextCrv->GetStartDir( vtNextStart) ;
dLenAgg += max( 0.4, vtEnd * vtNextStart) * dLenNext ;
}
}
// entità corrente
double dLen = 0 ;
if ( pCrv->GetLength( dLen)) {
const double LEN_TOL = 1 ;
// se di lunghezza praticamente uguale
if ( bFound && dLen + dLenAgg > dRefLen && abs( dLen + dLenAgg - dMaxLen) < LEN_TOL) {
Point3d ptTest ;
pCrv->GetMidPoint( ptTest) ;
if (( m_bAboveHead && ptTest.z > ptMid.z + 100 * EPS_SMALL) ||
( ! m_bAboveHead && ptTest.z < ptMid.z - 100 * EPS_SMALL) ||
( abs( ptTest.z - ptMid.z) < 100 * EPS_SMALL && ptTest.y < ptMid.y - 100 * EPS_SMALL)) {
dMaxLen = max( dMaxLen, dLen + dLenAgg) ;
ptMid = ptTest ;
// vettore ortogonale verso l'esterno (ruotato -90deg attorno a estrusione)
pCrv->GetMidDir( vtMidOrt) ;
vtMidOrt.Rotate( vtExtr, 0, -1) ;
}
}
// se più lunga ( o non già trovata )
else if ( dLen + dLenAgg > dMaxLen || !bFound) {
dMaxLen = dLen + dLenAgg ;
double dParIn ;
// cerco il parametro di tale curva (0 < dParIn < 1) migliore per entrata
if ( GetParamForPtStartOnEdge( pCrv, pCompo, vOtherCrv, dParIn)) {
pCrv->GetPointD1D2( dParIn, ICurve::FROM_PLUS, ptMid) ;
PtrOwner<ICurveComposite> pCompoClone( CloneCurveComposite( pCompo)) ;
if( IsNull( pCompoClone))
return false ;
double dU ;
pCompoClone->GetParamAtPoint( ptMid, dU) ;
pCompoClone->ChangeStartPoint( dU) ;
pCompoClone->GetStartDir( vtMidOrt) ;
vtMidOrt.Rotate( vtExtr, 0, -1) ;
bFound = true ;
if ( nPriorityOpenEdge == 0)
return true ;
}
}
dLenPrev = dLen ;
}
}
else
dLenPrev = 0 ;
// vado alla successiva
pPrevCrv = pCrv ;
pCrv = ( bNextOk ? pNextCrv : nullptr) ;
}
return bFound ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AdjustContourWithOpenEdges( ICurveComposite* pCompo, ICRVCOMPOPOVECTOR& vCrvIsl,
double dTool_Diam, double dOffR, double dSideStep, const Vector3d& vtTrasl,
ISurfTriMesh* pStmRaw, bool bInVsOut)
{
// vettore estrusione
Vector3d vtExtr ; pCompo->GetExtrusion( vtExtr) ;
// calcolo riferimento nel piano della svuotatura
Frame3d frPocket ;
Point3d ptStart ; pCompo->GetStartPoint( ptStart) ;
frPocket.Set( ptStart, vtExtr) ;
// sposto l'inizio a metà del tratto più lungo
AdjustContourStart( pCompo, vCrvIsl) ;
// raggio di riferimento per offset
double dOutEdge = 0.5 * dTool_Diam ;
if ( m_Params.m_nSubType == POCKET_SUB_SPIRALIN || m_Params.m_nSubType == POCKET_SUB_ZIGZAG)
dOutEdge = max( dOutEdge, dTool_Diam - dSideStep) ;
double dRad = dOutEdge + dOffR ;
// estraggo parti con proprietà uniforme in un vettore
ICURVEPOVECTOR vpCrvs ;
int nCurrTempProp ;
int nParStart = 0 ;
for ( int i = 0 ; i < pCompo->GetCurveCount() ; ++ i) {
int nTempProp ;
pCompo->GetCurveTempProp( i, nTempProp) ;
if ( i == 0) {
nCurrTempProp = nTempProp ;
nParStart = i ;
}
else if ( nCurrTempProp != nTempProp) {
PtrOwner<ICurve> pCrv( pCompo->CopyParamRange( nParStart, i)) ;
if ( IsNull( pCrv))
return false ;
pCrv->SetTempProp( nCurrTempProp) ;
pCrv->SetExtrusion( vtExtr) ;
vpCrvs.emplace_back( Release( pCrv)) ;
nCurrTempProp = nTempProp ;
nParStart = i ;
}
}
PtrOwner<ICurve> pCrv( pCompo->CopyParamRange( nParStart, pCompo->GetCurveCount())) ;
if ( IsNull( pCrv))
return false ;
pCrv->SetTempProp( nCurrTempProp) ;
pCrv->SetExtrusion( vtExtr) ;
vpCrvs.emplace_back( Release( pCrv)) ;
// offsetto del raggio le curve aperte
for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) {
if ( vpCrvs[i]->GetTempProp() == 1) {
OffsetCurve OffsCrv ;
if ( ! OffsCrv.Make( vpCrvs[i], dRad, ICurve::OFF_FILLET)) {
m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ;
return false ;
}
int nCrv_offs = OffsCrv.GetCurveCount() ;
if ( nCrv_offs == 0) {
// se un lato aperto è formato da più curve e l'offset di tale composita sparisce, la superficie può
// estendersi fino all'intersezione delle due curva ad amo che determinano l'immagine del tool nello svuotare
// i lati chiusi adiacenti
if ( i == 0)
continue ;
// determino la curva ad amo
Point3d ptEnd ; vpCrvs[i-1]->GetEndPoint( ptEnd) ;
Vector3d vtTg ; vpCrvs[i-1]->GetEndDir( vtTg) ;
Vector3d vtOrt = vtTg ; vtOrt.Rotate( vtExtr, 0, 1) ;
Point3d ptArc = ptEnd + ( 1.05 * dTool_Diam + 2 * dOffR ) * vtOrt ;
PtrOwner<ICurveArc> pCrvArc( CreateCurveArc()) ;
if ( IsNull( pCrvArc))
return false ;
pCrvArc->SetExtrusion( vtExtr) ;
pCrvArc->Set2PVN( ptEnd, ptArc, vtTg, vtExtr) ;
PtrOwner<ICurveComposite> pJCrv( CreateCurveComposite()) ;
if ( IsNull( pJCrv))
return false ;
pJCrv->AddCurve( Release( pCrvArc)) ;
// determino la curva ad amo
vpCrvs[i+1]->GetStartPoint( ptStart) ;
vpCrvs[i+1]->GetStartDir( vtTg) ;
vtOrt = vtTg ; vtOrt.Rotate( vtExtr, 0, 1) ;
ptArc = ptStart + ( 1.05 * dTool_Diam + 2 * dOffR ) * vtOrt ;
Point3d ptLine = ptArc + 5 * ( 1.05 * dTool_Diam + 2 * dOffR ) * vtTg ;
PtrOwner<ICurveComposite> pJCrv1( CreateCurveComposite()) ;
if ( IsNull( pJCrv1))
return false ;
pJCrv1->SetExtrusion( vtExtr) ;
pJCrv1->AddPoint( ptLine) ;
pJCrv1->AddLine( ptArc) ;
pJCrv1->AddArcTg( ptStart) ;
//int PURp = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pJCrv1->Clone()) ;
//m_pGeomDB->SetMaterial( PURp, PURPLE) ;
// intersezione
pJCrv->ToLoc( frPocket) ;
pJCrv1->ToLoc( frPocket) ;
IntersCurveCurve intCC( *pJCrv, *pJCrv1) ;
pJCrv->ToGlob( frPocket) ;
pJCrv1->ToGlob( frPocket) ;
// classificazione
IntCrvCrvInfo aInfo ;
if ( intCC.GetIntersCount() > 0) {
if ( intCC.GetIntCrvCrvInfo( 0, aInfo)) {
PtrOwner<ICurveComposite> pCrvFinal( CreateCurveComposite()) ;
PtrOwner<ICurve> PJ_Cut( pJCrv->CopyParamRange( 0, aInfo.IciA[0].dU)) ;
PtrOwner<ICurve> PJ1_Cut( pJCrv1->CopyParamRange( aInfo.IciB[0].dU, 1)) ;
//PJ1_Cut->Invert() ;
pCrvFinal->AddCurve( Release( PJ_Cut)) ;
pCrvFinal->AddCurve( Release( PJ1_Cut)) ;
for ( int u = 0 ; u < pCrvFinal->GetCurveCount() ; ++ u)
pCrvFinal->SetCurveTempProp( u, 0, 0) ;
vpCrvs[i].Set( Release( pCrvFinal)) ;
vpCrvs[i]->SetTempProp( 0) ;
}
}
else
continue ;
}
// dall'offset di un lato aperto posso generare più curva composite...
PtrOwner<ICurve> pCrvlonger( OffsCrv.GetLongerCurve()) ;
while ( ! IsNull( pCrvlonger)) {
// le chiuse mi entrano nel vettore delle isole
if ( pCrvlonger->IsClosed() && nCrv_offs > 1) {
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
pCrvCompo->AddCurve( Release( pCrvlonger)) ;
for ( int u = 0 ; u < pCrvCompo->GetCurveCount() ; ++ u)
pCrvCompo->SetCurveTempProp( u, 1, 0) ;
vCrvIsl.emplace_back( pCrvCompo->Clone()) ;
}
else // le aperte rimangono tali
vpCrvs[i].Set( Release( pCrvlonger)) ;
pCrvlonger.Set( OffsCrv.GetLongerCurve()) ;
}
// imposto le curva ottenute come aperte ( nuove isole comprese)
PtrOwner<ICurveComposite> pCrvRange( CreateCurveComposite()) ;
pCrvRange->AddCurve( vpCrvs[i]->Clone()) ;
for ( int j = 0 ; j < pCrvRange->GetCurveCount() ; ++ j)
pCrvRange->SetCurveTempProp( j, 1, 0) ;
vpCrvs[i].Set( pCrvRange) ;
vpCrvs[i]->SetTempProp( 1) ;
}
}
// clono la pCompo
PtrOwner<ICurveComposite> pCompo_clone( CloneCurveComposite( pCompo)) ;
// reinserisco le curve, chiudendo eventuali gap
pCompo->Clear() ;
pCompo->SetExtrusion( vtExtr) ;
bool bOpenCurr = false ;
double dDiam = 1.05 * dTool_Diam + 2 * dOffR ;
for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) {
// stato curve
bool bOpenPrev = bOpenCurr ;
bOpenCurr = ( vpCrvs[i]->GetTempProp() != 0) ;
PtrOwner<ICurve> pCrv_Check( vpCrvs[i]->Clone()) ;
// chiudo eventuale gap
if ( i > 0) {
Point3d ptEnd ; pCompo->GetEndPoint( ptEnd) ;
Point3d ptStart ; vpCrvs[i]->GetStartPoint( ptStart) ;
if ( ! AreSamePointEpsilon( ptEnd, ptStart, 10 * EPS_SMALL)) {
// se passo da chiuso ad aperto
if ( ! bOpenPrev && bOpenCurr) {
// -----------------------------------------------------------------------------------
// creazione della curva di bordo mediante Offset dei chiusi ( per ripulire angoli stretti)
PtrOwner<ICurveComposite> pCrvCompo_i( CreateCurveComposite()) ;
pCrvCompo_i->AddCurve( vpCrvs[i]->Clone()) ;
Point3d ptS ; pCompo->GetEndPoint( ptS) ;
Point3d ptE ; vpCrvs[i+1]->GetStartPoint( ptE) ;
PtrOwner<ICurveComposite> pCrvNew( CreateCurveComposite()) ;
if ( ! bInVsOut &&
AdjustPathOutsideRawForOpenEdges( pCompo_clone, vCrvIsl, pCrvCompo_i, ptS, ptE, dRad, dDiam,
pCrvNew, vtTrasl, pStmRaw, bInVsOut)) {
vpCrvs[i].Set( Release( pCrvNew)) ;
vpCrvs[i]->GetStartPoint( ptStart) ;
}
// -----------------------------------------------------------------------------------
// determino la curva ad amo
Vector3d vtTg ; pCompo->GetEndDir( vtTg) ;
Vector3d vtOrt = vtTg ; vtOrt.Rotate( vtExtr, 0, 1) ;
Point3d ptArc = ptEnd + dDiam * vtOrt ;
//Point3d ptLine = ptArc - 5 * dDiam * vtTg ;
PtrOwner<ICurveArc> pCrvArc( CreateCurveArc()) ;
if ( IsNull( pCrvArc))
return false ;
pCrvArc->SetExtrusion( vtExtr) ;
pCrvArc->Set2PVN( ptEnd, ptArc, vtTg, vtExtr) ;
PtrOwner<ICurveComposite> pJCrv( CreateCurveComposite()) ;
if ( IsNull( pJCrv))
return false ;
pJCrv->AddCurve( Release( pCrvArc)) ;
// assegno alle sue sottocurve la proprietà di curva aperta
for ( int u = 0 ; u < pJCrv->GetCurveCount() ; ++ u)
pJCrv->SetCurveTempProp( u, 1, 0) ;
// ------- controllo degli overlap tra la curva ad amo e la nuova curva di lato aperto ottenuta ------
bool bSucc = false ;
PtrOwner<ICurveComposite> pNewCrv( CreateCurveComposite()) ;
PtrOwner<ICurveComposite> pCrvOffsOri( CreateCurveComposite()) ;
pCrvOffsOri->AddCurve( vpCrvs[i]->Clone()) ;
if ( ! CheckOpenEdgeOverlapParts( pJCrv, vpCrvs[i], true, bSucc, pNewCrv))
return false ;
if ( bSucc)// se "overlap Trovato", modifico la vpCrvs[i]
vpCrvs[i].Set( Release( pNewCrv)) ;
// ---------------------------------------------------------------------------------------------------
// calcolo l'intersezione nel piano della svuotatura dell'amo con la curva aperta
pJCrv->ToLoc( frPocket) ;
vpCrvs[i]->ToLoc( frPocket) ;
IntersCurveCurve intCC( *pJCrv, *vpCrvs[i]) ;
pJCrv->ToGlob( frPocket) ;
vpCrvs[i]->ToGlob( frPocket) ;
// taglio opportunamente le curve
bool bFound = false ;
IntCrvCrvInfo aInfo ;
if ( intCC.GetIntersCount() > 0 && !bInVsOut) {
// cerco la prima intersezione che entra nella curva aperta
for ( int j = 0 ; j < intCC.GetIntersCount() ; ++ j) {
if ( intCC.GetIntCrvCrvInfo( j, aInfo) && ( bSucc || aInfo.IciA[0].nPrevTy == ICCT_OUT)) {
bFound = true ;
break ;
}
}
}
if ( bFound) {
if ( ! pJCrv->TrimEndAtParam( aInfo.IciA[0].dU))
pJCrv->Clear() ;
vpCrvs[i]->TrimStartAtParam( aInfo.IciB[0].dU) ;
pCompo->AddCurve( ::Release( pJCrv), true, 10 * EPS_SMALL) ;
}
else {
vpCrvs[i].Set( Release( pCrvOffsOri)) ;
pCompo->AddLine( ptStart) ;
pCompo->SetCurveTempProp( pCompo->GetCurveCount() - 1, bInVsOut ? 0 : 1, 0) ; // segmento aggiunto
if ( bInVsOut)
pCompo->SetCurveTempProp( pCompo->GetCurveCount() - 1, -99 , 1) ; // linea da controllare
}
}
// se passo da aperto a chiuso
else if ( bOpenPrev && ! bOpenCurr) {
// determino la curva ad amo
Vector3d vtTg ; vpCrvs[i]->GetStartDir( vtTg) ;
Vector3d vtOrt = vtTg ; vtOrt.Rotate( vtExtr, 0, 1) ;
Point3d ptArc = ptStart + dDiam * vtOrt ;
Point3d ptLine = ptArc + 5 * dDiam * vtTg ;
PtrOwner<ICurveComposite> pJCrv( CreateCurveComposite()) ;
if ( IsNull( pJCrv))
return false ;
pJCrv->SetExtrusion( vtExtr) ;
pJCrv->AddPoint( ptLine) ;
pJCrv->AddLine( ptArc) ;
pJCrv->AddArcTg( ptStart) ;
PtrOwner<ICurve> pCrvRemoved( pJCrv->RemoveFirstOrLastCurve( false)) ;
if ( IsNull( pCrvRemoved))
return false ;
// assegno alle sue sottocurve la proprietà di curva aperta
for ( int u = 0 ; u < pJCrv->GetCurveCount() ; ++ u)
pJCrv->SetCurveTempProp( u, 1, 0) ;
// prendo le ultime due curve ( sono sufficienti) della composita attuale per verificare l'intersezione
// con la curva ad amo
PtrOwner<ICurveComposite> pLCrv( CreateCurveComposite()) ;
if ( IsNull( pLCrv))
return false ;
pLCrv->AddCurve( pCompo->GetLastCurve()->Clone()) ;
if ( pCompo->GetCurveCount() >= 2)
pLCrv->AddCurve( pCompo->GetPrevCurve()->Clone(), false) ;
double dUL = pLCrv->GetCurveCount() ;
// ------- controllo degli overlap tra la curva ad amo e la nuova curva di lato aperto ottenuta ------
bool bSucc = false ;
PtrOwner<ICurveComposite> pNewCrv( CreateCurveComposite()) ;
PtrOwner<ICurveComposite> pCrvOffsOri( CreateCurveComposite()) ;
pCrvOffsOri->AddCurve( vpCrvs[i]->Clone()) ;
if ( ! CheckOpenEdgeOverlapParts( pJCrv, pLCrv, false, bSucc, pNewCrv))
return false ;
if ( bSucc) { // se "overlap Trovato", modifico la vpCrvs[i]
pLCrv.Set( pNewCrv->Clone()) ;
double dUS_tmp, dUE_tmp ;
pCompo->GetDomain( dUS_tmp, dUE_tmp) ;
if ( dUE_tmp >= 2) { // sempre ( ho sempre un pezzo di chiuso e il tratto aperto)
pCompo->TrimEndAtParam( dUE_tmp - dUL) ;
pCompo->AddCurve( pLCrv->Clone()) ;
}
}
dUL = pLCrv->GetCurveCount() ;
// ---------------------------------------------------------------------------------------------------
// calcolo l'intersezione nel piano della svuotatura dell'amo con la curva aperta
pJCrv->ToLoc( frPocket) ;
pLCrv->ToLoc( frPocket) ;
IntersCurveCurve intCC( *pJCrv, *pLCrv) ;
pJCrv->ToGlob( frPocket) ;
pLCrv->ToGlob( frPocket) ;
// taglio opportunamente le curve
IntCrvCrvInfo aInfo ;
if ( intCC.GetIntCrvCrvInfo( 0, aInfo) && !bInVsOut) {
double dUs, dUe ; pCompo->GetDomain( dUs, dUe) ;
if ( ! pCompo->TrimEndAtParam( dUe - dUL + aInfo.IciB[0].dU))
pCompo->Clear() ;
if ( ! pJCrv->TrimStartAtParam( aInfo.IciA[0].dU))
pJCrv->Clear() ;
pCompo->AddCurve( ::Release( pJCrv), true, 10 * EPS_SMALL) ;
}
else {
vpCrvs[i].Set( Release( pCrvOffsOri)) ;
pCompo->AddLine( ptStart) ;
pCompo->SetCurveTempProp( pCompo->GetCurveCount() - 1, bInVsOut ? 0 : 1, 0) ; // segmento come curva aperta
if ( bInVsOut)
pCompo->SetCurveTempProp( pCompo->GetCurveCount() - 1, -99 , 1) ; // linea da controllare
}
}
else {
vpCrvs[i].Set( Release( pCrv_Check)) ;
pCompo->AddLine( ptStart) ;
pCompo->SetCurveTempProp( pCompo->GetCurveCount() - 1, 1, 0) ; // segmento come curva aperta
if ( bInVsOut)
pCompo->SetCurveTempProp( pCompo->GetCurveCount() - 1, -99 , 1) ; // linea da controllare
}
}
}
// aggiungo la curva
pCompo->AddCurve( ::Release( vpCrvs[i]), true, 10 * EPS_SMALL) ;
// NB. Se ho solo una curva esterna e all'interno ho almeno un'isola chiusa più vicina del raggio del tool,
// non andrò mai a creare regioni di incidenza, quindi genererei 0 o più chunks dove il Tool non riesce a passare...
if ( i == 0 && ( int)vpCrvs.size() > 0 && ( int)vCrvIsl.size() > 0) {
Point3d ptS ; pCompo->GetEndPoint( ptS) ;
Point3d ptE ; pCompo->GetStartPoint( ptE) ;
bool bIsAllOpen = true ;
for ( int u = 0 ; u < pCompo->GetCurveCount() && bIsAllOpen ; ++ u) {
int nP = 0 ;
if ( pCompo->GetCurveTempProp( u, nP, 0) && nP == 0)
bIsAllOpen = false ;
}
if ( bIsAllOpen) {
PtrOwner<ICurveComposite> pCrvNew( CreateCurveComposite()) ;
if ( ! bInVsOut &&
AdjustPathOutsideRawForOpenEdges( pCompo_clone, vCrvIsl, pCompo, ptS, ptE, dRad, dDiam,
pCrvNew, vtTrasl, pStmRaw, !bInVsOut)) {
pCompo->Clear() ;
pCompo->CopyFrom( pCrvNew) ;
}
}
}
}
// non dovrebbe esserci un gap, ma meglio prevenire problemi
pCompo->Close() ;
return true ;
}
bool
Pocketing::CheckOpenEdgeOverlapParts( const ICurve* pCrvJ, const ICurve* pCrvOffBorder, bool bCloseToOpen, bool& bSucc,
ICurveComposite* pCrvFinal)
{
// controllo validità dei parametri
if ( pCrvJ == nullptr || ! pCrvJ->IsValid() ||
pCrvOffBorder == nullptr || ! pCrvOffBorder->IsValid() ||
pCrvFinal == nullptr )
return false ;
bSucc = false ;
pCrvFinal->Clear() ;
// converto la curva ad amo in curva composita
PtrOwner<ICurveComposite> pCrvJ_Cut( ConvertCurveToComposite( pCrvJ->Clone())) ;
if ( IsNull( pCrvJ_Cut) || ! pCrvJ_Cut->IsValid() || pCrvJ_Cut->GetCurveCount() == 0)
return false ;
// parametri per taglio
double dUTrim = EPS_SMALL ;
Point3d ptCut, ptBase ;
// se passo da chiuso ad aperto
if ( bCloseToOpen) {
pCrvOffBorder->GetStartPoint( ptCut) ; // punto di Trim
DistPointCurve DistPC( ptCut, *pCrvJ_Cut, true) ;
double dDist = INFINITO ;
// se distante esco...
if ( ! DistPC.GetDist( dDist) || dDist > 200 * EPS_SMALL)
return true ;
// dato che il punto è molto vicino...
if ( pCrvJ_Cut->GetParamAtPoint( ptCut, dUTrim, 200 * EPS_SMALL)) {
// cerco il parametro sulla curva J e taglio la parte finale
if ( ! pCrvJ_Cut->TrimEndAtParam( dUTrim))
return true ;
// punto finale della curva J ottenuta
pCrvJ_Cut->GetEndPoint( ptBase) ;
// ricavo il nuovo bordo esterno presso il lato aperto corrente
// ( estendendolo all'inizio per trovare l'intersezione)
if ( pCrvFinal->AddPoint( ptBase) &&
pCrvFinal->AddLine( ptCut) &&
pCrvFinal->ExtendStartByLen( 10) &&
pCrvFinal->AddCurve( pCrvOffBorder->Clone())) {
bSucc = true ;
}
}
}
// se passo da aperto a chiuso
else {
pCrvOffBorder->GetEndPoint( ptCut) ; // punto di Trim
DistPointCurve DistPC( ptCut, *pCrvJ_Cut, true) ;
double dDist = INFINITO ;
// se distante esco...
if ( ! DistPC.GetDist( dDist) || dDist > 200 * EPS_SMALL)
return true ;
// dato che il punto è molto vicino...
if ( pCrvJ_Cut->GetParamAtPoint( ptCut, dUTrim, 200 * EPS_SMALL)) {
// cerco il parametro sulla curva J e taglio la parte iniziale
if ( ! pCrvJ_Cut->TrimStartAtParam( dUTrim))
return true ;
// punto iniziale della curva J ottenuta
pCrvJ_Cut->GetStartPoint( ptBase) ;
// ricavo il nuovo bordo esterno presso il lato aperto corrente
// ( estendendolo alla fine per trovare l'intersezione)
if ( pCrvFinal->AddCurve( pCrvOffBorder->Clone()) &&
pCrvFinal->AddLine( ptBase) &&
pCrvFinal->ExtendEndByLen( 10))
bSucc = true ;
}
}
// controllo che tutto sia andato a buon fine, altrimenti esco
if ( bSucc == false)
return true ;
// assegno le proprietà :
// thickness
double dThick = pCrvOffBorder->GetThickness( dThick) ;
pCrvFinal->SetThickness( dThick) ;
// estrusione
Vector3d vtExtr ; pCrvOffBorder->GetExtrusion( vtExtr) ;
pCrvFinal->SetExtrusion( vtExtr) ;
// TmpProp0 + TmpProp1
int nProp0 = pCrvOffBorder->GetTempProp( 0) ;
pCrvFinal->SetTempProp( nProp0, 0) ;
int nProp1 = pCrvOffBorder->GetTempProp( 1) ;
pCrvFinal->SetTempProp( nProp1, 1) ;
// Proprietà di sottocurve aperte
for ( int u = 0 ; u < pCrvFinal->GetCurveCount() ; ++ u)
pCrvFinal->SetCurveTempProp( u, 1, 0) ; // sottocurve tutte aperte
return true ;
}
//---------------------------------------------------------------------------
bool
Pocketing::AdustTmpPropLinesForProjection( ICurveComposite* pCompo)
{
// controllo dei parametri
if ( pCompo == nullptr || ! pCompo->IsValid() || ! pCompo->IsClosed())
return false ;
// scorro la curva cercando tutti i tratti lineare con tmpProp 1 impostata a -99
for ( int u = 0 ; u < pCompo->GetCurveCount() ; ++ u) {
const ICurve* pCrv_u = pCompo->GetCurve( u) ;
if ( pCrv_u == nullptr)
return false ;
if ( pCrv_u->GetType() == CRV_LINE && pCrv_u->GetTempProp( 1) == -99) {
const ICurve* pCrv_prec = pCompo->GetCurve( u == 0 ? pCompo->GetCurveCount() - 1 : u) ;
if ( pCrv_prec == nullptr)
return false ;
pCompo->SetCurveTempProp( u, pCrv_prec->GetTempProp( 0), 0) ;
}
}
return pCompo->IsValid() && pCompo->IsClosed() ;
}
//---------------------------------------------------------------------------
bool
Pocketing::AdjustPathOutsideRawForOpenEdges( const ICurveComposite* pCompo, const ICRVCOMPOPOVECTOR& vCrvIsland,
ICurveComposite* pCrvOpenOffs, const Point3d& ptCrvOpenS,
const Point3d& ptCrvOpenE, const double dRad,
const double dDiam, ICurveComposite* pNewCrv, const Vector3d& vtTrasl,
ISurfTriMesh* pStmRaw, bool bInVsOut)
{
// controllo la validtà dei parametri
if ( pCompo == nullptr || ! pCompo->IsValid() || pCompo->GetCurveCount() == 0 ||
pCrvOpenOffs == nullptr || ! pCrvOpenOffs->IsValid() || pCrvOpenOffs->GetCurveCount() == 0)
return false ;
// recupero l'estrusione della curva di bordo
Vector3d vtExtr ; pCompo->GetExtrusion( vtExtr) ;
// -------------- RECUPERO DELLA CURVA ESTERNA PRIMA E DOPO IL LATO APERTO CORRENTE --------------
double dUTrimS, dUTrimE ;
PtrOwner<ICurveComposite> pCompo_Prec( CloneCurveComposite( pCompo)) ;
PtrOwner<ICurveComposite> pCompo_Succ( CloneCurveComposite( pCompo)) ;
PtrOwner<ICurveComposite> pCrvOpen( CloneCurveComposite( pCompo)) ;
if ( ! AreSamePointApprox( ptCrvOpenS, ptCrvOpenE)) {
// se inizio e fine diversi...
pCompo_Prec->GetParamAtPoint( ptCrvOpenS, dUTrimS) ;
if ( ! pCompo_Prec->TrimEndAtParam( dUTrimS))
pCompo_Prec->Clear() ;
pCompo_Succ->GetParamAtPoint( ptCrvOpenE, dUTrimE) ;
if ( ! pCompo_Succ->TrimStartAtParam( dUTrimE))
pCompo_Succ->Clear() ;
if ( ! pCrvOpen->TrimStartEndAtParam( dUTrimS, dUTrimE))
pCrvOpen->Clear() ;
}
else {
// se l'inizio coincide con la fine, allora la curva è tutta aperta
pCrvOpen.Set( pCompo->Clone()) ;
pCompo_Prec->Clear() ;
pCompo_Succ->Clear() ;
}
PtrOwner<ICurveComposite> pCompo_noOpenCrv( CloneCurveComposite( pCompo_Succ)) ;
pCompo_noOpenCrv->AddCurve( pCompo_Prec->Clone()) ;
// recupero i punti e i vettori tangenti iniziali e finali del lato aperto
Point3d ptSTART ; pCrvOpenOffs->GetStartPoint( ptSTART) ;
Point3d ptEND ; pCrvOpenOffs->GetEndPoint( ptEND) ;
Vector3d vtSTART ; pCrvOpenOffs->GetStartDir( vtSTART) ;
Vector3d vtEND ; pCrvOpenOffs->GetEndDir( vtEND) ;
// -------------- CREAZIONE DELLA REGIONE DI INFLUENZA --------------
// 1) Creo una copia della curva
PtrOwner<ICurveComposite> pCrvOpen_clone( CloneCurveComposite( pCrvOpen)) ;
if ( IsNull( pCrvOpen_clone) || ! pCrvOpen_clone->IsValid())
return false ;
// 2) Controllo la lunghezza della curva
double dLen ;
if ( ! pCrvOpen_clone->GetLength( dLen) || dLen < dDiam + EPS_SMALL)
return false ;
// 3) Accorcio l'inizio e la fine del raggio dell'utensile
double dUS, dUE ;
pCrvOpen_clone->GetParamAtLength( dRad, dUS) ;
pCrvOpen_clone->GetParamAtLength( dLen - dRad, dUE) ;
if ( ! pCrvOpen_clone->TrimStartEndAtParam( dUS, dUE))
pCrvOpen->Clear() ;
bool bOk = true ;
// 4) Creo regione squadrata da questa curva
PtrOwner<ISurfFlatRegion> pSfrInc( GetSurfFlatRegionFromFatCurve( Release( pCrvOpen_clone), dRad , true, false)) ;
if ( IsNull( pSfrInc) || ! pSfrInc->IsValid()) {
Point3d ptE ;
pCrvOpenOffs->GetEndPoint( ptE) ;
PtrOwner<ICurveComposite> pCrv_CompoHelp( CreateCurveComposite()) ;
pCrv_CompoHelp->AddCurve( pCrvOpen->Clone()) ;
pCrv_CompoHelp->AddLine( ptE) ;
PtrOwner<ICurveComposite> pCrvOpenOffs_Clone( CloneCurveComposite( pCrvOpenOffs)) ;
pCrvOpenOffs_Clone->Invert() ;
pCrv_CompoHelp->AddCurve( Release( pCrvOpenOffs_Clone)) ;
pCrvOpen->GetStartPoint( ptE) ;
pCrv_CompoHelp->AddLine( ptE) ;
pSfrInc.Set( CreateSurfFlatRegion()) ;
pSfrInc->AddExtLoop( Release( pCrv_CompoHelp)) ;
bOk = false ;
if ( IsNull( pSfrInc) || ! pSfrInc->IsValid())
return false ;
}
// -------------- AGGIORNAMENTO DELLA REGIONE DI INFLUENZA --------------
// creo un vettore con la pCompo senza lato aperto e le isole contenute al suo interno
ICRVCOMPOPOVECTOR vCrvToCheck ;
vCrvToCheck.emplace_back( pCompo_noOpenCrv->Clone()) ; // la curva esterna in prima posizione
for ( int i = 0 ; i < ( int)vCrvIsland.size() ; ++ i)
vCrvToCheck.emplace_back( vCrvIsland[i]->Clone()) ;
// scorro il vettore creato...
for ( int c = 0 ; c < ( int)vCrvToCheck.size() ; ++ c) {
// 1) recupero la curva corrente
PtrOwner<ICurveComposite> pCrvCurr( CloneCurveComposite( vCrvToCheck[c])) ;
if ( IsNull( pCrvCurr) || ! pCrvCurr->IsValid())
continue ;
CRVCVECTOR ccClass ;
if ( pSfrInc->GetCurveClassification( *pCrvCurr, EPS_SMALL, ccClass)) {
for ( int i = 0 ; i < ( int)ccClass.size() ; ++ i) {
if ( ccClass[i].nClass == CRVC_IN) {
// 2) Trovo il tratto di curva interno
PtrOwner<ICurveComposite> pCrvCurrPartIn_( CloneCurveComposite( pCrvCurr)) ;
if ( IsNull( pCrvCurr) || ! pCrvCurr->IsValid())
return false ;
if ( ! pCrvCurrPartIn_->TrimStartEndAtParam( ccClass[i].dParS, ccClass[i].dParE))
pCrvCurrPartIn_->Clear() ;
if ( IsNull( pCrvCurrPartIn_) || ! pCrvCurrPartIn_->IsValid())
continue ;
// Cerco solo i tratti di curva che sono chiusi
ICURVEPOVECTOR vCrvOpen, vCrvClose ;
if ( ! GetHomogeneousParts( pCrvCurrPartIn_, vCrvOpen, vCrvClose))
return false ;
for ( int t_Open = 0 ; t_Open < ( int)vCrvClose.size() ; ++ t_Open) {
PtrOwner<ICurveComposite> pCrvCurrPartIn( CreateCurveComposite()) ;
pCrvCurrPartIn->AddCurve( vCrvClose[t_Open]->Clone()) ;
if ( IsNull( pCrvCurrPartIn) || ! pCrvCurrPartIn->IsValid())
continue ;
pCrvCurrPartIn->SetExtrusion( vtExtr) ;
PtrOwner<ICurveComposite> pCrvCurrPartIn_Clone( CloneCurveComposite( pCrvCurrPartIn)) ;
if ( IsNull( pCrvCurrPartIn_Clone) || ! pCrvCurrPartIn_Clone->IsValid())
continue ;
// 3) ricavo il punto iniziale e il punto finale, assieme ai vettori tangenti
Point3d ptS1 ; pCrvCurrPartIn->GetStartPoint( ptS1) ;
Point3d ptE1 ; pCrvCurrPartIn->GetEndPoint( ptE1) ;
Vector3d vtS1 ; pCrvCurrPartIn->GetStartDir( vtS1) ;
Vector3d vtE1 ; pCrvCurrPartIn->GetEndDir( vtE1) ;
// 4) effettuo l'Offset della curva del diametro del tool
OffsetCurve OffsCrv ;
if ( ! OffsCrv.Make( pCrvCurrPartIn_Clone, - dDiam, ICurve::OFF_FILLET)) {
m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ;
return false ;
}
// 5) scorro tutte le curve di Offset che si sono formate, prendendo sempre la più lunga tra le rimanenti
PtrOwner<ICurve> pOffLongestCrv( OffsCrv.GetLongerCurve()) ;
while ( ! IsNull( pOffLongestCrv)) {
// 6) escludo le curve che si chiudono su se stesse dopo l'Offset
if ( ! pOffLongestCrv->IsClosed()) {
// 7) trasformo la curva in composita
PtrOwner<ICurveComposite> pCompoPartInOffs( CreateCurveComposite()) ;
pCompoPartInOffs->AddCurve( pOffLongestCrv->Clone()) ;
// 8) creo due archi che collegano i punti iniziali e finali della curva originale e di quella con offset
PtrOwner<ICurveArc> pArcS( CreateCurveArc()) ;
PtrOwner<ICurveArc> pArcE( CreateCurveArc()) ;
if ( IsNull( pArcS) || IsNull( pArcE))
return false ;
Point3d ptS2 ; pCompoPartInOffs->GetStartPoint( ptS2) ;
Point3d ptE2 ; pCompoPartInOffs->GetEndPoint( ptE2) ;
Vector3d vtS2 ; pCompoPartInOffs->GetStartDir( vtS2) ;
Vector3d vtE2 ; pCompoPartInOffs->GetEndDir( vtE2) ;
pArcS->Set2PVN( ptS1, ptS2, - vtS1, - vtExtr) ;
pArcE->Set2PVN( ptE2, ptE1, vtE2, - vtExtr) ;
// 9) creo il loop esterno della regione da aggiungere
PtrOwner<ICurveComposite> pCrvExtBorder( CreateCurveComposite()) ;
if ( IsNull( pCrvExtBorder))
return false ;
pCrvExtBorder->AddCurve( Release( pArcS)) ; // primo tratto lineare
pCrvExtBorder->AddCurve( Release( pCompoPartInOffs)) ; // tratto di offset
pCrvExtBorder->AddCurve( Release( pArcE)) ; // secondo tratto lineare
pCrvCurrPartIn->Invert() ; // inversione del tratto interno
pCrvExtBorder->AddCurve( pCrvCurrPartIn->Clone()) ; // aggiunta del tratto interno
if ( pCrvExtBorder->IsClosed()) {
// 9) Creo la nuova regione da aggiungere a quella di influenza
PtrOwner<ISurfFlatRegion> pSfrExpan( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrExpan))
return false ;
pSfrExpan->AddExtLoop( Release( pCrvExtBorder)) ;
if ( pSfrExpan->IsValid()) {
if ( AreOppositeVectorApprox( pSfrExpan->GetNormVersor(), vtExtr))
pSfrExpan->Invert() ;
// ----------- AGGIORNAMENTO DELLA REGIONE DI INFLUENZA ----------
PtrOwner<ISurfFlatRegion> pSfrInc_c( CloneSurfFlatRegion( pSfrInc)) ;
if ( IsNull( pSfrInc_c))
return false ;
if ( pSfrInc_c->Subtract( *pSfrExpan)) {
pSfrInc->Clear() ;
for ( int cc = 0 ; cc < pSfrInc_c->GetChunkCount() ; ++ cc) {
CRVCVECTOR ccClass_cc ;
PtrOwner<ISurfFlatRegion> pSfrChunk_cc( pSfrInc_c->CloneChunk( cc)) ;
if ( pSfrChunk_cc->GetCurveClassification( *pCrvOpen, EPS_SMALL, ccClass_cc)) {
for ( int jj = 0 ; jj < ( int)ccClass_cc.size() ; ++ jj) {
if ( ccClass_cc[jj].nClass == CRVC_IN) {
if ( IsNull( pSfrInc) || ! pSfrInc->IsValid())
pSfrInc.Set( pSfrChunk_cc->Clone()) ;
else
pSfrInc->Add( *pSfrChunk_cc) ;
break ;
}
}
}
}
}
pSfrInc->Add( *pSfrExpan) ;
}
}
}
pOffLongestCrv.Set( OffsCrv.GetLongerCurve()) ;
}
}
}
}
}
else
return false ;
}
// recupero il Grezzo e sottraggo tutto ciò che sta nella regione
if ( pStmRaw != nullptr) {
bool bIsChanged ;
if ( m_bIntersRaw) {
PtrOwner<ISurfFlatRegion> pSrfInc_Copy( CloneSurfFlatRegion( pSfrInc)) ;
int nChunkBef = pSfrInc->GetChunkCount() ;
if ( ! IntersSurfWithRaw( pSfrInc, pStmRaw, 1.01 * vtTrasl, bIsChanged, 1500 * EPS_SMALL, bInVsOut, false, false))
return false ;
if ( IsNull( pSfrInc) || ! pSfrInc->IsValid() || pSfrInc->GetChunkCount() == 0 ||
( nChunkBef < pSfrInc->GetChunkCount()))
pSfrInc.Set( pSrfInc_Copy) ;
}
}
if ( IsNull( pSfrInc) || ! pSfrInc->IsValid())
return false ;
// RECUPERO DELLA CURVA DI BORDO ESTERNA DA AGGIUNGERE ALLA SVUOTATURA
PtrOwner<ICurveComposite> pCrvNewBorder( GetCurveComposite( pSfrInc->GetLoop( 0, 0))) ;
if ( IsNull( pCrvNewBorder))
return false ;
if ( ! AreSamePointApprox( ptCrvOpenE, ptCrvOpenS)) {
double dUSTART ;
if ( ! pCrvNewBorder->GetParamAtPoint( ptSTART, dUSTART, 5000 * EPS_SMALL)) {
int nFlag ;
if ( ! DistPointCurve( ptSTART, *pCrvNewBorder).GetParamAtMinDistPoint( 0, dUSTART, nFlag))
return false ;
}
pCrvNewBorder->ChangeStartPoint( dUSTART) ;
double dUEND ;
if ( ! pCrvNewBorder->GetParamAtPoint( ptEND, dUEND, 5000 * EPS_SMALL)) {
int nFlag ;
if ( ! DistPointCurve( ptEND, *pCrvNewBorder).GetParamAtMinDistPoint( 0, dUEND, nFlag))
return false ;
}
if ( ! pCrvNewBorder->TrimEndAtParam( dUEND))
pCrvNewBorder->Clear() ;
}
pNewCrv->Clear() ;
pNewCrv->AddCurve( Release( pCrvNewBorder)) ;
for ( int u = 0 ; u < pNewCrv->GetCurveCount() ; ++ u)
pNewCrv->SetCurveTempProp( u, 1, 0) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AdjustContourStart( ICurveComposite* pCompo, const ICRVCOMPOPOVECTOR& vCrvIsl, bool bOrder)
{
// se cerco semplicemente il tratto lineare chiuso più lungo ...
if ( ! bOrder) {
// cerco il tratto lineare più lungo che non sia aperto
int i = 0 ;
int nMax = - 1 ;
double dLenMax = 0 ;
const ICurve* pCrv = pCompo->GetFirstCurve() ;
while ( pCrv != nullptr) {
double dLen ;
if ( pCrv->GetType() == CRV_LINE && pCrv->GetTempProp() == 0 && pCrv->GetLength( dLen) && dLen > dLenMax) {
dLenMax = dLen ;
nMax = i ;
}
++ i ;
pCrv = pCompo->GetNextCurve() ;
}
// se non trovato o troppo corto, cerco il tratto generico più lungo
if ( nMax < 0 || dLenMax < 2 * m_TParams.m_dDiam) {
i = 0 ;
pCrv = pCompo->GetFirstCurve() ;
while ( pCrv != nullptr) {
double dLen ;
if ( pCrv->GetType() != CRV_LINE && pCrv->GetTempProp() == 0 && pCrv->GetLength( dLen) && dLen > dLenMax) {
dLenMax = dLen ;
nMax = i ;
}
++ i ;
pCrv = pCompo->GetNextCurve() ;
}
}
const ICurve* pCrvClone( pCompo->GetCurve( nMax)) ;
double dPar ;
if ( GetParamForPtStartOnEdge( pCrvClone, pCompo, vCrvIsl, dPar))
pCompo->ChangeStartPoint( nMax + dPar) ;
else
// sposto inizio a metà
if ( nMax >= 0)
pCompo->ChangeStartPoint( nMax + 0.5) ;
}
// se invece sto cercando di entrare da un lato chiuso per una svuotatura, allora riordino i lati
// chiusi a seconda della lunghezza, e a partire dal più lungo cerco un parametro su tale curva che mi consenta
// un'entrata sufficientemente distante da isole e da altre curve della curva stessa su cui cerco l'entrata ...
else {
// creo un vettore di indici che definisce l'ordine delle curve chiuse in base alla lunghezza
INTVECTOR vInd ; vInd.reserve( pCompo->GetCurveCount()) ;
// vettore di indici già utilizzati
INTVECTOR vIndUsed ; vIndUsed.reserve( pCompo->GetCurveCount()) ;
double dMaxLen = -INFINITO ;
int nCurrInd = 0 ;
bool bStop = false ;
for ( int c = 0 ; c < pCompo->GetCurveCount() && ! bStop ; ++ c) {
bStop = true ;
for ( int i = 0 ; i < pCompo->GetCurveCount() ; ++ i) {
int nProp_i ;
// se la curva i-esima non è già stata considerata ed è aperta...
if ( find( vIndUsed.begin(), vIndUsed.end(), i) == vIndUsed.end() &&
pCompo->GetCurveTempProp( i, nProp_i, 0) && nProp_i == 0) {
// creo la curva i-esima
const ICurve* pCrv_i( pCompo->GetCurve( i)) ;
double dLen_i ;
if ( pCrv_i->GetLength( dLen_i) && dLen_i > dMaxLen) { // se di lunghezza maggiore alla soglia...
dMaxLen = dLen_i ;
nCurrInd = i ;
bStop = false ;
}
}
}
vIndUsed.push_back( nCurrInd) ;
vInd.push_back( nCurrInd) ;
dMaxLen = -INFINITO ;
}
if (( int)vInd.size() == 0) {
// se questa condizione fosse vera allora non sono riuscito ad entrare da nessun lato aperto in precedenza e non
// ho nemmeno un lato chiuso disponibile per entrare...
pCompo->ChangeStartPoint( 0.5) ;
return true ;
}
// ora che ho riempito il vettore di indici lo scorro e cerco di entrare in questi lati chiusi secondo l'ordine
bool bOk = false ;
for ( int i = 0 ; i < ( int)vInd.size() && !bOk ; ++ i) {
const ICurve* pCrv( pCompo->GetCurve( vInd[i])) ;
double dPar ;
if ( GetParamForPtStartOnEdge( pCrv, pCompo, vCrvIsl, dPar)) {
pCompo->ChangeStartPoint( vInd[i] + dPar) ;
bOk = true ;
}
}
if ( ! bOk) {
// se non riesco ad entrare da nessun lato chiuso, considerando che in precedenza ho già provato ad
// entrare da tutti i lati aperti...
pCompo->ChangeStartPoint( 0.5) ;
return true ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::VerifyLeadInHelix( ISurfFlatRegion* pSrfChunk, const Point3d& ptCen, double dRad) const
{
// controllo della superifice
if ( pSrfChunk == nullptr)
return false ;
// vettore di tutte le curve della superficie
ICRVCOMPOPOVECTOR vCrv ;
for( int c = 0 ; c < pSrfChunk->GetChunkCount() ; c++) {
for ( int l = 0 ; l < pSrfChunk->GetLoopCount( c) ; l++) {
vCrv.emplace_back( ConvertCurveToComposite( pSrfChunk->GetLoop( c, l))) ;
}
}
if (( int)vCrv.size() == 0)
return false ;
// estraggo il bordo esterno
PtrOwner<ICurveComposite> pCompo( CloneCurveComposite( vCrv[0])) ;
if ( IsNull( pCompo))
return false ;
// recupero il piano della curva di contorno
Point3d ptStart ;
Vector3d vtN ;
if ( ! pCompo->GetStartPoint( ptStart) || ! pCompo->GetExtrusion( vtN))
return false ;
// porto il centro sullo stesso piano del contorno
Point3d ptCenL = ptCen - ( ptCen - ptStart) * vtN * vtN ;
// calcolo la distanza del centro dal contorno
double dMinDist ;
bool bOk = DistPointCurve( ptCenL, *pCompo).GetDist( dMinDist) &&
dMinDist > dRad + 0.5 * m_TParams.m_dDiam - 10 * EPS_SMALL ;
// se la curva per l'attacco è valida per tale, controllo che l'elica non intersechi eventuali isole
for ( int i = 1 ; bOk && i < int( vCrv.size()) ; i++)
bOk = DistPointCurve( ptCenL, *vCrv[i]).GetDist( dMinDist) &&
dMinDist > dRad + 0.5 * m_TParams.m_dDiam - 10 * EPS_SMALL ;
return bOk ;
}
//----------------------------------------------------------------------------
bool
Pocketing::VerifyLeadInZigZag( ISurfFlatRegion* pSrfChunk, const Point3d& ptPa, const Point3d& ptPb) const
{
// controllo della superificie
if ( pSrfChunk == nullptr)
return false ;
// vettore di tutte le curve della superficie
ICRVCOMPOPOVECTOR vCrv ;
for ( int c = 0 ; c < pSrfChunk->GetChunkCount() ; c++) {
for ( int l = 0 ; l < pSrfChunk->GetLoopCount( c) ; l++) {
vCrv.emplace_back( GetCurveComposite( pSrfChunk->GetLoop( c, l))) ;
}
}
if ( vCrv.size() == 0)
return false ;
// estraggo il bordo esterno
PtrOwner<ICurveComposite> pCompo( CloneCurveComposite( vCrv[0])) ;
if ( IsNull( pCompo))
return false ;
// recupero il piano della curva di contorno
Point3d ptStart ;
Vector3d vtN ;
if ( ! pCompo->GetStartPoint( ptStart) || ! pCompo->GetExtrusion( vtN))
return false ;
// porto i punti sullo stesso piano del contorno
Point3d ptPaL = ptPa - ( ptPa - ptStart) * vtN * vtN ;
Point3d ptPbL = ptPb - ( ptPb - ptStart) * vtN * vtN ;
// calcolo la distanza dei due punti dal contorno
double dMinDistPa ;
if ( ! DistPointCurve( ptPaL, *pCompo).GetDist( dMinDistPa))
return false ;
double dMinDistPb ;
if ( ! DistPointCurve( ptPbL, *pCompo).GetDist( dMinDistPb))
return false ;
bool bOk = dMinDistPa > 0.5 * m_TParams.m_dDiam - 10 * EPS_SMALL && dMinDistPb > 0.5 * m_TParams.m_dDiam - 10 * EPS_SMALL ;
// se la curva per l'attacco è valida per tale, controllo che lo ZigZag non intersechi eventuali isole
for ( int i = 1 ; bOk && i < int( vCrv.size()) ; i++) {
if ( ! DistPointCurve( ptPaL, *vCrv[i]).GetDist( dMinDistPa))
return false ;
if ( ! DistPointCurve( ptPbL, *vCrv[i]).GetDist( dMinDistPb))
return false ;
bOk = dMinDistPa > 0.5 * m_TParams.m_dDiam - 10 * EPS_SMALL && dMinDistPb > 0.5 * m_TParams.m_dDiam - 10 * EPS_SMALL ;
}
return bOk ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetParamsAtEachStep( ISURFFRPOVECTOR& vSrfSliced, vector<ICRVCOMPOPOVECTOR>& vCrvOEWithFlags,
BOOLVECTOR& vbChangedPrec, VCT3DVECTOR& vVtTrasl, const ISurfFlatRegion* pSrfChunk,
int& nStep, const Vector3d vtTool, const double& dElev, const double& dDepth,
const double& dStep)
{
// clono la superficie da svuotare
PtrOwner<ISurfFlatRegion> pSrfChunk_c( CloneSurfFlatRegion( pSrfChunk)) ;
if ( IsNull( pSrfChunk_c) || ! pSrfChunk_c->IsValid() || pSrfChunk_c->GetChunkCount() == 0)
return false ;
vVtTrasl.clear() ;
// creazione di un vettore con gli step ( caso base)
for ( int j = 1 ; j <= nStep ; ++ j)
vVtTrasl.push_back( - vtTool * ( dDepth - dElev + j * dStep)) ;
// ================================ RECUPERO DELLA TRIMESH (se selezionata) ==============================
// recupero il bordo della superficie
PtrOwner<ICurveComposite> pCrvBorder( GetCurveComposite( pSrfChunk_c->GetLoop( 0, 0))) ;
if ( IsNull( pCrvBorder) || ! pCrvBorder->IsValid())
return false ;
// recupero la superificie Trimesh ( se selezionata) ed eventualmente la FlatRegion
bool bIsStm = false ;
PtrOwner<ISurfTriMesh> pStmORIG( CreateSurfTriMesh()) ;
PtrOwner<ISurfFlatRegion> pSfrExtended( CreateSurfFlatRegion()) ;
if ( IsNull( pStmORIG) ||
IsNull( pSfrExtended) ||
! pStmORIG->AdjustTopology() ||
! GetSelectedStm( pCrvBorder, GLOB_FRM, bIsStm, pStmORIG))
return false ;
//========================================================================================================
// ============= SE TRIMESH SELEZIONATA, ALLORA RICAVO REGIONE MASSIMA ===================================
// DI PROEIZIONE E RICALCOLO EVENTUALI STEPS EXTRA
if ( bIsStm) {
// se la geometria selezionata è una Trimesh, allora :
// 1) controllo se ci sono delle facce da proiettare
if ( ! ProjectEdgesOfSelectedStm( pSrfChunk_c, pStmORIG, pSfrExtended))
return false ;
// 2) controllo se ci sono degli step extra ( aggiornando il vettore degli step)
if ( ! CalcExtraSteps( pSrfChunk_c, pStmORIG, vtTool, dElev, dDepth, nStep, dStep, vVtTrasl))
return false ;
vSrfSliced.resize(( int)vVtTrasl.size()) ;
vCrvOEWithFlags.resize(( int)vVtTrasl.size()) ;
vbChangedPrec.resize(( int)vVtTrasl.size()) ;
nStep = ( int)vVtTrasl.size() ;
}
// ======================================================================================
// =========================== RECUPERO DEL GREZZO NELLA FASE ATTUALE ===================
// recupero la temp prop 0 ( id per gruppo del grezzo corrente)
PtrOwner<ICurve> pCrv( pSrfChunk_c->GetLoop( 0, 0)) ;
if ( IsNull( pCrv))
return false ;
int nProp0 = pCrv->GetTempProp( 0) ;
PtrOwner<ISurfTriMesh> pStmRaw( CreateSurfTriMesh()) ;
pStmRaw->AdjustTopology() ;
if ( ! GetStmRawPart( nProp0 , pStmRaw, GLOB_FRM))
return false ;
// ======================================================================================
// ======================================================================================
// ======================== AD OGNI STEP ADATTO LA SUPERIFICIE ==========================
// ADATTAMENTO A TRIMESH ( se necessario) o SHAPE, INTERSEZIONE, PROIEZIONE
// ED ESTENSIONE PRESSO LATI APERTI
for ( int j = 1 ; j <= int( vVtTrasl.size()) ; ++ j) {
// vettore traslazione corrente
Vector3d vtTrasl = vVtTrasl[j-1] ;
// vettore delle curve con Flag per lati aperti
ICRVCOMPOPOVECTOR vCrvOEF ;
// flag se la superificie è cambiata
bool bChanged = false ;
// dichiaro la superificie da svuotare
PtrOwner<ISurfFlatRegion> pSrfToPock( CloneSurfFlatRegion( pSrfChunk_c)) ;
if ( IsNull( pSrfToPock) || ! pSrfToPock->IsValid())
return false ;
// se la geometria iniziale è una TriMesh, allora adatto la FlatRegion della svuotatura...
if ( bIsStm) {
if ( ! IsNull( pSfrExtended) && pSfrExtended->IsValid()) {
PtrOwner<ISurfFlatRegion> pSrfNewChunk_c( CreateSurfFlatRegion()) ;
if ( ! GetAdaptedSfrByTrimesh( pSfrExtended, pSrfChunk_c, pStmORIG, vtTrasl, pSrfNewChunk_c))
return false ;
pSrfToPock.Set( Release( pSrfNewChunk_c)) ;
}
}
// adatto la superficie dello step corrente con la geometria del grezzo
if ( AdaptSfrWithRaw( pSrfToPock, vtTrasl, pStmRaw, vCrvOEF, bChanged, j, dStep, 500 * EPS_SMALL, m_pStmShape)) {
// // 8) DISEGNO =========== TOGLIEREEEEEEEEEEEEEEEEEEEEEEEE ================================
/* PtrOwner<ISurfFlatRegion> pSrf_toDraw( CloneSurfFlatRegion( pSrfToPock)) ;
pSrf_toDraw->Translate( vtTrasl) ;
int a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrf_toDraw->Clone()) ;
m_pGeomDB->SetMaterial( a, Color( 0.0, 0.0, 1.0, 0.45)) ;
for ( int c = 0 ; c < pSrf_toDraw->GetChunkCount() ; ++ c) {
for ( int l = 0 ; l < pSrf_toDraw->GetLoopCount( c) ; ++ l) {
PtrOwner<ICurveComposite> pCrvCompo( GetCurveComposite( pSrf_toDraw->GetLoop( c, l))) ;
for ( int u = 0 ; u < pCrvCompo->GetCurveCount() ; ++ u) {
int nProp0 ; pCrvCompo->GetCurveTempProp( u, nProp0, 0) ;
int nProp1 ; pCrvCompo->GetCurveTempProp( u, nProp1, 1) ;
int aaa = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvCompo->GetCurve( u)->Clone()) ;
m_pGeomDB->SetMaterial( aaa, nProp0 == 0 ? BLUE : RED) ;
}
}
}*/
//return false ;
//// ===================================================================
vSrfSliced[j-1].Set( pSrfToPock->Clone()) ;
// la superificie potrebbe non essere valida ( ad esempio se già svuotata tutta con un Tool in precedenza...)
if ( ! IsNull( vSrfSliced[j-1])) {
for ( int h = 0 ; h < ( int)vCrvOEF.size() ; ++ h)
vCrvOEWithFlags[j-1].emplace_back( vCrvOEF[h]->Clone()) ;
// controllo se la superificie attuale e precedente sono diverse tra loro
if ( j > 1) {
double dAreaPrec = 0 ; double dAreaAct = 0 ;
if ( ! IsNull( vSrfSliced[j-2])) {
vSrfSliced[j-2]->GetArea( dAreaPrec) ;
vSrfSliced[j-1]->GetArea( dAreaAct) ;
if ( abs( dAreaAct - dAreaPrec) > 500 * EPS_SMALL)
vbChangedPrec[j-1] = true ;
}
else
vbChangedPrec[j-1] = true ;
}
}
}
else
return false ;
}
// ======================================================================================
return true ;
}
// --------------------------------------------------------------------------
bool
Pocketing::DetectShape( int nId, Frame3d frPocket)
{
// controllo dei parametri
if ( ! frPocket.IsValid())
return false ;
// recupero l'oggetto geometrico
const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( nId) ;
if ( pGObj == nullptr)
return false ;
// se l'oggetto geometrico non è una trimesh, allora errore
if ( pGObj->GetType() != SRF_TRIMESH)
return false ;
// recupero il Frame in cui si trova
Frame3d frRawPart ;
m_pGeomDB->GetGlobFrame( nId, frRawPart) ;
// recupero la TriMesh ( shape) associata all'oggetto geometrico
PtrOwner<ISurfTriMesh> pSrfRawPart( CloneSurfTriMesh( pGObj)) ;
if ( IsNull( pSrfRawPart))
return false ;
// porto la TriMesh ( shape) dal suo frame al frame richiesto
pSrfRawPart->LocToLoc( frRawPart, frPocket) ;
// assegno la TriMesh ( shape) al parametro della funzione e controllo la sua validità
m_pStmShape.Set( Release( pSrfRawPart)) ;
return m_pStmShape != nullptr && m_pStmShape->IsValid() && m_pStmShape->GetTriangleCount() > 0 ;
}
// --------------------------------------------------------------------------
bool
Pocketing::CalcExtraSteps( const ISurfFlatRegion* pSfrAct, const ISurfTriMesh* pStmORIG,
const Vector3d vtTool, const double& dElev, const double& dDepth, const int& nStep,
const double& dStep, VCT3DVECTOR& vtVtTrasl)
{
// controllo dei parametri
if ( pSfrAct == nullptr || ! pSfrAct->IsValid() || pSfrAct->GetChunkCount() == 0 ||
pStmORIG == nullptr || ! pStmORIG->IsValid())
return false ;
vtVtTrasl.clear() ;
// 0) scorro tutti gli steps
for ( int j = 1 ; j <= nStep ; ++ j) {
// 1) clono la superficie TriMesh originale
PtrOwner<ISurfTriMesh> pStmORIG_c( CloneSurfTriMesh( pStmORIG)) ;
if ( IsNull( pStmORIG_c) || ! pStmORIG_c->IsValid())
return false ;
// 2) ricavo il vettore di Traslazione attuale e il precedente ( salvo l'attuale)
Vector3d vtActTrasl = - vtTool * ( dDepth - dElev + j * dStep) ;
vtVtTrasl.push_back( vtActTrasl) ;
Vector3d vtPrecTrasl = - vtTool * ( dDepth - dElev + ( j-1) * dStep) ;
// 2) Ricavo i piani di taglio
Point3d ptC ; pSfrAct->GetCentroid( ptC) ;
Vector3d vtN = pSfrAct->GetNormVersor() ;
Plane3d plNear ; plNear.Set( ptC + vtActTrasl, -vtN) ;
Plane3d plFar ; plFar.Set( ptC + vtPrecTrasl, vtN) ;
if ( ! plNear.IsValid() || ! plFar.IsValid())
return false ;
// 3) taglio la Trimesh con questi piani
if ( ! pStmORIG_c->Cut( plNear, true) ||
! pStmORIG_c->Cut( plFar, true))
return false ;
if ( ! pStmORIG_c->IsValid())
continue ;
// 4) Cerco se ci sono delle facce che presentano una normale parallela al versore di svuotatura
vector<double> vdDists ;
for ( int f = 0 ; f < pStmORIG_c->GetFacetCount() ; ++ f) {
Vector3d vtN_Check ; pStmORIG_c->GetFacetNormal( f, vtN_Check) ;
if ( ! AreSameVectorApprox( vtN_Check, vtN))
continue ;
// 5) se faccia trovata, allora calcolo la distanza tra il piano far e la faccia
Point3d ptC_f ; pStmORIG_c->GetFacetCenter( f, ptC_f, vtN) ;
double dCurrDist = abs( DistPointPlane( ptC_f, plFar)) ;
if ( dCurrDist < 100 * EPS_SMALL || abs( dCurrDist - dStep) < 100 * EPS_SMALL) // andava già bene lo step deciso a priori ;)
continue ;
// 6) inserisco uno step se tale distanza non è già ( in maniera approssimativa) contenuta nel vettore
// delle distanze
bool bInsert = true ;
for ( int d = 0 ; d < ( int)vdDists.size() && bInsert ; ++ d) {
if ( abs( dCurrDist - vdDists[d]) < 100 * EPS_SMALL * dStep)
bInsert = false ;
}
if ( bInsert) {
// 6.1) aggiorno il vettore delle distanze
vdDists.push_back( dCurrDist) ;
// 6.2) ricavo il vettore traslazione extra
Vector3d vtTraslExtra = vtPrecTrasl - vtTool * dCurrDist ;
// 6.3) inserisco nel vettore traslazione il nuovo step ricavato
vtVtTrasl.push_back( vtTraslExtra) ;
}
}
}
// 7) ora riodino il vettore ( le facce f ricavate non sono per forza ordinate rispetto al versore di svuotatura)
// 7.1) creo un frame locale per confrontare solo i valori lungo Z
Frame3d frPock ;
Point3d ptORIG ; pSfrAct->GetCentroid( ptORIG) ;
frPock.Set( ptORIG, pSfrAct->GetNormVersor()) ;
if ( ! frPock.IsValid())
return false ;
// 7.2) porto in locale il vettore delle traslazioni
for ( int v = 0 ; v < ( int)vtVtTrasl.size() ; ++ v)
vtVtTrasl[v].ToLoc( frPock) ;
// 7.3) confronto i valori di Z ( ordine decrescente)
sort( vtVtTrasl.begin(), vtVtTrasl.end(), []( Vector3d &a, Vector3d &b){ return a.z > b.z ; }) ;
// 7.4) riporto il vettore nel frame globale
for ( int v = 0 ; v < ( int)vtVtTrasl.size() ; ++ v)
vtVtTrasl[v].ToGlob( frPock) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetSelectedStm( const ICurveComposite* pCvrBorder, Frame3d frPocket, bool& bIsStm, ISurfTriMesh* pStmOrig)
{
// controllo dei parametri
if ( pCvrBorder == nullptr || ! pCvrBorder->IsValid() || pCvrBorder->GetCurveCount() == 0)
return false ;
bIsStm = false ;
// recupero l'Id della geometria selezionata
int nId = pCvrBorder->GetTempProp( 0) ;
// recupero l'oggetto dal database con tale Id
const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( nId) ;
if ( pGObj == nullptr)
return false ;
// recupero il frame in cui si trova
Frame3d frGeObj ;
m_pGeomDB->GetGlobFrame( nId, frGeObj) ;
// controllo che sia una Trimesh, altrimenti non modifico nulla
if ( pGObj->GetType() != SRF_TRIMESH)
return true ;
// recupero la Trimesh originale
PtrOwner<ISurfTriMesh> pStmORIG( CloneSurfTriMesh( pGObj)) ;
if ( IsNull( pStmORIG) || ! pStmORIG->IsValid())
return false ;
// porto la trimesh in globale
pStmORIG->LocToLoc( frGeObj, frPocket) ;
pStmOrig->CopyFrom( pStmORIG) ;
// aggiorno il Flag
bIsStm = true ;
return pStmOrig != nullptr && pStmOrig->IsValid() && pStmOrig->GetTriangleCount() > 0 ;
}
//----------------------------------------------------------------------------
bool
Pocketing::ProjectEdgesOfSelectedStm( const ISurfFlatRegion* pSrfToPock, const ISurfTriMesh* pStmORIG,
ISurfFlatRegion* pSfrNew)
{
// controllo dei parametri
if ( pSrfToPock == nullptr || ! pSrfToPock->IsValid() || pSrfToPock->GetChunkCount() == 0 ||
pStmORIG == nullptr || ! pStmORIG->IsValid() || pStmORIG->GetTriangleCount() == 0)
return false ;
pSfrNew->Clear() ;
// controllo se il tool ha un SideAngle
if ( m_TParams.m_dSideAng != 0) {
// ... controllo che gli angoli delle facce siano coerenti al tool selezionato
// ...
// ...
// ...
return true ;
}
// 1) recupero la curva esterna della regione da svuotare
PtrOwner<ICurveComposite> pCrvBorder( GetCurveComposite( pSrfToPock->GetLoop( 0, 0))) ;
if ( IsNull( pCrvBorder) || ! pCrvBorder->IsValid() || pCrvBorder->GetCurveCount() == 0)
return false ;
// 2) Recupero la faccia selezionata ( è la TmpProp 1)
int nFacet = pCrvBorder->GetTempProp( 1) ;
if ( nFacet < 0)
return false ;
// 3) creazione di una FlatRegion formata dall'originale a cui unisco ogni proiezione ( le isole sono trascurate)
PtrOwner<ISurfFlatRegion> pSrfGlobProjection( CreateSurfFlatRegion()) ;
if ( IsNull( pSrfGlobProjection))
return false ;
// --------------------------------- Proiezioni di tutti i lati adiacenti --------------------------------------
// a) creazione di una FlatRegion con solo il bordo esterno ( le isole sono trascurate)
PtrOwner<ISurfFlatRegion> pSrfBorderExt( CreateSurfFlatRegion()) ;
if ( IsNull( pSrfBorderExt))
return false ;
pSrfBorderExt->AddExtLoop( pCrvBorder->Clone()) ;
// b) creazione del piano di svuotatura ( piano passante per la faccia selezionata sulla TriMesh)
Point3d ptC ; pSrfToPock->GetCentroid( ptC) ;
Vector3d vtN = pSrfToPock->GetNormVersor() ;
Plane3d plPock ; plPock.Set( ptC, vtN) ;
if ( ! plPock.IsValid())
return false ;
// c) creo una copia della TriMesh originale togliendo la faccia selezionata
PtrOwner<ISurfTriMesh> pStmORIG_noSelFace( CloneSurfTriMesh( pStmORIG)) ;
if ( IsNull( pStmORIG_noSelFace) || ! pStmORIG_noSelFace->IsValid() ||
! pStmORIG_noSelFace->RemoveFacet( nFacet))
return false ;
if ( IsNull( pStmORIG_noSelFace) ||
! pStmORIG_noSelFace->IsValid() ||
pStmORIG_noSelFace->GetTriangleCount() == 0)
return true ; // <--- tutti i lati sono aperti !
// d) proietto tutto sul piano di svuotatura e aggiungo la faccia selezionata
PtrOwner<ISurfFlatRegion> pSfrProj( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrProj) ||
! ProjectStmOnPlane( pStmORIG_noSelFace, plPock, pSfrProj))
return false ;
if ( ! IsNull( pSfrProj) && pSfrProj->IsValid() && pSfrProj->GetChunkCount() != 0) {
if ( ! pSrfBorderExt->Add( *pSfrProj))
return false ;
}
// d) se valida, restituisco
if ( pSrfBorderExt->IsValid())
pSfrNew->CopyFrom( pSrfBorderExt) ;
return pSfrNew->IsValid() && pSfrNew->GetChunkCount() > 0 ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetAdaptedSfrByTrimesh( const ISurfFlatRegion* pSrfExtended, const ISurfFlatRegion* pSfrORIG,
const ISurfTriMesh* pStmORIG, const Vector3d& vtTrasl, ISurfFlatRegion* pNewSrfPock)
{
// controllo dei parametri
if ( pSrfExtended == nullptr || ! pSrfExtended->IsValid() || pNewSrfPock == nullptr)
return false ;
pNewSrfPock->Clear() ;
// clono la superficie da svuotare e la porto allo step corrente
PtrOwner<ISurfFlatRegion> pSrfExtended_cl( CloneSurfFlatRegion( pSrfExtended)) ;
if ( IsNull( pSrfExtended_cl) || ! pSrfExtended_cl->IsValid())
return false ;
pSrfExtended_cl->Translate( vtTrasl) ;
// proprietà :
PtrOwner<ICurveComposite> pCrvForProps( GetCurveComposite( pSfrORIG->GetLoop( 0, 0))) ;
Vector3d vtExtr ; pCrvForProps->GetExtrusion( vtExtr) ;
double dThick ; pCrvForProps->GetThickness( dThick) ;
int nTmpProp0 = pCrvForProps->GetTempProp( 0) ;
int nTmpProp1 = pCrvForProps->GetTempProp( 1) ;
// 1) Converto la FlatRegion estesa in Trimesh
PtrOwner<ISurfTriMesh> pStmExtended( CloneSurfTriMesh( pSrfExtended_cl->GetAuxSurf())) ;
if ( IsNull( pStmExtended) || ! pStmExtended->IsValid())
return false ;
//m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmExtended->Clone()) ;
//m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmORIG->Clone()) ;
// 2) Creazione della FlatRegion di proiezione complessiva delle facce della TriMesh sopra al piano di svuotatura
// attuale
PtrOwner<ISurfFlatRegion> pSfrProjUP( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrProjUP))
return false ;
// 4) Creo il piano di proeizione allo step attuale
Point3d ptC ; pSrfExtended_cl->GetCentroid( ptC) ;
Vector3d vtN = pSfrORIG->GetNormVersor() ;
Plane3d plProj ; plProj.Set( ptC, -vtN) ;
if ( ! plProj.IsValid())
return false ;
// 5) taglio la TriMesh originale togliendo tutto ciò che sta sotto al piano di proiezione
PtrOwner<ISurfTriMesh> pStmORIG_forCut( CloneSurfTriMesh( pStmORIG)) ;
if ( IsNull( pStmORIG_forCut) || ! pStmORIG_forCut->IsValid())
return false ;
if ( ! pStmORIG_forCut->Cut( plProj, true))
return false ;
if ( pStmORIG_forCut->IsValid()) {
// 6) Proietto tutto ciò che sta sopra alla superficie di taglio
if ( ! ProjectStmOnPlane( pStmORIG_forCut, plProj, pSfrProjUP))
return false ;
}
//m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrProjUP->Clone()) ;
// 7) verifico se la superificie è problematica per il taglio
PtrOwner<ISurfFlatRegion> pSfrORIGNoSelFaceProj( CreateSurfFlatRegion()) ;
PtrOwner<ISurfFlatRegion> pSfrExtended( CreateSurfFlatRegion()) ;
if ( ! GetSfrByStm( pStmExtended, pSfrExtended, plProj, vtExtr, dThick))
return false ;
PtrOwner<ISurfTriMesh> pStmORIGNoSelFace( CloneSurfTriMesh( pStmORIG)) ;
if ( ! pStmORIGNoSelFace->RemoveFacet( nTmpProp1) ||
! ProjectStmOnPlane( pStmORIGNoSelFace, plProj, pSfrORIGNoSelFaceProj))
return false ;
if ( AreOppositeVectorApprox( vtN, pSfrORIGNoSelFaceProj->GetNormVersor()))
pSfrORIGNoSelFaceProj->Invert() ;
if ( ! IsNull( pSfrORIGNoSelFaceProj) && pSfrORIGNoSelFaceProj->IsValid()) {
PNTVECTOR vPt ;
BIPNTVECTOR vBpt ;
TRIA3DVECTOR vTria ;
if ( IntersPlaneSurfTm( plProj, *pStmORIG, vPt, vBpt, vTria) && ( int)vTria.size() == 0) {
ChainCurves chainC ;
chainC.Init( false, 50 * EPS_SMALL, 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 false ;
}
// recupero i percorsi concatenati
Point3d ptNear = ( vBpt.empty() ? ORIG : vBpt[0].first) ;
INTVECTOR vId ;
bool bExtraSub = false ;
while ( chainC.GetChainFromNear( ptNear, false, vId)) {
// creo una curva composita
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
if ( IsNull( pCrvCompo))
return false ;
// 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 false ;
// 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) > 50 * EPS_SMALL / 2 &&
pLine->Set( ptStart, ptEnd) &&
pCrvCompo->AddCurve( Release( pLine), true, 50 * EPS_SMALL)) ;
ptNear = ( bAdded ? ptEnd : ptStart) ;
}
// le linee chiuse si riesono a tagliare
if ( pCrvCompo->IsClosed())
continue ;
// Test dei punti
Point3d ptS, ptE ;
pCrvCompo->GetStartPoint( ptS) ;
pCrvCompo->GetEndPoint( ptE) ;
bool bS = false ;
bool bE = false ;
for ( int c = 0 ; c < pSfrExtended->GetChunkCount() ; ++ c) {
for ( int l = 0 ; l < pSfrExtended->GetLoopCount( c) ; ++ l) {
PtrOwner<ICurve> pCrvLoopH( pSfrExtended->GetLoop( c, l)) ;
if ( pCrvLoopH->IsPointOn( ptS, 50 * EPS_SMALL))
bS = true ;
if ( pCrvLoopH->IsPointOn( ptE, 50 * EPS_SMALL))
bE = true ;
//m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvCompo->Clone()) ;
//m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrExtended->Clone()) ;
}
}
bExtraSub = ! ( bS && bE) ;
if ( bExtraSub) {
// 9.2) conservo le parti in comuune tra quest'ultima FlatRegion e la superificie originale
if ( ! pSfrORIGNoSelFaceProj->Intersect( *pSfrORIG))
return false ;
// 7.3) Sottraggo
if ( pSfrORIGNoSelFaceProj->IsValid() &&
pSfrExtended->Subtract( *pSfrORIGNoSelFaceProj)) {
if ( IsNull( pSfrExtended) || ! pSfrExtended->IsValid())
return false ;
pStmExtended.Set( pSfrExtended->GetAuxSurf()->Clone()) ;
if ( IsNull( pStmExtended) || ! pStmExtended->IsValid())
return false ;
}
break ;
}
}
}
}
// 8) Verifico se riesco a fare il taglio
//m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmExtended->Clone()) ;
//m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmORIG->Clone()) ;
if ( ! pStmExtended->CutWithOtherSurf( *pStmORIG, false, true))
return false ;
if ( ! IsNull( pStmExtended) && pStmExtended->GetTriangleCount() == 0)
pStmExtended.Set( CloneSurfTriMesh( pSfrORIG->GetAuxSurf())) ;
//m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmExtended->Clone()) ;
// 8) Riconverto in FlatRegion
if ( ! GetSfrByStm( pStmExtended, pSfrExtended, plProj, vtExtr, dThick))
return false ;
if ( pSfrProjUP->IsValid()) {
if ( AreOppositeVectorApprox( vtN, pSfrProjUP->GetNormVersor()))
pSfrProjUP->Invert() ;
if ( IsNull( pSfrExtended) ||
! pSfrExtended->Subtract( *pSfrProjUP))
return false ;
//m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrExtended->Clone()) ;
//m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrProjUP->Clone()) ;
//m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrExtended_Sub->Clone()) ;
}
// 9) Ricalcolo lati aperti e lati chiusi
SurfFlatRegionByContours sfrBC ;
// 13.1) scorro tutti i Loops ottenuti e imposto loro le TmpProps
for ( int c = 0 ; c < pSfrExtended->GetChunkCount() ; ++ c) {
for ( int l = 0 ; l < pSfrExtended->GetLoopCount( c) ; ++ l) {
// 13.2) recupero della Curva Composita
PtrOwner<ICurveComposite> pCrvLoop( ConvertCurveToComposite( pSfrExtended->GetLoop( c, l))) ;
if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid())
return false ;
// 13.3) se Isola allora tutta la curva è chiusa
if ( l > 0) {
for ( int u = 0 ; u < pCrvLoop->GetCurveCount() ; ++ u)
pCrvLoop->SetCurveTempProp( u, 0, 0) ;
}
// 13.4) se curva esterna, setto le TmpProp mediante Overlaps
else {
// 13.5.1) riempio un vettore du curve con TmpProps adeguate
ICRVCOMPOPOVECTOR vCrvWithTmpProps ;
if ( pSfrORIGNoSelFaceProj->IsValid())
pSfrORIGNoSelFaceProj->Intersect( *pSfrORIG) ;
PtrOwner<ISurfFlatRegion> pSfrORIG_Tr( CloneSurfFlatRegion( pSfrORIG)) ;
pSfrORIG_Tr->Translate( vtTrasl) ;
if ( ! ManageTmpPropForAdaptingStm( pSfrORIG_Tr, pSfrProjUP, pSfrORIGNoSelFaceProj, vCrvWithTmpProps))
return false ;
// 13.5.2) assegno la TmpProp ad ogni sottocurva
for ( int u = 0 ; u < pCrvLoop->GetCurveCount() ; ++ u) {
bool bFound = false ;
for ( int i = 0 ; i < ( int)vCrvWithTmpProps.size() && !bFound ; ++ i) {
int nStat ;
if ( SetTmpPropByOverlap( pCrvLoop, u, vCrvWithTmpProps[i], nStat, 250 * EPS_SMALL) &&
nStat == 1)
bFound = true ;
}
// se non vi è Overlap, controllo se sono sulla TriMesh o no
if ( ! bFound) {
PtrOwner<ICurve> pCrv_u( pCrvLoop->GetCurve( u)->Clone()) ;
Point3d ptS, ptM, ptE ;
pCrv_u->GetStartPoint( ptS) ;
pCrv_u->GetEndPoint( ptE) ;
pCrv_u->GetMidPoint( ptM) ;
PtrOwner<ISurfTriMesh> pStmNoSelFace( CloneSurfTriMesh( pStmORIG)) ;
//if ( ! pStmNoSelFace->RemoveFacet( nTmpProp1))
// return false ;
DistPointSurfTm dPStm1( ptS, *pStmNoSelFace) ;
DistPointSurfTm dPStm2( ptM, *pStmNoSelFace) ;
DistPointSurfTm dPStm3( ptE, *pStmNoSelFace) ;
double dDist1, dDist2, dDist3 ;
pCrvLoop->SetCurveTempProp( u, 0, 0) ;
if ( dPStm1.GetDist( dDist1) && dDist1 > 250 * EPS_SMALL)
pCrvLoop->SetCurveTempProp( u, 1, 0) ;
else if ( dPStm2.GetDist( dDist2) && dDist2 > 250 * EPS_SMALL)
pCrvLoop->SetCurveTempProp( u, 1, 0) ;
else if ( dPStm3.GetDist( dDist3) && dDist3 > 250 * EPS_SMALL)
pCrvLoop->SetCurveTempProp( u, 1, 0) ;
}
}
}
// 2.6) riporto le proprietà
pCrvLoop->SetTempProp( nTmpProp0, 0) ;
pCrvLoop->SetTempProp( nTmpProp1, 1) ;
pCrvLoop->SetExtrusion( vtExtr) ;
pCrvLoop->SetThickness( dThick) ;
// 2.8) inserimento della curva
sfrBC.AddCurve( Release( pCrvLoop)) ;
}
}
// 7) ritorno la superificie ottenuta
PtrOwner<ISurfFlatRegion> pSfrFINAL( sfrBC.GetSurf()) ;
if ( IsNull( pSfrFINAL) || ! pSfrFINAL->IsValid())
return false ;
pNewSrfPock->CopyFrom( pSfrFINAL) ;
pNewSrfPock->Translate( -vtTrasl) ;
return pNewSrfPock != nullptr && pNewSrfPock->IsValid() && pNewSrfPock->GetChunkCount() > 0 ;
}
//----------------------------------------------------------------------------
bool
Pocketing::ManageTmpPropForAdaptingStm( const ISurfFlatRegion* pSfrORIG, const ISurfFlatRegion* pSfrProjUP,
const ISurfFlatRegion* pSrfProjToT, ICRVCOMPOPOVECTOR& vCrvWithTmpProps)
{
// controllo dei parametri
if ( pSfrORIG == nullptr || ! pSfrORIG->IsValid() || pSfrORIG->GetChunkCount() == 0 )
return false ;
vCrvWithTmpProps.clear() ;
// in prima posizione metto il loop esterno
for ( int c = 0 ; c < pSfrORIG->GetChunkCount() ; ++ c) {
PtrOwner<ICurveComposite> pCrvCompoLoop( ConvertCurveToComposite( pSfrORIG->GetLoop( c, 0))) ;
vCrvWithTmpProps.emplace_back( Release( pCrvCompoLoop)) ;
}
// in successione metto tutte le altre curve ricavate dal bordo della ProjectUP
if ( pSrfProjToT != nullptr && pSrfProjToT->IsValid()) {
for ( int c = 0 ; c < pSrfProjToT->GetChunkCount() ; ++ c) {
for ( int l = 0 ; l < pSrfProjToT->GetLoopCount( c) ; ++ l) {
PtrOwner<ICurveComposite> pCrvCompoLoop( ConvertCurveToComposite( pSrfProjToT->GetLoop( c, l))) ;
for ( int u = 0 ; u < pCrvCompoLoop->GetCurveCount() ; ++ u)
pCrvCompoLoop->SetCurveTempProp( u, 0, 0) ; // <-- chiuse
vCrvWithTmpProps.emplace_back( Release( pCrvCompoLoop)) ;
}
}
}
// in successione metto tutte le altre curve ricavate dal bordo della ProjectUP
if ( pSfrProjUP != nullptr && pSfrProjUP->IsValid()) {
for ( int c = 0 ; c < pSfrProjUP->GetChunkCount() ; ++ c) {
for ( int l = 0 ; l < pSfrProjUP->GetLoopCount( c) ; ++ l) {
PtrOwner<ICurveComposite> pCrvCompoLoop( ConvertCurveToComposite( pSfrProjUP->GetLoop( c, l))) ;
for ( int u = 0 ; u < pCrvCompoLoop->GetCurveCount() ; ++ u)
pCrvCompoLoop->SetCurveTempProp( u, 0, 0) ; // <-- chiuse
vCrvWithTmpProps.emplace_back( Release( pCrvCompoLoop)) ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::ProjectStmOnPlane( const ISurfTriMesh* pStmAbove, const Plane3d plPock, ISurfFlatRegion* pSfrProj)
{
// controllo parametri
if ( pStmAbove == nullptr || ! pStmAbove->IsValid() || pStmAbove->GetTriangleCount() == 0)
return true ;
if ( ! plPock.IsValid())
return false ;
pSfrProj->Clear() ;
// 1) creo il sistema di riferimento ( inerente al piano di svuotatura)
Point3d ptORIG = plPock.GetPoint() ;
Vector3d vtN = -plPock.GetVersN() ;
Frame3d frPlane ; frPlane.Set( ptORIG, vtN) ;
if ( ! frPlane.IsValid())
return false ;
// 2) creo una copia della superficie nel nuovo sistema di riferimento
PtrOwner<ISurfTriMesh> pStmRef( CloneSurfTriMesh( pStmAbove)) ;
if ( IsNull( pStmRef) || ! pStmRef->IsValid())
return false ;
//int b = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmRef->Clone()) ;
//m_pGeomDB->SetMaterial( b, BLUE) ;
// 2.1) Per semplicità rimuovo dalla superficie tutti i triangoli che sono perpendicolari al piano di svuotatura
StmFromTriangleSoup TriaSoupEasy ; TriaSoupEasy.Start() ;
for ( int t = 0 ; t < pStmRef->GetTriangleCount() ; ++ t) {
Vector3d vtNTria ;
if ( pStmRef->GetFacetNormal( pStmRef->GetFacetFromTria( t), vtNTria) &&
abs( vtNTria * vtN) > EPS_SMALL) {
Triangle3d Tria ; pStmRef->GetTriangle( t, Tria) ;
TriaSoupEasy.AddTriangle( Tria) ;
}
}
TriaSoupEasy.End() ;
PtrOwner<ISurfTriMesh> pStmRef_Easy( TriaSoupEasy.GetSurf()) ;
if ( IsNull( pStmRef_Easy) || ! pStmRef_Easy->IsValid())
return true ; // non ho nulla da proiettare
pStmRef.Set( pStmRef_Easy->Clone()) ;
// 3) scalo la superficie rispetto al sistema di riferimento ( mettendo a 0 la componente vtN)
pStmRef->ToLoc( frPlane) ;
if ( ! pStmRef->Scale( GLOB_FRM, 1., 1., 0.))
return false ;
pStmRef->ToGlob( frPlane) ;
//int P = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmRef->Clone()) ;
//m_pGeomDB->SetMaterial( P, PURPLE) ;
// 4) controllo la validità della superficie ottenuta
if ( IsNull( pStmRef) || ! pStmRef->IsValid() || pStmRef->GetTriangleCount() == 0)
return true ; // la proeizione sparisce
// 5) NB. A seconda di come sono orientate le facce, posso avere i Triangoli con normali vtN o -vtN...
// rendo le normali dei triangoli coerenti
StmFromTriangleSoup TriaSoupUp ; TriaSoupUp.Start() ;
StmFromTriangleSoup TriaSoupDown ; TriaSoupDown.Start() ;
for ( int t = 0 ; t < pStmRef->GetTriangleCount() ; ++ t) {
Triangle3d Tria ; pStmRef->GetTriangle( t, Tria) ;
if ( AreOppositeVectorApprox( Tria.GetN(), vtN))
TriaSoupDown.AddTriangle( Tria) ;
else
TriaSoupUp.AddTriangle( Tria) ;
}
TriaSoupUp.End() ;
TriaSoupDown.End() ;
PtrOwner<ISurfTriMesh> pStmUp( TriaSoupUp.GetSurf()) ; // superificie con i Triangoli Up
PtrOwner<ISurfTriMesh> pStmDown( TriaSoupDown.GetSurf()) ; // superificie con i Triangoli Down
// 5.1) Controllo ausiliario... ( per possibili approssimazioni con triangoli particolari)
if ( ! IsNull( pStmUp) && pStmUp->IsValid() && pStmUp->GetTriangleCount() == 0 &&
! IsNull( pStmDown) && pStmDown->IsValid() && pStmDown->GetTriangleCount() == 0)
return true ;
pStmUp->Repair() ; pStmDown->Repair() ;
//int r = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmUp->Clone()) ;
//int o = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmDown->Clone()) ;
//m_pGeomDB->SetMaterial( r, RED) ;
//m_pGeomDB->SetMaterial( o, ORANGE) ;
//m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrProj->Clone()) ;
// 6) Essendo due Trimesh piane e sullo stesso piano, converto in FlatRegion prima di unirle
PtrOwner<ISurfFlatRegion> pSfrUp( CreateSurfFlatRegion()) ;
PtrOwner<ISurfFlatRegion> pSfrUp1( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrUp) || IsNull( pSfrUp1))
return false ;
if ( ! IsNull( pStmUp) && pStmUp->IsValid() && pStmUp->GetTriangleCount() > 0)
if ( ! GetSfrByStm( pStmUp, pSfrUp, plPock, V_NULL, 0., 0.))
return false ;
if ( ! IsNull( pStmDown) && pStmDown->IsValid() && pStmDown->GetTriangleCount() > 0)
if ( pStmDown->Invert())
if ( ! GetSfrByStm( pStmDown, pSfrUp1, plPock, V_NULL, 0., 0.))
return false ;
// 7) Controllo validità e creo la FlatRegion da restituire
if ( ! IsNull( pSfrUp) && pSfrUp->IsValid()) { // se Up valida, allora inizio a sostituire
if ( AreOppositeVectorApprox( pSfrUp->GetNormVersor(), plPock.GetVersN()))
pSfrUp->Invert() ;
pSfrProj->CopyFrom( pSfrUp) ;
}
if ( ! IsNull( pSfrUp1) && pSfrUp1->IsValid()) { // se Down valida...
if ( AreOppositeVectorApprox( pSfrUp1->GetNormVersor(), plPock.GetVersN()))
pSfrUp1->Invert() ;
if ( pSfrProj != nullptr && pSfrProj->IsValid()) { // e Up valida -> aggiungo
if ( ! pSfrProj->Add( *pSfrUp1))
return false ;
}
else // se Up non valida -> copio
pSfrProj->CopyFrom( pSfrUp1) ;
}
return pSfrProj != nullptr && pSfrProj->IsValid() && pSfrProj->GetChunkCount() != 0 ;
}
//----------------------------------------------------------------------------
bool
Pocketing::CloseCurvesOnProjectionSurface( ICurveComposite* pCrvCompo, const ISurfFlatRegion* pSrfProjDanger)
{
int YE = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvCompo->Clone()) ;
m_pGeomDB->SetMaterial( YE, YELLOW) ;
int ORA = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrfProjDanger->Clone()) ;
m_pGeomDB->SetMaterial( ORA, ORANGE) ;
// controllo dei parametri
if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid() || pCrvCompo->GetCurveCount() == 0)
return false ;
// se non ho regioni pericolse, allora il problema non si pone
if ( pSrfProjDanger == nullptr || ! pSrfProjDanger->IsValid() || pSrfProjDanger->GetChunkCount() == 0)
return true ;
// Interseco la curva con la superificie pericolosa
CRVCVECTOR ccClass ;
for ( int u = 0 ; u < pCrvCompo->GetCurveCount() ; ++ u) {
// recupero la curva u-esima
PtrOwner<ICurve> pCrv_u( pCrvCompo->GetCurve( u)->Clone()) ;
if ( IsNull( pCrv_u) || ! pCrv_u->IsValid())
return false ;
// classifico la curva con la regione pericolosa di proiezione
if ( pSrfProjDanger->GetCurveClassification( *pCrv_u, EPS_SMALL, ccClass)) {
if (( int)ccClass.size() == 1 && ccClass[0].nClass != CRVC_OUT) {
pCrvCompo->SetCurveTempProp( u, 0, 0) ;
pCrvCompo->SetCurveTempProp( u, -2, 1) ;
}
else {
for ( int j = 0 ; j < ( int)ccClass.size() ; ++ j) {
if ( ccClass[j].nClass != CRVC_OUT) {
PtrOwner<ICurveComposite> pCrv_Bef( CloneCurveComposite( pCrvCompo)) ; // tratto precente
PtrOwner<ICurveComposite> pCrv_Aft( CloneCurveComposite( pCrvCompo)) ; // tratto successivo
PtrOwner<ICurveComposite> pCrv_New( CloneCurveComposite( pCrvCompo)) ; // tratto attuale
if ( IsNull( pCrv_Bef) || IsNull( pCrv_Aft) || IsNull( pCrv_New) ||
! pCrv_Bef->IsValid() || ! pCrv_Aft->IsValid())
return false ;
// ricomposizione con tagli per non perdere le proprietà appena impostate
if ( ! pCrv_Bef->TrimEndAtParam( u + ccClass[j].dParS))
pCrv_Bef->Clear() ;
if ( ! pCrv_Aft->TrimStartAtParam( u + ccClass[j].dParE))
pCrv_Aft->Clear() ;
if ( ! IsNull( pCrv_Bef) && pCrv_Bef->IsValid())
pCrv_New->AddCurve( Release( pCrv_Bef)) ;
if ( ! pCrv_New->TrimStartEndAtParam( u + ccClass[j].dParS, u + ccClass[j].dParE))
break ;
pCrv_New->SetCurveTempProp( 0, 0, 0) ; // tratto di curva chiuso
if ( ! IsNull( pCrv_Aft) && pCrv_Aft->IsValid())
pCrv_New->AddCurve( Release( pCrv_Aft)) ;
if ( ! IsNull( pCrv_New) && pCrv_New->IsValid() && pCrv_New->IsClosed()) {
pCrvCompo->Clear() ;
pCrvCompo->AddCurve( Release( pCrv_New)) ;
}
}
}
}
}
else
return false ;
}
return pCrvCompo != nullptr && pCrvCompo->IsValid() &&
pCrvCompo->GetCurveCount() > 0 && pCrvCompo->IsClosed() ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AdaptSfrWithRaw( ISurfFlatRegion* pSrf, Vector3d vtTrasl, ISurfTriMesh* pStmRaw,
ICRVCOMPOPOVECTOR& vCrvOEFlags, bool& bChanged, int nStep, double dStep, double dAreaToll,
ISurfTriMesh* pStmShape)
{
// controllo dei parametri
if ( pSrf == nullptr || dAreaToll < EPS_SMALL)
return false ;
// recupero la temp prop 0 ( id per gruppo del grezzo corrente)
PtrOwner<ICurve> pCrv( pSrf->GetLoop( 0, 0)) ;
if ( IsNull( pCrv))
return false ;
int nProp0 = pCrv->GetTempProp( 0) ;
// se il grezzo è stato trovato, allora controllo intersezioni e proiezioni per lati aperti
if ( pStmRaw->IsValid() || pStmRaw->GetTriangleCount() > 0) {
// tengo una copia della superificie prima dell'intersezione con il grezzo
PtrOwner<ISurfFlatRegion> pSrfOrig( CloneSurfFlatRegion( pSrf)) ;
if ( IsNull( pSrfOrig) || ! pSrfOrig->IsValid())
return false ;
// 1) INTERSEZIONE CON GREZZO
if ( m_bIntersRaw) {
if ( ! IntersSurfWithRaw( pSrf, pStmRaw, vtTrasl, bChanged, dAreaToll, true, m_dDiam_Prec < EPS_SMALL))
return false ;
if ( pSrf == nullptr || pSrf->GetChunkCount() == 0 || ! pSrf->IsValid())
return true ;
}
// 2) PROIEZIONE CON GREZZO
if ( m_bProjectRaw) {
// recupero la Trimesh di partenza
if ( ! ProjectRaw( pSrf, vtTrasl, pStmRaw, nProp0, pSrfOrig, nStep, dStep))
return false ;
if ( pSrf->GetChunkCount() == 0 || ! pSrf->IsValid())
return true ;
}
// 3) ADATTAMENTO A GEOMETRIA FINALE
if ( m_bHasShape && ( pStmShape != nullptr && pStmShape->IsValid() && pStmShape->GetTriangleCount() > 0)) {
if ( ! SubtractFinalShape( pSrf, vtTrasl, pStmShape))
return false ;
if ( pSrf->GetChunkCount() == 0 || ! pSrf->IsValid())
return true ;
}
}
// salvo una copia della superficie attuale
PtrOwner<ISurfFlatRegion> pSrf_noOpenEdge( CloneSurfFlatRegion( pSrf)) ;
if ( IsNull( pSrf_noOpenEdge))
return false ;
// 4) ESTENSIONE PER I LATI APERTI
if ( ! ModifySurfByOpenEdge( pSrf, vCrvOEFlags, vtTrasl, pStmRaw))
return false ;
// 5) SE SUPERIFICIE PRECEDENTEMENTE GIA' LAVORATA...
if ( m_dDiam_Prec > 0)
return GetNewSrfByAnotherPocketing( pSrf, pSrf_noOpenEdge, vtTrasl) ;
return pSrf->IsValid() && pSrf->GetChunkCount() != 0 ;
}
//----------------------------------------------------------------------------
bool
Pocketing::SubtractFinalShape( ISurfFlatRegion* pSfrCurr, const Vector3d& vtTrasl, const ISurfTriMesh* pStmShape)
{
// controllo dei parametri
if ( pSfrCurr == nullptr || ! pSfrCurr->IsValid() || pSfrCurr->GetChunkCount() == 0)
return false ;
// creo il piano per tagliare lo Shape allo step corrente
Point3d ptC ; pSfrCurr->GetCentroid( ptC) ;
Vector3d vtN = pSfrCurr->GetNormVersor() ;
Plane3d plCut ; plCut.Set( ptC + vtTrasl, -vtN) ;
if ( ! plCut.IsValid())
return false ;
// recupero estrusione e profondità
PtrOwner<ICurve> pCrvProp( pSfrCurr->GetLoop( 0, 0)) ;
int nProp0 = pCrvProp->GetTempProp( 0) ;
int nProp1 = pCrvProp->GetTempProp( 1) ;
Vector3d vtExtr ; pCrvProp->GetExtrusion( vtExtr) ;
double dThick ; pCrvProp->GetThickness( dThick) ;
// recupero tutte le curve della regione piana attuale da svuotare ( per ricalcolare le TmpProp)
ICRVCOMPOPOVECTOR vCrvAll ;
// riempio il vettore con le curve di Bordo del Chunk
for ( int c = 0 ; c < pSfrCurr->GetChunkCount() ; ++ c) {
PtrOwner<ICurveComposite> pCrvCompo( ConvertCurveToComposite( pSfrCurr->GetLoop( c, 0))) ;
if ( IsNull( pCrvCompo) || ! pCrvCompo->IsValid())
return false ;
vCrvAll.emplace_back( Release( pCrvCompo)) ;
}
// aggiungo poi eventuali isole
for ( int c = 0 ; c < pSfrCurr->GetChunkCount() ; ++ c) {
for ( int l = 1 ; l < pSfrCurr->GetLoopCount( c) ; ++ l) {
PtrOwner<ICurveComposite> pCrvCompo( ConvertCurveToComposite( pSfrCurr->GetLoop( c, l))) ;
if ( IsNull( pCrvCompo) || ! pCrvCompo->IsValid())
return false ;
vCrvAll.emplace_back( Release( pCrvCompo)) ;
}
}
// clono la superificie shape
PtrOwner<ISurfTriMesh> pStmShape_c( CloneSurfTriMesh( pStmShape)) ;
if ( IsNull( pStmShape_c) || ! pStmShape_c->IsValid())
return false ;
// taglio la superificie shape con il piano creato
PtrOwner<ISurfFlatRegion> pSfrShape_c( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrShape_c))
return false ;
if ( pStmShape_c->Cut( plCut, true)) {
// proietto la superficie ottenuta sul piano e converto in FlatRegion
if ( ! ProjectStmOnPlane( pStmShape_c, plCut, pSfrShape_c))
return false ;
if ( IsNull( pSfrShape_c) || ! pSfrShape_c->IsValid() || pSfrShape_c->GetChunkCount() == 0)
return true ;
pSfrShape_c->Translate( -vtTrasl) ;
}
else
return false ;
// Sottraggo alla regione di svuotatura la proeizione della superificie Shape
PtrOwner<ISurfFlatRegion> pSfrCurr_c( CloneSurfFlatRegion( pSfrCurr)) ;
if ( IsNull( pSfrCurr_c) || ! pSfrCurr_c->IsValid())
return false ;
//m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrCurr_c->Clone()) ;
//m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrShape_c->Clone()) ;
if ( pSfrCurr_c ->IsValid() && pSfrShape_c->IsValid()) {
if ( AreOppositeVectorApprox( pSfrCurr_c->GetNormVersor(), pSfrShape_c->GetNormVersor()))
pSfrShape_c->Invert() ;
if ( ! pSfrCurr_c->Subtract( *pSfrShape_c))
return false ;
}
// ricalcolo le TmpProp
SurfFlatRegionByContours sfrBC ;
// scorro tutti i Loops ottenuti e imposto loro le TmpProps
for ( int c = 0 ; c < pSfrCurr_c->GetChunkCount() ; ++ c) {
for ( int l = 0 ; l < pSfrCurr_c->GetLoopCount( c) ; ++ l) {
// recupero della Curva composita
PtrOwner<ICurveComposite> pCrvLoop( ConvertCurveToComposite( pSfrCurr_c->GetLoop( c, l))) ;
if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid())
return false ;
// se Isola allora tutta la curva è chiusa
if ( l > 0) {
for ( int u = 0 ; u < pCrvLoop->GetCurveCount() ; ++ u)
pCrvLoop->SetCurveTempProp( u, 0, 0) ;
}
// se curva esterna, setto le TmpProp mediante Overlaps
else {
Vector3d vtN = pSfrShape_c->GetNormVersor() ;
if ( ! SetTmpPropWithRawProjectedFaces( pCrvLoop, vCrvAll, vtN))
return false ;
}
// riporto le proprietà
pCrvLoop->SetTempProp( nProp0, 0) ;
pCrvLoop->SetTempProp( nProp1, 1) ;
pCrvLoop->SetExtrusion( vtExtr) ;
pCrvLoop->SetThickness( dThick) ;
// inserimento della curva
sfrBC.AddCurve( Release( pCrvLoop)) ;
}
}
// 7) ritorno la superificie ottenuta
PtrOwner<ISurfFlatRegion> pSfrFINAL( sfrBC.GetSurf()) ;
if ( IsNull( pSfrFINAL) || ! pSfrFINAL->IsValid())
return false ;
pSfrCurr->CopyFrom( pSfrFINAL) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AdjustFakeOpenEdges( ICurveComposite* pCrvCompo, const ISurfFlatRegion* pSfrOrig, const ISurfTriMesh* pStmRaw,
const Vector3d vtTrasl, bool bFromProj)
{
//if ( ! bFromProj)
return true ;
// controllo dei parametri
if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid() || pCrvCompo->GetCurveCount() == 0)
return false ;
if ( pStmRaw == nullptr) // se non c'è grezzo...
return true ;
// recupero le tmpProp, vettore estrusione e spessore
int nTmpProp0 = pCrvCompo->GetTempProp() ;
int nTmpProp1 = pCrvCompo->GetTempProp( 1) ;
Vector3d vtExtr ; pCrvCompo->GetExtrusion( vtExtr) ;
double dThick ; pCrvCompo->GetThickness( dThick) ;
// -------------------- TAGLIO IL GREZZO CON IL PIANO DEFINITO ALLO STEP ATTUALE -------------
// 1) CREAZIONE DEL PIANO
Plane3d plProj ;
Point3d ptCen ;
if ( ! pCrvCompo->GetCentroid( ptCen)) // punto
if ( ! pCrvCompo->GetStartPoint( ptCen))
return false ;
Vector3d vtNorm = pSfrOrig->GetNormVersor() ; // normale
if ( vtNorm.IsSmall())
return false ;
plProj.Set( ptCen + vtTrasl, -vtNorm) ; // così taglio tutto cià che sta nel semipiano negativo dello step attuale
if ( ! plProj.IsValid())
return false ;
// 2) TAGLIO DEL GREZZO
PtrOwner<ISurfTriMesh> pSrfRaw_clone( CloneSurfTriMesh( pStmRaw)) ;
if ( IsNull( pSrfRaw_clone))
return false ;
if ( ! pSrfRaw_clone->Cut( plProj, true))
return false ;
if ( ! pSrfRaw_clone->IsValid() || pSrfRaw_clone->GetTriangleCount() == 0)
return true ;
// -------------------------------------------------------------------------------------------
// ------- PROIEZIONE DELLE CURVE DI OGNI FACCIA DEL GREZZO RICAVATO SUL PIANO DELLA SVUOTATURA --------------
// Proietto ora le curve, delle facce della superificie ottenuta, sul piano della svuotatura
ICRVCOMPOPOVECTOR vCrvExtProj ;
PtrOwner<ICurveComposite> pCrvCompo_Clone_Trasl( CloneCurveComposite( pCrvCompo)) ;
if ( IsNull( pCrvCompo_Clone_Trasl) || ! pCrvCompo_Clone_Trasl->IsValid())
return false ;
pCrvCompo_Clone_Trasl->Translate( vtTrasl) ;
vCrvExtProj.emplace_back( CloneCurveComposite( pCrvCompo_Clone_Trasl)) ; // come indice 0
for ( int f = 0 ; f < pSrfRaw_clone->GetFacetCount() ; ++ f) {
// controllo se la faccia è quasi perpendicolare, nel caso la salto
Vector3d vtN_check ; pSrfRaw_clone->GetFacetNormal( f, vtN_check) ;
if ( abs( vtN_check * vtNorm) < EPS_ZERO)
continue ;
POLYLINEVECTOR vPL ;
pSrfRaw_clone->GetFacetLoops( f, vPL) ;
// per ogni Loop l della faccia f
for ( int l = 0 ; l < ( int) vPL.size() ; ++ l) {
PtrOwner<ICurveComposite> pCrvBorder( CreateCurveComposite()) ;
if ( IsNull( pCrvBorder) || ! pCrvBorder->FromPolyLine( vPL[l]))
return false ;
PtrOwner<ICurve> pCrvProjFacef( ProjectCurveOnPlane( *pCrvBorder, plProj)) ;
if ( IsNull( pCrvProjFacef) || ! pCrvProjFacef->IsValid())
return false ;
// controllo validità della curva ( che sia chiusa e non degenere)
double dArea = EPS_SMALL ;
Plane3d plCheck ;
if ( ! pCrvProjFacef->IsClosed() || ! pCrvProjFacef->GetArea( plCheck, dArea) || dArea <= EPS_SMALL)
continue ;
// creo la curva composita associata
PtrOwner<ICurveComposite> pCrvBorderProj_f( CreateCurveComposite()) ;
pCrvBorderProj_f->AddCurve( Release( pCrvProjFacef)) ;
vCrvExtProj.emplace_back( Release( pCrvBorderProj_f)) ;
}
}
//-------------------------------------------------------------------------------------------------------------
// ---------------- CREAZIONE DELLA VERA A PROPRIA REGIONE DI INCIDENZA, COME SOMMA DELLE
// ----------------------------- SINGOLE FLATREGIONS DI PROIEZIONE -----------------------------
PtrOwner<ISurfFlatRegion> pSrf_Proj_Ext( CreateSurfFlatRegion()) ;
if ( IsNull( pSrf_Proj_Ext))
return false ;
for ( int i = 1 ; i < ( int)vCrvExtProj.size() ; ++ i) {
PtrOwner<ISurfFlatRegion> pSrf_H( CreateSurfFlatRegion()) ;
if ( IsNull( pSrf_H))
return false ;
pSrf_H->AddExtLoop( vCrvExtProj[i]->Clone()) ;
// inverto se le normali risultano opposte
if ( pSrf_H->IsValid()) {
if ( AreOppositeVectorApprox( pSrf_H->GetNormVersor() , pSfrOrig->GetNormVersor()))
pSrf_H->Invert() ;
}
if ( pSrf_Proj_Ext->GetChunkCount() == 0)
pSrf_Proj_Ext.Set( Release( pSrf_H)) ;
else
pSrf_Proj_Ext->Add( *pSrf_H) ;
}
// creo la vera e propria regione di proiezione, sommando la proiezione esterna con la superifcie originale da svuotare
PtrOwner<ISurfFlatRegion> pSrf_Proj( CloneSurfFlatRegion( pSrf_Proj_Ext)) ;
PtrOwner<ISurfFlatRegion> pSrf_ind0( CreateSurfFlatRegion()) ;
if ( IsNull( pSrf_Proj) || ! pSrf_Proj->IsValid() || IsNull( pSrf_ind0))
return false ;
pSrf_ind0->AddExtLoop( vCrvExtProj[0]->Clone()) ;
if ( AreOppositeVectorApprox( pSrf_ind0->GetNormVersor(), pSfrOrig->GetNormVersor()))
pSrf_ind0->Invert() ;
pSrf_Proj->Add( *pSrf_ind0) ;
if ( ! bFromProj) {
//int ooo = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrf_Proj->Clone()) ;
//m_pGeomDB->SetMaterial( ooo, Color( 0.0, 1.0, 0.0, 0.3)) ;
}
// ===============================================================================================================
// Clono la superificie originaria, portandola allo step corrente
PtrOwner<ISurfFlatRegion> pSrfOrig_clone( CloneSurfFlatRegion( pSfrOrig)) ;
if ( IsNull( pSrfOrig_clone) || ! pSrfOrig_clone->IsValid())
return false ;
pSrfOrig_clone->Translate( vtTrasl) ;
if ( ! bFromProj) {
//int oooo = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrfOrig_clone->Clone()) ;
//m_pGeomDB->SetMaterial( oooo, Color( 0.0, 0.0, 0.0, 0.3)) ;
}
bool bLoopL_isChanged = false ; // flag di indetificazione di un Fake Open Edge
const int MAX_TRY = 10 ; // numero di raffinamenti massimi
int nCont = -1 ; // contatore dei raffinamenti
// OGNI VOLTA CHE INDIVIDUO UN LATO APERTO CHE IN REALTA' DEVE ESSERE CHIUSO, QUEST'ULTIMO VIENE IMPOSTATO COME
// CHIUSO ( FACENDO COSI', PERO', NON GARANTISCO CHE I LATI APERTI CORRETTI IN PRECEDENZA SIANO ANCORA
// LATI APERTI CORRETTI, DEVO RIPETERE L'ALGORITMO....)
// calcolo la regione critica
PtrOwner<ISurfFlatRegion> pSrf_critica( CloneSurfFlatRegion( pSrf_Proj)) ;
pSrf_critica->Subtract( *pSrfOrig_clone) ;
do {
++nCont ;
bLoopL_isChanged = false ;
// creo i tratti di curva omogonei ( tratti uniformi chiusi o aperti)
ICURVEPOVECTOR vCrvOpen ; ICURVEPOVECTOR vCrvClose ;
if ( ! GetHomogeneousParts( pCrvCompo_Clone_Trasl, vCrvOpen, vCrvClose, true))
return false ;
// scorro tutti i tratti aperti
for ( int t = 0 ; t < ( int)vCrvOpen.size() && !bLoopL_isChanged ; ++ t) {
// 1) ricavo il tratto aperto t-esimo
PtrOwner<ICurveComposite> pCrvCompo_t_Open( CreateCurveComposite()) ;
if ( IsNull( pCrvCompo_t_Open))
return false ;
pCrvCompo_t_Open->AddCurve( vCrvOpen[t]->Clone()) ;
// 2) Ricavo il paramtro iniziale e finale sulla curva originale
Point3d ptS ;
double dU_jump ;
pCrvCompo_t_Open->GetStartPoint( ptS) ;
pCrvCompo_Clone_Trasl->GetParamAtPoint( ptS, dU_jump) ;
// 3) effettuo l'Offset
pCrvCompo_t_Open->SetExtrusion( vtExtr) ;
OffsetCurve OffsCrv ;
if ( ! OffsCrv.Make( pCrvCompo_t_Open, m_dDiam_Prec > 0 ? 0.5 * m_dDiam_Prec + m_dOffsetR_Prec :
0.5 * m_TParams.m_dDiam + GetOffsR(), ICurve::OFF_FILLET))
return false ;
// -> se Offset non preduce nessuna curva, allora passo al tratto successivo
int nCrv_offs = OffsCrv.GetCurveCount() ;
if ( nCrv_offs == 0)
continue ;
PtrOwner<ICurve> pCrvlonger( OffsCrv.GetLongerCurve()) ;
// -> per ogni curva di Offset
while ( ! IsNull( pCrvlonger) && ! bLoopL_isChanged) {
if ( ! pCrvlonger->IsClosed() || nCrv_offs == 1) { // salto le curve "chiuse" ( a meno che non sia l'unica)
// 4) classifico la curva di offset ricavata con la supericie originale
// NB. Tutti tratti di curva che sono esterni alla superificie originale e che si trovano all'interno della
// superificie di proeizione del grezzo lo rovineranno al di fuori della superficie originale, quindi
// vanno impostati come chiusi
PtrOwner<ICurveComposite> pCrv_tOpen_Offs( CloneCurveComposite( pCrvlonger)) ;
if ( IsNull( pCrv_tOpen_Offs) || ! pCrv_tOpen_Offs->IsValid())
return false ;
if ( ! bFromProj) {
//int YE = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrv_tOpen_Offs->Clone()) ;
//m_pGeomDB->SetMaterial( YE, YELLOW) ;
}
CRVCVECTOR ccClass ;
if ( pSrf_critica->GetCurveClassification( *pCrv_tOpen_Offs, 10 * EPS_SMALL, ccClass)) {
for ( int j = 0 ; j < ( int)ccClass.size() && ! bLoopL_isChanged ; ++ j) {
if ( ccClass[j].nClass == CRVC_IN) {
// 7) se trovo una parte interna alla proeizione, allora devo ricavare la parte di curva
// originaria ( della pCrvCompo_t_Open) relativa a questo tratto e impostarla come aperta
// ... ricavo il tratto di curva
int nRealDUS = ( int)floor( ccClass[j].dParS) ;
int nRealDUE = ( int)floor( ccClass[j].dParE) ;
if ( ceil( ccClass[j].dParS) - ccClass[j].dParS < 50 * EPS_SMALL)
nRealDUS = ( int)ceil( ccClass[j].dParS) ;
if ( abs( ccClass[j].dParE - ceil( ccClass[j].dParE)) < 50 * EPS_SMALL)
nRealDUE = ( int)ceil( ccClass[j].dParE) ;
// modifico il range per evitare indici errati
nRealDUS = Clamp( nRealDUS, 0, pCrv_tOpen_Offs->GetCurveCount() - 1) ;
nRealDUE = Clamp( nRealDUE, 0, pCrv_tOpen_Offs->GetCurveCount() - 1) ;
// recupero la TempProp 0 della curva ( mi indica l'offset da chi deriva)
int nCrvStart ; pCrv_tOpen_Offs->GetCurveTempProp( nRealDUS, nCrvStart, 0) ;
-- nCrvStart ;
int nCrvEnd ; pCrv_tOpen_Offs->GetCurveTempProp( nRealDUE, nCrvEnd, 0) ;
-- nCrvEnd ;
double dUStart ; // parametro relativo iniziale
double dUEnd ; // parametro relativo finale
PtrOwner<ICurve> CIAO( pCrv_tOpen_Offs->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ;
if ( ! bFromProj) {
//int YEs = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, CIAO->Clone()) ;
//m_pGeomDB->SetMaterial( YEs, Color( 0.95, 0.0, 0.63, 1.0)) ;
}
// ------------------------------ PARAMETRO FINALE -----------------------------------
// se non sono su un raccordo ...
if ( nCrvEnd != -1) {
dUEnd = max( 0., min( nCrvEnd + ( ccClass[j].dParE - ( int)ccClass[j].dParE),
1. * pCrv_tOpen_Offs->GetCurveCount())) ;
if ( abs(( ccClass[j].dParE) - pCrv_tOpen_Offs->GetCurveCount()) < 50 * EPS_SMALL)
++ dUEnd ;
}
// se sono su un raccordo ...
else {
// cerco la prima tra le curve successive che non sia un raccordo
int nCrvToAsk = ( int)( min( ccClass[j].dParE + 1, 1. * ( pCrv_tOpen_Offs->GetCurveCount() - 1))) ;
int nCrvEndReal ;
do {
pCrv_tOpen_Offs->GetCurveTempProp( nCrvToAsk, nCrvEndReal, 0) ;
++ nCrvToAsk ;
nCrvEndReal = min( nCrvEndReal, pCrv_tOpen_Offs->GetCurveCount()) - 1 ;
} while ( nCrvEndReal == -1 && nCrvToAsk < pCrv_tOpen_Offs->GetCurveCount()) ;
if ( nCrvEndReal == -1) // se non trovo -> tratto finale in proporzione
dUEnd = pCrv_tOpen_Offs->GetCurveCount() - 1 + ( ccClass[j].dParE - ( int)ccClass[j].dParE) ;
else { // seleziono il pezzo iniziale del primo tratto trovato ...
const ICurve* pCrv_forLen = pCrv_tOpen_Offs->GetCurve( nCrvEndReal) ;
double dLen = EPS_SMALL ;
double dLenMin = 0.05 * ( m_dDiam_Prec > 0 ? 0.5 * m_dDiam_Prec : 0.5 * m_TParams.m_dDiam) ;
double dParShift = 1. ;
if ( pCrv_forLen != nullptr && pCrv_forLen->GetLength( dLen) && dLen > dLenMin)
dParShift = dLenMin / dLen ;
dUEnd = max( 0.0 , min( nCrvEndReal + 0 + dParShift, 1. * ( pCrv_tOpen_Offs->GetCurveCount() - 1))) ;
}
}
// ------------------------------ PARAMETRO INZIALE -----------------------------------
// se non sono su un raccordo ...
if ( nCrvStart != -1)
dUStart = max( 0., min( nCrvStart + ( ccClass[j].dParS - ( int)ccClass[j].dParS),
1. * ( pCrv_tOpen_Offs->GetCurveCount()))) ;
// se sono su un raccordo ...
else {
int nCrvToAsk = ( int)( max( 0., ccClass[j].dParS - 1)) ;
int nCrvStartReal ;
do {
pCrv_tOpen_Offs->GetCurveTempProp( nCrvToAsk, nCrvStartReal, 0) ;
--nCrvToAsk ;
nCrvStartReal = min( nCrvStartReal, pCrv_tOpen_Offs->GetCurveCount()) - 1 ;
} while ( nCrvStartReal == -1 && nCrvStartReal > 0) ;
if ( nCrvStartReal == -1) // se non trovo -> tratto iniziale in proporzione
nCrvStartReal = ccClass[j].dParS - ( int)ccClass[j].dParS ;
else { // seleziono il pezzo finale del primo tratto trovato ...
const ICurve* pCrv_forLen = pCrv_tOpen_Offs->GetCurve( nCrvStartReal) ;
double dLen = EPS_SMALL ;
double dLenMin = 0.05 * ( m_dDiam_Prec > 0 ? 0.5 * m_dDiam_Prec : 0.5 * m_TParams.m_dDiam) ;
double dParShift = 1. ;
if ( pCrv_forLen != nullptr && pCrv_forLen->GetLength( dLen) && dLen > dLenMin)
dParShift = dLenMin / dLen ;
dUStart = max( 0., min( nCrvStartReal + 1 - dParShift, 1. * pCrv_tOpen_Offs->GetCurveCount())) ;
}
}
// controllo...
if ( dUStart > dUEnd)
swap( dUStart, dUEnd) ;
// tratto precente
PtrOwner<ICurveComposite> pCrv_Bef( CloneCurveComposite( pCrvCompo_Clone_Trasl)) ;
// tratto successivo
PtrOwner<ICurveComposite> pCrv_Aft( CloneCurveComposite( pCrvCompo_Clone_Trasl)) ;
// tratto corrente da mettere come chiuso
PtrOwner<ICurveComposite> pCrv_curr_Close( CreateCurveComposite()) ;
// nuova curva...
PtrOwner<ICurveComposite> pCrv_New( CreateCurveComposite()) ;
if ( IsNull( pCrv_Bef) || ! pCrv_Bef->IsValid() ||
IsNull( pCrv_Aft) || ! pCrv_Aft->IsValid() ||
IsNull( pCrv_curr_Close) ||
IsNull( pCrv_New))
return false ;
// ricomposizione con tagli per non perdere le proprietà appena impostate
dUStart += dU_jump ;
dUEnd += dU_jump ;
if ( ! pCrv_Bef->TrimEndAtParam( dUStart))
pCrv_Bef->Clear() ;
if ( ! pCrv_Aft->TrimStartAtParam( dUEnd))
pCrv_Aft->Clear() ;
if ( ! IsNull( pCrv_Bef) && pCrv_Bef->IsValid())
pCrv_New->AddCurve( Release( pCrv_Bef)) ;
pCrv_curr_Close->AddCurve( pCrvCompo_Clone_Trasl->CopyParamRange( dUStart, dUEnd)) ;
for ( int uu = 0 ; uu < pCrv_curr_Close->GetCurveCount() ; ++ uu) {
pCrv_curr_Close->SetCurveTempProp( uu, 0, 0) ; // chiusa
pCrv_curr_Close->SetCurveTempProp( uu, -99, 1) ; // chiusa
}
if ( ! IsNull( pCrv_curr_Close) && pCrv_curr_Close->IsValid())
pCrv_New->AddCurve( Release( pCrv_curr_Close)) ;
else
// se la nuova curva chiusa è piccola, la ignoro...
continue ;
if ( ! IsNull( pCrv_Aft) && pCrv_Aft->IsValid())
pCrv_New->AddCurve( Release( pCrv_Aft)) ;
// controllo validità della curva, altrimenti non modifico nulla ed esco ( Avrò un chiuso)
if ( ! IsNull( pCrv_New) && pCrv_New->IsValid() && pCrv_New->IsClosed()) {
pCrvCompo_Clone_Trasl.Set( Release( pCrv_New)) ;
bLoopL_isChanged = true ;
}
}
}
}
}
pCrvlonger.Set( OffsCrv.GetLongerCurve()) ;
}
}
} while ( bLoopL_isChanged && nCont < MAX_TRY) ;
// sotituisco la curva originale, traslo e miglioro...
if ( ! IsNull( pCrvCompo_Clone_Trasl) && pCrvCompo_Clone_Trasl->IsValid() && pCrvCompo_Clone_Trasl->IsClosed()) {
pCrvCompo_Clone_Trasl->Translate( - vtTrasl) ;
pCrvCompo_Clone_Trasl->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ;
pCrvCompo->Clear() ;
pCrvCompo->CopyFrom( pCrvCompo_Clone_Trasl) ;
pCrvCompo->SetExtrusion( vtExtr) ;
pCrvCompo->SetThickness( dThick) ;
pCrvCompo->SetTempProp( nTmpProp0, 0) ;
pCrvCompo->SetTempProp( nTmpProp1, 1) ;
}
return pCrvCompo != nullptr && pCrvCompo->IsValid() && pCrvCompo->GetCurveCount() > 0 ;
}
//----------------------------------------------------------------------------
bool
Pocketing::ModifySurfByOpenEdge( ISurfFlatRegion* pSrf, ICRVCOMPOPOVECTOR& vCrvOEFlags, const Vector3d& vtTrasl,
ISurfTriMesh* pStmRaw)
{
// controllo dei parametri
if ( pSrf == nullptr || ! pSrf->IsValid() || pSrf->GetChunkCount() == 0)
return false ;
// creo la superifcie da restituire...
PtrOwner<ISurfFlatRegion> pSrfFinal( CreateSurfFlatRegion()) ;
if ( IsNull( pSrfFinal))
return false ;
// salvo un vettore contenente tutte le isole
ICRVCOMPOPOVECTOR vCrvToTIsl ;
// vettore temporaneo di curve originale
ICRVCOMPOPOVECTOR vCrvOrig_tmp ;
// per ogni Chunck della superificie ottenuta...
for ( int c = 0 ; c < pSrf->GetChunkCount() ; ++ c) {
// 1) salvo la curva esterna -> per casi ottimizzati
PtrOwner<ICurveComposite> pCrvEL( ConvertCurveToComposite( pSrf->GetLoop( c, 0))) ;
if ( IsNull( pCrvEL))
return false ;
//vCrvOrig_tmp.emplace_back( Release( pCrvEL)) ;
vCrvOEFlags.emplace_back( Release( pCrvEL)) ;
// 2) creo un vettore con le isole del Chunk ( e uno con le isole ammissibili)
ICRVCOMPOPOVECTOR vCrvIsl ;
for ( int l = 1 ; l < pSrf->GetLoopCount( c) ; ++ l) {
PtrOwner<ICurveComposite> pCrvIL( ConvertCurveToComposite( pSrf->GetLoop( c, l))) ;
if ( IsNull( pCrvIL))
return false ;
vCrvIsl.emplace_back( Release( pCrvIL)) ;
}
ICRVCOMPOPOVECTOR vCrvModIsland ;
// 3) Allargo la superificie ( curva esterna) mediante i lati aperti
bool bSomeOpen = false ;
int nProp0 = -1 ;
PtrOwner<ICurveComposite> pCrvExt( ConvertCurveToComposite( pSrf->GetLoop( c, 0))) ;
for ( int u = 0 ; u < pCrvExt->GetCurveCount() && !bSomeOpen ; ++ u) {
if ( pCrvExt->GetCurveTempProp( u, nProp0, 0) && nProp0 == 1)
bSomeOpen = true ;
}
if ( bSomeOpen) { // se trovo dei lati aperti
// 3.1) sistemo la superificie
if ( ! AdjustContourWithOpenEdges( pCrvExt, vCrvIsl, m_dDiam_Prec > 0 ? m_dDiam_Prec : m_TParams.m_dDiam,
m_dDiam_Prec > 0 ? m_dOffsetR_Prec : GetOffsR(),
m_dDiam_Prec > 0 ? m_dSideStep_Prec : GetSideStep(),
vtTrasl, pStmRaw)) {
m_pMchMgr->SetLastError( 2430, "Error in Pocketing : adjust open edges failed") ;
return false ;
}
}
// 4) aggiungo le curve alla nuova superificie
// NB Controllo se la curva si Autointerseca... alcuni lati aperti potrebbero mergiarsi
SelfIntersCurve SiC( *pCrvExt) ;
if ( SiC.GetIntersCount() > 0) {
// creo la flatRegion
SurfFlatRegionByContours SfrBC ;
SfrBC.AddCurve( pCrvExt->Clone()) ;
PtrOwner<ISurfFlatRegion> pSfrHelp( SfrBC.GetSurf()) ;
if ( IsNull( pSfrHelp) || ! pSfrHelp->IsValid())
return false ;
pCrvExt.Set( ConvertCurveToComposite( pSfrHelp->GetLoop( 0, 0))) ;
for ( int l = 1 ; l < pSfrHelp->GetLoopCount( 0) ; ++ l) {
PtrOwner<ICurveComposite> pCrvClosedIsland( ConvertCurveToComposite( pSfrHelp->GetLoop( 0, l))) ;
if ( IsNull( pCrvClosedIsland) || ! pCrvClosedIsland->IsValid())
return false ;
for ( int u = 0 ; u < pCrvClosedIsland->GetCurveCount() ; ++ u)
pCrvClosedIsland->SetCurveTempProp( u, 0, 0) ;
vCrvIsl.emplace_back( Release( pCrvClosedIsland)) ;
}
}
// 5) Controllo i bordi delle isole ottenute e modifico quelli in cui sono presenti lati aperti
for ( int i = 0 ; i < ( int)vCrvIsl.size() ; ++ i) {
bSomeOpen = false ;
nProp0 = -1 ;
PtrOwner<ICurveComposite> pCrvIsl( ConvertCurveToComposite( vCrvIsl[i]->Clone())) ;
for ( int u = 0 ; u < pCrvIsl->GetCurveCount() ; ++ u) {
if ( pCrvIsl->GetCurveTempProp( u, nProp0, 0) && nProp0 == 1)
bSomeOpen = true ;
}
if ( bSomeOpen) { // se trovo dei lati aperti
// 5.1) se l'isola è tutta aperta e trascurabile la talgo
bool bRemove = false ;
if ( ! CheckForRemovingIsland( pCrvIsl, m_dDiam_Prec > 0 ? m_dDiam_Prec + m_dOffsetR_Prec : m_TParams.m_dDiam,
bRemove))
return false ;
if ( bRemove) // se si può trascurare passo alla successiva
continue ;
// 5.2) sistemo la superificie
ICRVCOMPOPOVECTOR vCrvNULL ;
if ( ! AdjustContourWithOpenEdges( pCrvIsl, vCrvNULL, m_dDiam_Prec > 0 ? m_dDiam_Prec : m_TParams.m_dDiam,
m_dDiam_Prec > 0 ? m_dOffsetR_Prec : GetOffsR(),
m_dDiam_Prec > 0 ? m_dSideStep_Prec : GetSideStep(), vtTrasl, pStmRaw)) {
m_pMchMgr->SetLastError( 2430, "Error in Pocketing : adjust open edges failed") ;
return false ;
}
}
vCrvModIsland.emplace_back( pCrvIsl->Clone()) ;
vCrvToTIsl.emplace_back( pCrvIsl->Clone()) ;
}
// 6) Creo la nuova superificie da svuotare
// NB. I vari chunk, dopo esseresi allargati nei lati aperti, potrebbero unirsi tra loro in alcuni parti...
SurfFlatRegionByContours SfrBC_Def ;
SfrBC_Def.AddCurve( Release( pCrvExt)) ;
for ( int i = 0 ; i < ( int)vCrvModIsland.size() ; ++ i)
SfrBC_Def.AddCurve( Release( vCrvModIsland[i])) ;
PtrOwner<ISurfFlatRegion> pSrfHelp_( SfrBC_Def.GetSurf()) ;
if ( pSrfFinal->GetChunkCount() == 0)
pSrfFinal.Set( pSrfHelp_) ;
else
pSrfFinal->Add( *pSrfHelp_) ;
}
// ora che ho la superificie finale, questa potrebbe contenere più isole rispetto a quelle originarie
// ( Se la superficie, dopo intersezione e proeizione, è formata da c-Chunks e questi una volta allargati presso
// i lati aperti dalla funzione AdjustContourWithOpenEdges si sono uniti -> possono esseresi formate ulteriori isole
// aperte...) => devo togliere le isole opportune )
SurfFlatRegionByContours pSrf_noFakeIslands ;
for ( int c = 0 ; c < pSrfFinal->GetChunkCount() ; ++ c) {
// aggiungo il bordo esterno
pSrf_noFakeIslands.AddCurve( pSrfFinal->GetLoop( c, 0)) ;
for ( int l = 1 ; l < pSrfFinal->GetLoopCount( c) ; ++ l) {
PtrOwner<ICurveComposite> pCrvCompo( ConvertCurveToComposite( pSrfFinal->GetLoop( c, l))) ;
if ( IsNull( pCrvCompo))
return false ;
bool bIsRealIsland = false ;
// se l'isola attuale ha una curva che fa overlap con una delle isole originarie allora la tengo ...
for ( int is = 0 ; is < ( int)vCrvToTIsl.size() && !bIsRealIsland ; ++ is) {
for ( int u = 0 ; u < pCrvCompo->GetCurveCount() && !bIsRealIsland ; ++ u) {
const ICurve* pCrv_u = pCrvCompo->GetCurve( u) ;
if ( pCrv_u == nullptr)
return false ;
int nStat = -1 ;
if ( CheckSimpleOverlap( pCrv_u, vCrvToTIsl[is], nStat, 50 * EPS_SMALL) && nStat == 1)
bIsRealIsland = true ;
}
}
// ... ( quindi la inserisco)
if ( bIsRealIsland)
pSrf_noFakeIslands.AddCurve( Release( pCrvCompo)) ;
// altrimenti controllo se è necessaria
else {
bool bRemove = false ;
if ( ! CheckForRemovingIsland( pCrvCompo, m_dDiam_Prec > 0 ? m_dDiam_Prec + m_dOffsetR_Prec : m_TParams.m_dDiam,
bRemove))
return false ;
if ( ! bRemove)
pSrf_noFakeIslands.AddCurve( Release( pCrvCompo)) ;
}
}
}
// aggiorno la superficie originaria
pSrfFinal.Set( pSrf_noFakeIslands.GetSurf()) ;
if ( IsNull( pSrfFinal))
return false ;
// ricavo le curve originali per i casi ottimizzati
for ( int c = 0 ; c < pSrfFinal->GetChunkCount() ; ++ c) {
int nChunk_contained = 0 ;
int nIndex = -1 ;
const ISurfFlatRegion* pSfrChunk = pSrfFinal->CloneChunk( c) ;
for ( int x = 0 ; x < int( vCrvOrig_tmp.size()) ; ++x) {
CRVCVECTOR ccClass ;
if ( pSfrChunk->GetCurveClassification( *vCrvOrig_tmp[x], EPS_SMALL, ccClass)) {
bool bIsOut = false ;
for ( int j = 0 ; j < int( ccClass.size()) && !bIsOut ; ++ j)
if ( ccClass[j].nClass == CRVC_OUT)
bIsOut = true ;
if ( ! bIsOut) {
++ nChunk_contained ;
nIndex = x ;
}
}
}
//if ( nChunk_contained == 1)
//vCrvOEFlags.emplace_back( vCrvOrig_tmp[nIndex]->Clone()) ;
//else
// inserisco il loop del chunk attuale
}
pSrf->Clear() ;
pSrf->CopyFrom( pSrfFinal) ;
return pSrf->IsValid() && pSrf->GetChunkCount() > 0 ;
}
bool
Pocketing::CheckForRemovingIsland( const ICurveComposite* pCrvIslandBorder, double dOffs, bool bRemove)
{
// controllo dei parametri
// NB. La curva dell'isola gira in senso orario, quindi l'offset va fatto in positivo
if ( pCrvIslandBorder == nullptr || ! pCrvIslandBorder->IsValid() || dOffs < EPS_SMALL)
return false ;
bRemove = false ;
// controllo se l'isola è tutta aperta
for ( int u = 0 ; u < pCrvIslandBorder->GetCurveCount() ; ++ u) {
const ICurve* pCrv_u = pCrvIslandBorder->GetCurve( u) ;
if ( pCrv_u == nullptr)
return false ;
int nTmpProp0 = pCrv_u->GetTempProp( 0) ;
// se trovo una sottocurva che non è aperta, esco
if ( nTmpProp0 != 1)
return true ;
}
// tutte le curva sono aperte, effettuo un offset per vedere se l'isola è da tenere
OffsetCurve OffsCrv ;
if ( ! OffsCrv.Make( pCrvIslandBorder, dOffs, ICurve::OFF_FILLET)) {
m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ;
return false ;
}
// nel caso l'Offset sparisca, all'ora l'isola non è necessaria
if ( OffsCrv.GetCurveCount() == 0)
bRemove = true ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::IntersSurfWithRaw( ISurfFlatRegion* pSfrPock, const ISurfTriMesh* pStmRaw, const Vector3d& vtTrasl,
bool& bIsChanged, double dAreaToll, bool bInVsOut, bool bRemoveSmallRawParts,
bool bComputeOpenEdge)
{
// se funzione non necessaria, esco subito
if ( ! m_bIntersRaw)
return true ;
bIsChanged = false ;
// trasformo in Trimesh la superificie da svuotare ( per sottrazione con il grezzo)
PtrOwner<ISurfTriMesh> pStm( CloneSurfTriMesh( pSfrPock->GetAuxSurf())) ;
if ( IsNull( pStm))
return false ;
// calcolo l'area della superificie da svuotare
double dAreaBefore = 0 ;
if ( ! pStm->GetArea( dAreaBefore))
return false ;
// salvo una copia della superificie Trimesh ( nel caso in cui la sottrazione non funzioni)
PtrOwner<ISurfTriMesh> pStmCopy( CloneSurfTriMesh( pStm)) ;
if ( IsNull( pStmCopy))
return false ;
// traslo la superificie da svuotare a seconda dello step e la taglio con il grezzo
if ( ! pStm->Translate( vtTrasl) ||
! pStm->CutWithOtherSurf( *pStmRaw, bInVsOut, true)) {
pStm.Set( pStmCopy) ;
// nel caso il taglio non sia riuscito, allungo leggermente il vettore di traslazione e riprovo
if ( ! pStm->Translate(( 1 + 20 * EPS_SMALL) * vtTrasl) ||
! pStm->CutWithOtherSurf( *pStmRaw, bInVsOut, true))
return true ; // nel caso non riesca ancora, lascio la superificie da svuotare inviariata...
}
// se non ottengo nulla, allora non devo svuotare, salterò questo step (j)-esimo
if ( pStm->GetTriangleCount() == 0 || ! pStm->IsValid()) {
pSfrPock->CopyFrom( CreateSurfFlatRegion()) ;
return true ;
}
// calcolo la nuova area e la confronto con la precedente ( capisco se la superificie è cambiata o meno)
double dAreaAfter = 0 ;
bIsChanged = true ;
// recupero thickness ed estrusione dalle curve della superificie originaria
PtrOwner<ICurve> pCrvEL( pSfrPock->GetLoop( 0, 0)) ;
double dThick ; pCrvEL->GetThickness( dThick) ;
Vector3d vtExtr ; pCrvEL->GetExtrusion( vtExtr) ;
// determino il piano su cui giace la superificie originale della svuotatura ( traslato)
Plane3d plPock ;
Vector3d vtN = pSfrPock->GetNormVersor() ;
Point3d ptC ; pSfrPock->GetCentroid( ptC) ;
plPock.Set( ptC, vtN) ;
if ( ! plPock.IsValid())
return false ;
plPock.Translate( vtTrasl) ;
// recupero la FlatRegion associata a questa intersezione
PtrOwner<ISurfFlatRegion> pSrfByCurves( CreateSurfFlatRegion()) ;
if ( IsNull( pSrfByCurves) || ! GetSfrByStm( pStm, pSrfByCurves, plPock, vtExtr, dThick) ||
pSrfByCurves->GetChunkCount() == 0)
return false ;
// riporto la superificie tagliata alla quota originale
pSrfByCurves->Translate( - vtTrasl) ;
// ricalcolo i lati aperti ( se richisto)
if ( bComputeOpenEdge) {
PtrOwner<ISurfTriMesh> pStmRaw_clone( CloneSurfTriMesh( pStmRaw)) ;
if ( IsNull( pStmRaw_clone) ||
! SetOpenOrCloseEdge( pSrfByCurves, pSfrPock, pSfrPock, false, pStmRaw_clone, vtTrasl))
return false ;
}
// modifico la superficie da svuotare
pSfrPock->Clear() ;
pSfrPock->CopyFrom( pSrfByCurves) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::SetOpenOrCloseEdge( ISurfFlatRegion* pSrfTP, const ISurfFlatRegion* pSrfForCrvs, const ISurfFlatRegion* pSrfOrig,
bool bFromProj, ISurfTriMesh* pStmRaw, Vector3d vtTrasl, bool bCheckfakeOpenEdge)
{
// controllo parametri
if ( pSrfTP == nullptr || pSrfTP->GetChunkCount() == 0 ||
pSrfForCrvs == nullptr || pSrfForCrvs->GetChunkCount() == 0 ||
pSrfOrig == nullptr || pSrfOrig->GetChunkCount() == 0)
return false ;
// recupero le proprietà
PtrOwner<ICurve> pCrvEL( pSrfForCrvs->GetLoop( 0, 0)) ;
int nProp0 = pCrvEL->GetTempProp( 0) ;
int nProp1 = pCrvEL->GetTempProp( 1) ;
// creo un vettore contenente tutti i loop Esterni ed Interni della superificie originaria
int nExtLoop = pSrfForCrvs->GetChunkCount() ;
ICRVCOMPOPOVECTOR vCrvAll ;
for ( int c = 0 ; c < ( int)pSrfForCrvs->GetChunkCount() ; ++ c)
vCrvAll.emplace_back( ConvertCurveToComposite( pSrfForCrvs->GetLoop( c, 0))) ;
for ( int c = 0 ; c < ( int)pSrfForCrvs->GetChunkCount() ; ++ c)
for ( int l = 1 ; l < ( int)pSrfForCrvs->GetLoopCount( c) ; ++ l)
vCrvAll.emplace_back( ConvertCurveToComposite( pSrfForCrvs->GetLoop( c, l))) ;
// superificie da ritornare ( aggiornata)
SurfFlatRegionByContours pSrfMod ;
// NB. Se sto svuotando un Chunk della superificie, quando lo interseco con il grezzo potrei ottenere più Chunks...
// per ogni chunk della superificie da svuotare ...
for ( int c = 0 ; c < pSrfTP->GetChunkCount() ; ++ c) {
// per ogni loop ...
for ( int l = 0 ; l < pSrfTP->GetLoopCount( c) ; ++ l) {
// ricavo il loop come curva composita
PtrOwner<ICurveComposite> pCrv( GetCurveComposite( pSrfTP->GetLoop( c, l))) ;
if ( IsNull( pCrv))
return false ;
// sistemazioni varie
pCrv->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ;
for ( int i = 0 ; i < pCrv->GetCurveCount() ; ++ i) {
if ( !bFromProj) // se non derivo da una proiezione, setto di Defualt le tmp prop della curva a -1
pCrv->SetCurveTempProp( i, -1, 0) ; // setto proprietà da definire di default
for ( int j = 0 ; j < ( int)vCrvAll.size() ; ++ j) {
int nStat = 0 ;
int nCrv = pCrv->GetCurveCount() ; // # curve attuali
if ( ! SetTmpPropByOverlap( pCrv, i, vCrvAll[j], nStat, 1500 * EPS_SMALL))
return false ;
if ( nStat == 1) { // se overlap Trovato
// se ho inserito solo curve chiuse, allora evito di controllare gli altri loops,
// se ho inserito curve aperte, allora controllo con gli altri loops
// potrebbero esserci delle isole chiuse molto vicine ad un lato aperto ;
// dato che le curve in vCrvAll sono ordinate sempre dalle esterne alle interne, rischio di impostare
// aperto il lato chiuso di un'isola vicina al bordo aperto
// NB. Escludo il loop esterno ( altrimenti effetto domino)
bool bAllClosed = true ;
for ( int u = i ; u <= i + pCrv->GetCurveCount() - nCrv && bAllClosed && l != 0; ++ u) {
int nP = 0 ;
if ( pCrv->GetCurveTempProp( u, nP, 0) && nP == 1)
bAllClosed = false ;
}
if ( bAllClosed)
break ;
}
}
}
// sistemo gli errori dovuti alle tolleranze
if ( ! CheckSmallPartsForOpenEdge( pCrv))
return false ;
// controllo che le isole definite sulla superificie originale siano coerenti con le nuove isole ricavate
ICRVCOMPOPOVECTOR vAllCrv_Isl ;
for ( int i = nExtLoop ; i < ( int)vCrvAll.size() ; ++ i) {
// copio la curva corrente da analizzare
PtrOwner<ICurveComposite> pCrv_CurrIsland( CloneCurveComposite( vCrvAll[i])) ;
if ( IsNull( pCrv_CurrIsland) || !pCrv_CurrIsland->IsValid())
return false ;
bool bIsIn = false ;
// scorro tutti loop della superificie originale
for ( int cc_ = 0 ; cc_ < pSrfTP->GetChunkCount() && ! bIsIn ; ++ cc_) {
for ( int ll_ = 1 ; ll_ < pSrfTP->GetLoopCount( cc_) && ! bIsIn ; ++ ll_) {
// copio il bordo corrente
PtrOwner<ICurveComposite> pCrv_onOrig( GetCurveComposite( pSrfTP->GetLoop( cc_, ll_))) ;
if ( IsNull( pCrv_onOrig) || !pCrv_onOrig->IsValid())
return false ;
bool bIsStillIsland = true ;
// controllo se l'isola fa overlap con altre isole
for ( int u = 0 ; u < pCrv_CurrIsland->GetCurveCount() && bIsStillIsland; ++ u) {
const ICurve* pCrv = pCrv_CurrIsland->GetCurve( u) ;
if ( pCrv == nullptr || ! pCrv->IsValid())
return false ;
int nStat = 0 ;
if ( CheckSimpleOverlap( pCrv, pCrv_onOrig, nStat, 500 * EPS_SMALL) && nStat == 0)
bIsStillIsland = false ;
}
if ( bIsStillIsland) {
vAllCrv_Isl.emplace_back( CloneCurveComposite( vCrvAll[i])) ;
bIsIn = true ;
}
}
}
}
// controllo le sottocurve non definite con TmpProp = -1 ( non se sono nel caso di una proeizione)
for ( int i = 0 ; i < pCrv->GetCurveCount() && !bFromProj ; ++ i) {
int nProp ;
if ( pCrv->GetCurveTempProp( i, nProp) && nProp == -1) {
// controllo che quel lato non abbia un estremo in comune con un'isola
if ( ! CheckBoundingPointForIslands( pCrv, i, vAllCrv_Isl, 0, true)) {
pCrv->SetCurveTempProp( i, ( int)vAllCrv_Isl.size() == 0 ? 1 : 0) ;
}
}
}
// imposto le proprietà ...
pCrv->SetTempProp( nProp0, 0) ;
pCrv->SetTempProp( nProp1, 1) ;
// controllo se i lati aperti impostati sono effettivamente aperti ( se non sono nella proieizone)
if ( bCheckfakeOpenEdge)
if ( ! AdjustFakeOpenEdges( pCrv, pSrfOrig, pStmRaw, vtTrasl, bFromProj))
return false ;
// aggiungo la curva alla nuova superificie
pSrfMod.AddCurve( pCrv->Clone()) ;
}
}
pSrfTP->Clear() ;
PtrOwner<ISurfFlatRegion> pSrfF( pSrfMod.GetSurf()) ;
pSrfTP->CopyFrom( pSrfF) ;
return pSrfTP->IsValid() && pSrfTP->GetChunkCount() != 0 ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetCurveByOverlap( const ICurve* pCrv_, const ICurveComposite* pCrvCompo_, int& nInd, double dToll) {
// controllo dei parametri
if ( pCrv_ == nullptr || pCrvCompo_ == nullptr)
return false ;
nInd = -1 ;
// porto le curve nel sistema di riferimento locale ( clonandole )
PtrOwner<ICurve> pCrv( pCrv_->Clone()) ;
PtrOwner<ICurveComposite> pCrvCompo( pCrvCompo_->Clone()) ;
if ( IsNull( pCrv) || IsNull( pCrvCompo))
return false ;
// creo il vettore di curve contenute in pCrvCompo
ICURVEPOVECTOR vCrv ; vCrv.reserve( pCrvCompo->GetCurveCount()) ;
const ICurve* pMyCrv = pCrvCompo->GetFirstCurve() ;
while ( pMyCrv != nullptr) {
vCrv.emplace_back( pMyCrv->Clone()) ;
pMyCrv = pCrvCompo->GetNextCurve() ;
}
if (( int)vCrv.size() == 0)
return false ;
// vettore di punti sulla curva
PNTVECTOR vPts ;
const double nMAX = 10.0 ;
for ( int i = 0 ; i <= nMAX ; ++ i) {
double dPar = i / nMAX ;
Point3d ptC ; pCrv->GetPointD1D2( dPar, ICurve::FROM_PLUS, ptC) ;
vPts.push_back( ptC) ;
}
// controllo se una sottocurva della composita è abbastanza vicina a tutti i punti trovati
for ( int jj = 0 ; jj < ( int)vCrv.size() ; ++ jj) {
bool bOk = true ;
for ( int i = 0 ; i <= nMAX && bOk ; ++ i) {
if ( ! vCrv[jj]->IsPointOn( vPts[i], dToll)) {
bOk = false ;
}
}
if ( bOk) {
nInd = jj ;
return true ;
}
}
return false ;
}
//----------------------------------------------------------------------------
bool
Pocketing::CheckBoundingPointForIslands( ICurveComposite* pCrvCurr, int nInd, const ICRVCOMPOPOVECTOR& vCrvAll,
int nIndFI, bool bFlag)
{
// controllo dei parametri
if ( pCrvCurr == nullptr)
return false ;
const ICurve* pCrv = pCrvCurr->GetCurve( nInd) ;
Point3d ptS ; pCrv->GetStartPoint( ptS) ; // punto iniziale di pCrv
Point3d ptE ; pCrv->GetEndPoint( ptE) ; // punto finale di pCrv
int nIS = -1 ;
int nIE = -1 ;
int nStat = -1 ;
// scorro tutto il vettore di curve interne ( le isole)
for ( int i = nIndFI ; i < ( int)vCrvAll.size() ; ++ i){
if ( vCrvAll[i]->IsPointOn( ptS, 1000 * EPS_SMALL)) {
double dUS ; vCrvAll[i]->GetParamAtPoint( ptS, dUS, 1000 * EPS_SMALL) ;
dUS = ceil( dUS) ;
int nProp ; vCrvAll[i]->GetCurveTempProp( dUS, nProp, 0) ;
if ( nProp == 0)
nIS = i ;
}
if ( vCrvAll[i]->IsPointOn( ptE, 1000 * EPS_SMALL)) {
double dUE ; vCrvAll[i]->GetParamAtPoint( ptE, dUE, 1000 * EPS_SMALL) ;
dUE = ceil( dUE) ;
int nProp ; vCrvAll[i]->GetCurveTempProp( dUE, nProp, 0) ;
if ( nProp == 0)
nIE = i ;
}
if ( nIS != -1 && nIE != -1)
break ;
}
// 0 -> solo punto iniziale su Isola | 1 -> solo punto finale su Isola | 2 -> estremi su Isola/e
if ( nIS != -1 && nIE == -1)
nStat = 0 ;
else if ( nIS == -1 && nIE != -1)
nStat = 1 ;
else if ( nIS != -1 && nIE != -1)
nStat = 2 ;
else if ( nIS == -1 && nIE == -1) { // non tocca nessun'isola
pCrvCurr->SetCurveTempProp( nInd, bFlag) ; // la curva è scelta dal Flag
return true ;
}
// se la curva è troppo corta, allora non la spezzo
double dLen = 0 ;
if ( ! pCrv->GetLength( dLen))
return false ;
if ( nStat != 2 && dLen < 2 * m_TParams.m_dDiam + 100 * EPS_SMALL) {
pCrvCurr->SetCurveTempProp( nInd, 0) ; // la curva è chiusa
return true ;
}
if ( nStat == 2 && dLen < 3 * m_TParams.m_dDiam + 100 * EPS_SMALL) {
pCrvCurr->SetCurveTempProp( nInd, 0) ; // la curva è chiusa
return true ;
}
if ( nStat != 2) { // se ho un solo estremo su un'isola
double dUCut = 0.5 ;
pCrv->GetParamAtLength( nStat == 0 ? m_TParams.m_dDiam * 1.05 : dLen - m_TParams.m_dDiam * 1.05, dUCut) ;
pCrvCurr->AddJoint( nInd + dUCut) ;
pCrvCurr->SetCurveTempProp( nInd, nStat) ;
pCrvCurr->SetCurveTempProp( nInd + 1, 1 - nStat) ;
}
else { // se ho entrambi gli estremi su isole
double dUCutS = 0.5 ; double dUCutE = 0.5 ;
pCrv->GetParamAtLength( m_TParams.m_dDiam * 1.05, dUCutS) ;
pCrv->GetParamAtLength( dLen - m_TParams.m_dDiam * 1.05, dUCutE) ;
pCrvCurr->AddJoint( nInd + dUCutS) ;
pCrvCurr->SetCurveTempProp( nInd, 0) ;
pCrvCurr->AddJoint( nInd + 1 + ( 1 - dUCutS) * dUCutE) ;
pCrvCurr->SetCurveTempProp( nInd + 1, 1) ;
pCrvCurr->SetCurveTempProp( nInd + 2 , 0) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetStmRawPart( int nId, ISurfTriMesh* pSrfTMRaw, Frame3d frPocket)
{
// controllo se ho i flag abilitati
if ( ! m_bIntersRaw && ! m_bProjectRaw)
return true ;
// controllo MachManager e database geometrico
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
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) ;
// recupero il frame in cui si trova
Frame3d frRaw ;
m_pGeomDB->GetGlobFrame( nRawSolidId, frRaw) ;
if ( pGObj == nullptr)
return false ;
// controllo che sia una Trimesh
if ( pGObj->GetType() == SRF_TRIMESH) {
// Trimesh della parte p-esima
PtrOwner<ISurfTriMesh> pStmRawPart( CloneSurfTriMesh( pGObj)) ;
if ( IsNull( pStmRawPart))
return false ;
// porto la trimesh in globale
pStmRawPart->LocToLoc( frRaw, frPocket) ;
// lo aggiungo alla Trimesh complessiva
pSrfTMRaw->Add( *pStmRawPart) ;
}
}
// passo al grezzo successivo
nRawId = m_pMchMgr->GetNextRawPart( nRawId) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::OptimizeChunkOneWay( ISurfFlatRegion* pSrfOrig, ISURFFRPOVECTOR& vSrfIdeal, INTVECTOR& vIndChunk, PNTVECTOR& vPtCheck)
{
// controllo parametri
if ( pSrfOrig == nullptr || pSrfOrig->GetChunkCount() == 0)
return false ;
vSrfIdeal.clear() ;
vIndChunk.clear() ;
vPtCheck.clear() ;
// Temp prop della superificie
int nProp0 ;
int nProp1 ;
// clono la superificie passata alla funzione
PtrOwner<ISurfFlatRegion> pSrfToPock( CloneSurfFlatRegion( pSrfOrig)) ;
if ( IsNull( pSrfToPock) || pSrfToPock->GetChunkCount() == 0)
return false ;
// classifico i chunks in modo da creare delle regioni ideali; una regione ideale è formata da un chunk principale
// con tutti gli altri contenuti in esso ( in questo modo ottimizzo i percorsi per i bordi)
INTVECTOR vChunksAvailable( pSrfToPock->GetChunkCount(), 1) ;
struct PtSPtC { // struttura per punti inziali
int nInd ; // indice per vettori vPtStart, vbMidOpen, vPtMidOpen, vVtMidOut
Point3d ptC ; // punto check sulla curva
} ;
typedef vector<PtSPtC> vPtSCheck ;
vPtSCheck vNewPtStart ;
for ( int c = 0 ; c < pSrfToPock->GetChunkCount() ; ++ c) {
PtrOwner<ISurfFlatRegion> pSrfIdeal( CreateSurfFlatRegion()) ;
if ( IsNull( pSrfIdeal))
return false ;
if ( vChunksAvailable[c] == 1) { // se Chunk valido...
PtrOwner<ICurveComposite> pCrvExt( GetCurveComposite( pSrfToPock->GetLoop( c, 0))) ;
if ( IsNull( pCrvExt))
return false ;
nProp0 = pCrvExt->GetTempProp( 0) ;
nProp1 = pCrvExt->GetTempProp( 1) ;
pSrfIdeal.Set( pSrfToPock->CloneChunk( c)) ; // inserisco curva esterna
vChunksAvailable[c] = -1 ;
PtSPtC newPtSPtC ; newPtSPtC.nInd = c ; pCrvExt->GetStartPoint( newPtSPtC.ptC) ;
for ( int i = 0 ; i < int( vChunksAvailable.size()) ; ++ i) {
if ( vChunksAvailable[i] == 1) { // se chunk valido...
PtrOwner<ICurveComposite> pCrvExtC( GetCurveComposite( pSrfToPock->GetLoop( i, 0))) ;
if ( IsNull( pCrvExtC))
return false ;
IntersCurveCurve intCC( *pCrvExtC, *pCrvExt) ;
CRVCVECTOR ccClass, ccClass1 ;
intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ;
intCC.GetCurveClassification( 1, EPS_SMALL, ccClass1) ;
if (( ccClass.size() == 1 && ccClass[0].nClass == CRVC_IN) ||
( ccClass1.size() == 1 && ccClass1[0].nClass == CRVC_IN)) {
pSrfIdeal->Add( *pSrfToPock->CloneChunk( i)) ; // ... inserisco loop interno
vChunksAvailable[i] = -1 ;
if (( int)ccClass1.size() == 1 && ccClass1[0].nClass == CRVC_IN) {
pCrvExt.Set( pCrvExtC->Clone()) ;
newPtSPtC.nInd = i ; pCrvExtC->GetStartPoint( newPtSPtC.ptC) ;
i = 0 ;
}
}
}
}
vNewPtStart.push_back( newPtSPtC) ;
}
if ( pSrfIdeal->GetChunkCount() > 0) {
vSrfIdeal.emplace_back( Release( pSrfIdeal)) ;
}
}
// imposto vettore dei punti iniziali e vettore degli indici dei chunks
for ( int i = 0 ; i < ( int)vNewPtStart.size() ; ++ i){
vIndChunk.emplace_back( vNewPtStart[i].nInd) ;
vPtCheck.emplace_back( vNewPtStart[i].ptC) ;
}
// reimposto tutte le temp prop alle curve delle nuove superifici
for ( int i = 0 ; i < ( int)vSrfIdeal.size() ; ++ i) {
PtrOwner<ISurfFlatRegion> pSrfIdeal_TmpProp( CreateSurfFlatRegion()) ;
if ( IsNull( pSrfIdeal_TmpProp))
return false ;
for ( int c = 0 ; c < vSrfIdeal[i]->GetChunkCount() ; ++ c) {
for ( int l = 0 ; l < vSrfIdeal[i]->GetLoopCount( c) ; ++ l) {
PtrOwner<ICurve> pCrvCurr( vSrfIdeal[i]->GetLoop( c, l)) ;
if ( IsNull( pCrvCurr) || ! pCrvCurr->IsValid())
return false ;
pCrvCurr->SetTempProp( nProp0, 0) ;
pCrvCurr->SetTempProp( nProp1, 1) ;
if ( l == 0)
pSrfIdeal_TmpProp->AddExtLoop( Release( pCrvCurr)) ;
else
pSrfIdeal_TmpProp->AddIntLoop( Release( pCrvCurr)) ;
}
}
vSrfIdeal[i].Set( Release( pSrfIdeal_TmpProp)) ;
}
return ( vSrfIdeal.size() != 0) ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AssignContourToPath( const ICRVCOMPOPOVECTOR& vpCrvs, const Frame3d frPocket, const ISurfFlatRegion* pSrfOffs,
ICRVCOMPOPOVECTOR& vAllCrv)
{
// controllo dei parametri
if (( int) vpCrvs.size() == 0 || pSrfOffs == nullptr || pSrfOffs->GetChunkCount() == 0)
return false ;
vAllCrv.clear() ;
// estraggo i bordi esterni dei chunk della superificie
for ( int c = 0 ; c < ( int)pSrfOffs->GetChunkCount() ; ++ c) {
PtrOwner<ICurveComposite> pCrvExtChunkC( CloneCurveComposite( pSrfOffs->GetLoop( c, 0))) ;
IntersCurveCurve intCC( *vpCrvs[0], *pCrvExtChunkC) ;
CRVCVECTOR ccClass ;
intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ;
if ( ccClass.size() == 1 && ccClass[0].nClass == CRVC_IN) {
for( int l = 0 ; l < pSrfOffs->GetLoopCount( c) ; ++ l) {
PtrOwner<ICurveComposite> pCrv( CloneCurveComposite( pSrfOffs->GetLoop( c, l))) ;
pCrv->ToGlob( frPocket) ;
vAllCrv.emplace_back( Release( pCrv)) ;
}
return true ;
}
}
return false ;
}
//----------------------------------------------------------------------------
bool
Pocketing::OrderCurvesByLastPntOfPath( ICRVCOMPOPOVECTOR& vCrv, Point3d ptEnd, PNTVECTOR& vPtStart,
VCT3DVECTOR& vVtOut, BOOLVECTOR& vbMidOut)
{
if (( int)vCrv.size() == 0)
return false ;
Point3d ptRef = ptEnd ;
double dMinDist = INFINITO ;
int nIndexSwitch = -1 ;
for ( int i = -1 ; i < int( vCrv.size()) - 1 ; ++ i) {
for ( int j = i + 1 ; j < int( vCrv.size()) ; ++ j) {
Point3d ptS ; vCrv[j]->GetStartPoint( ptS) ;
if ( Dist( ptS, ptRef) < dMinDist) {
dMinDist = Dist( ptS, ptRef) ;
nIndexSwitch = j ;
}
}
if ( nIndexSwitch != i + 1) {
// scambio le curve
PtrOwner<ICurveComposite> pCrvClosest( vCrv[nIndexSwitch]->Clone()) ;
vCrv[nIndexSwitch].Set( vCrv[i+1]) ;
vCrv[i+1].Set( pCrvClosest) ;
// scambio i punti
Point3d ptStart = vPtStart[nIndexSwitch] ;
vPtStart[nIndexSwitch] = vPtStart[i+1] ;
vPtStart[i+1] = ptStart ;
// scambio i vettori
Vector3d vtOut = vVtOut[nIndexSwitch] ;
vVtOut[nIndexSwitch] = vVtOut[i+1] ;
vVtOut[i+1] = vtOut ;
// scambio i booleani
bool bOut = vbMidOut[nIndexSwitch] ;
vbMidOut[nIndexSwitch] = vbMidOut[i+1] ;
vbMidOut[i+1] = bOut ;
// scambio uscite forzate
//bool bForcedOut = vbForcedOutStart[nIndexSwitch] ;
//vbForcedOutStart[nIndexSwitch] = vbForcedOutStart[i+1] ;
//vbForcedOutStart[i+1] = bForcedOut ;
}
vCrv[i+1]->GetEndPoint( ptRef) ;
dMinDist = INFINITO ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::ProjectEdgesOnSelFace( const ISurfFlatRegion* pSfrFacet, const ISurfTriMesh* pStmOrig, INTVECTOR& vId ,
int nFacet, ISurfFlatRegion* pSfrProj, bool bIsIsland, ISurfFlatRegion* pSrfProjDanger)
{
// controllo parametri
if ( pSfrFacet == nullptr || pSfrFacet->GetChunkCount() == 0 || nFacet < 0)
return false ;
pSfrProj->Clear() ;
pSrfProjDanger->Clear() ;
// creo il piano contenente la superifice FlatRegion
Point3d ptC ; pSfrFacet->GetCentroid( ptC) ;
Vector3d vtN = pSfrFacet->GetNormVersor() ;
Plane3d plPock ; plPock.Set( ptC, vtN) ;
// scorro tutti gli indici bannati
for ( int id = 0 ; id < ( int)vId.size() ; ++ id) {
if ( vId[id] != -1 && vId[id] != nFacet &&
find( vId.begin(), vId.end(), nFacet) != vId.end()) {
// se ho un id presente nel vettore degli id ... estraggo il bordo della faccia con questo id
POLYLINEVECTOR vPL ;
pStmOrig->GetFacetLoops( vId[id], vPL) ;
PtrOwner<ICurveComposite> pCrvBorder( CreateCurveComposite()) ;
if ( IsNull( pCrvBorder))
return false ;
pCrvBorder->FromPolyLine( vPL[0]) ; // ( non considero le isole nelle facce laterali della Trimesh)
pCrvBorder->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ;
// proietto questa curva nel piano della faccia selezionata
PtrOwner<ICurve> pCrvProj( ProjectCurveOnPlane( *pCrvBorder, plPock)) ;
if ( IsNull( pCrvProj) || ! pCrvProj->IsValid())
return false ;
// creo la FlatRegion associata
PtrOwner<ISurfFlatRegion> pSfrTemp( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrTemp))
return false ;
pSfrTemp->AddExtLoop( pCrvProj->Clone()) ;
// se valida...
if ( pSfrTemp->IsValid()) {
// oriento
if ( AreOppositeVectorApprox( pSfrTemp->GetNormVersor(), vtN))
pSfrTemp->Invert() ;
// aggiorno la superificie di proeizione
if ( pSfrProj->GetChunkCount() == 0)
pSfrProj->CopyFrom( pSfrTemp) ;
else
pSfrProj->Add( *pSfrTemp) ;
// NB. Creazione della regione di proiezione per curve chiuse.
// 1) se bordo esterno, la superificie da considerare è l'unione delle superfici proeittate che presentano
// una parte interna alla superficie orginale
// 2) se bordo di un'isola, la superificie da considerare è l'unione delle superfici proiettate che presentano
// una parte esterna ad esse ( quindi fuori dall'isola)
CRVCVECTOR ccClass ;
if ( pSfrFacet->GetCurveClassification( *pCrvProj, EPS_SMALL, ccClass)) {
for ( int j = 0 ; j < ( int)ccClass.size() ; ++ j) {
if ( ccClass[j].nClass == ( bIsIsland ? CRVC_OUT : CRVC_IN)) {
if ( pSrfProjDanger->GetChunkCount() == 0)
pSrfProjDanger->CopyFrom( pSfrTemp) ;
else
pSrfProjDanger->Add( *pSfrTemp) ;
break ;
}
}
// per coerenza...
if ( bIsIsland && pSrfProjDanger->IsValid()) {
pSrfProjDanger->Invert() ;
pSrfProjDanger->Subtract( *pSfrFacet) ;
}
}
}
}
}
return pSfrProj->IsValid() && pSfrProj->GetChunkCount() > 0 ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetNewBorderByProjectionOfFaces( ISurfFlatRegion* pSrfpCompo, ICurveComposite* pCrvProj, const Point3d ptStart)
{
// controllo dei parametri
if ( pSrfpCompo == nullptr || pSrfpCompo->GetChunkCount() == 0 ||
pCrvProj == nullptr || pCrvProj->GetCurveCount() == 0)
return false ;
// creo una superificie definita dalla curva di proiezione
PtrOwner<ISurfFlatRegion> pSrfProj( CreateSurfFlatRegion()) ;
pSrfProj->AddExtLoop( pCrvProj->Clone()) ;
if ( IsNull( pSrfProj))
return false ;
if ( AreOppositeVectorApprox( pSrfpCompo->GetNormVersor(), pSrfProj->GetNormVersor()))
pSrfProj->Invert() ;
PtrOwner<ISurfFlatRegion> pSrfpCompoClone( CloneSurfFlatRegion( pSrfpCompo)) ;
if ( IsNull( pSrfpCompoClone) || pSrfpCompoClone->GetChunkCount() == 0)
return false ;
// sottraggo le due superifici
if ( ! pSrfpCompoClone->Subtract( *pSrfProj))
return false ;
pSrfpCompo->Clear() ;
pSrfpCompo->CopyFrom( pSrfpCompoClone) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetSurfByAdj( const ISurfTriMesh* pSrfOri, INTVECTOR& vBannedId, int idCurrFace)
{
vBannedId.push_back( idCurrFace) ;
INTMATRIX M ;
if ( ! pSrfOri->GetFacetAdjacencies( idCurrFace, M))
return false ;
for ( int i = 0 ; i < ( int)M[0].size() ; ++ i) {
if ( find( vBannedId.begin(), vBannedId.end(), M[0][i]) == vBannedId.end()) {
GetSurfByAdj( pSrfOri, vBannedId, M[0][i]) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetProjStmOnSfr( const ISurfFlatRegion* pSfr, const ISurfTriMesh* pStmRaw, const ISurfFlatRegion* pSrfOrig,
const int nStep, double dStep, const Vector3d& vtTrasl, ISurfFlatRegion* pSfrRawBoxProj)
{
// controllo dei parametri
if ( pSfr == nullptr || ! pSfr->IsValid() || pSfr->GetChunkCount() == 0 ||
pStmRaw == nullptr || ! pStmRaw->IsValid() || pStmRaw->GetTriangleCount() == 0)
return false ;
// copio la superficie in globale
PtrOwner<ISurfFlatRegion> pSfrPock( CloneSurfFlatRegion( pSfr)) ;
if ( IsNull( pSfrPock))
return false ;
// ------------------------- CREAZIONE DEI PIANI DI TAGLIO NEAR, FAR E DI PROIEZIONE --------------------------------------
// recupero il piano di proiezione ( piano che contiene la flatRegion)
PtrOwner<ICurveComposite> pCrv( ConvertCurveToComposite( pSfrPock->GetLoop( 0, 0))) ;
if ( IsNull( pCrv))
return false ;
Plane3d plNear, plFar, plProj ;
Point3d ptCen ;
if ( ! pCrv->GetCentroid( ptCen)) // punto
if ( ! pCrv->GetStartPoint( ptCen))
return false ;
Vector3d vtNorm = pSfrPock->GetNormVersor() ; // normale
if ( vtNorm.IsSmall())
return false ;
plNear.Set( ptCen - 2 * EPS_SMALL * vtNorm, -vtNorm ) ; // taglio tutto ciò che sta nel semipiano negativo
Vector3d vtTraslPlane = dStep * vtNorm ;
plFar.Set( ptCen + vtTraslPlane, vtNorm) ; // taglio tutto ciò che sta nel semepiano positivo
plProj.Set( ptCen, -vtNorm) ;
if ( ! plNear.IsValid() || ! plFar.IsValid() || ! plProj.IsValid())
return false ;
// ---------------------- RICERCA DELLA REGIONE DI INCIDENZA DI PROIEZIONE --------------------------
// offsetto la regione della quantità richiesta ( raggio di ricerca per eventuali proeizioni)
PtrOwner<ISurfFlatRegion> pSrf_Pock_Clone( CloneSurfFlatRegion( pSfrPock)) ;
if ( ! pSrf_Pock_Clone->Offset( m_dMaxLenRawProj, ICurve::OFF_CHAMFER))
return false ;
// per evitare memory leaks all'uscita della funzione per vCrv ( vettore di puntatori a curve const)
ICURVEPOVECTOR vCrvPO ;
CICURVEPVECTOR vCrv ;
for ( int c = 0 ; c < pSrf_Pock_Clone->GetChunkCount() ; ++ c) {
for ( int l = 0 ; l < pSrf_Pock_Clone->GetLoopCount( c) ; ++ l) {
vCrvPO.emplace_back( pSrf_Pock_Clone->GetLoop( c, l)) ;
vCrv.emplace_back( vCrvPO.back()) ;
}
}
const int STEP_HEIGHT = dStep * 1.5 ;
PtrOwner<ISurfTriMesh> pSrf_ForCuttingRaw( GetSurfTriMeshByRegionExtrusion( vCrv, vtNorm * STEP_HEIGHT)) ;
if ( IsNull( pSrf_ForCuttingRaw) || ! pSrf_ForCuttingRaw->IsValid())
return false ;
// --------------------- CREAZIONE PARTE DI GREZZO AL DI SOPRA DELLA REGIONE SI SVUOTATURA
// ----------------------------------- NELLA REGIONE DI INCIDENZA -----------------------------
// clono la Trimesh del Grezzo
PtrOwner<ISurfTriMesh> pSrfRaw_clone( CloneSurfTriMesh( pStmRaw)) ;
if ( IsNull( pSrfRaw_clone))
return false ;
// taglio la Trimesh con il piano near e il piano far
pSrfRaw_clone->Cut( plNear, true) ;
if ( pSrfRaw_clone->IsValid())
pSrfRaw_clone->Cut( plFar, true) ;
// chiudo la superificie dalla parte del piano di far
if ( ! IsNull( pSrfRaw_clone) && pSrfRaw_clone->IsValid()) {
POLYLINEVECTOR vPL ;
pSrfRaw_clone->GetLoops( vPL) ;
for ( int p = 0 ; p < ( int)vPL.size() ; ++ p) {
// controllo se questa curva è contenuta nel piano dove svuoto, nel caso quindi la salto
Plane3d plCheck ; double dArea ; Point3d ptCheck ;
if ( vPL[p].IsClosedAndFlat( plCheck, dArea)) {
if ( vPL[p].GetPointNbr() > 0 ) {
if ( vPL[p].GetFirstPoint( ptCheck)) {
double dDist = DistPointPlane( ptCheck, plNear) ;
if ( abs ( dDist) < 50 * EPS_SMALL)
continue ;
}
}
}
PtrOwner<ISurfTriMesh> pStm_SideAtFar( CreateSurfTriMesh()) ;
if ( pStm_SideAtFar->CreateByFlatContour( vPL[p])) {
Vector3d vtN ;
if ( pStm_SideAtFar->GetFacetNormal( 0, vtN) && AreOppositeVectorApprox( vtN, -plNear.GetVersN()))
pStm_SideAtFar->Invert() ;
}
pSrfRaw_clone->DoSewing( *pStm_SideAtFar) ;
}
}
// controllo validità
if ( ! pSrfRaw_clone->IsValid() || pSrfRaw_clone->GetTriangleCount() == 0)
pSrfRaw_clone.Set( CloneSurfTriMesh( pStmRaw)) ;
// considero la parte di grezzo interna alla regione di incidenza
if ( ! pSrfRaw_clone->CutWithOtherSurf( *pSrf_ForCuttingRaw, true, true))
return false ;
if ( ! pSrfRaw_clone->IsValid() || pSrfRaw_clone->GetTriangleCount() == 0) {
pSfrRawBoxProj->Clear() ;
return true ;
}
// --------------------- RIMOZIONE DELLE PARTI NON ESSENZIALI ---------------------------------
// Recupero solo la parte di TriMesh contente la superificie da svuotare
// Tagliando il grezzo posso ottenere diverse Parts, tengo solo quelle che influenzano la mia regione di svuotatura
PtrOwner<ISurfTriMesh> pStr_real( CreateSurfTriMesh()) ;
for ( int p = 0 ; p < pSrfRaw_clone->GetPartCount() ; ++ p) { // per ogni part della TriMesh
PtrOwner<ISurfTriMesh> pStm_raw_part( pSrfRaw_clone->ClonePart( p)) ;
POLYLINEVECTOR vPl ;
pStm_raw_part->GetLoops( vPl) ; // ricavo i Loops
for ( int l = 0 ; l < ( int)vPl.size() ; ++ l) {
PtrOwner<ICurveComposite> pCompo( CreateCurveComposite()) ;
pCompo->FromPolyLine( vPl[l]) ; // converto in curva composita
PtrOwner<ISurfFlatRegion> pSfr_H( CreateSurfFlatRegion()) ;
pSfr_H->AddExtLoop( Release( pCompo)) ; // creo una regione per ogni Loop
if ( ! AreSameVectorApprox( pSfr_H->GetNormVersor(), pSfrPock->GetNormVersor()))
pSfr_H->Invert() ; // se necessario inverto
for ( int c = 0 ; c < pSfrPock->GetChunkCount() ; ++ c) { // per ogni chunk della regione di svuotatura
if ( pSfr_H->GetChunkSimpleClassification( 0, *pSfrPock, c) != CCREGC_OUT) {
if ( pStr_real->GetTriangleCount() != 0)
pStr_real->Add( *Release( pStm_raw_part)) ;
else
pStr_real.Set( Release( pStm_raw_part)) ;
l = ( int)vPl.size() ;
break ;
}
}
}
}
// ------- PROIEZIONE DI OGNI FACCIA DEL GREZZO RICAVATO SUL PIANO DELLA SVUOTATURA --------------
// creo un vettore con le curve esterne
// in posizione 0 metto la curva esterna della superificie da svuoatre originale
// nelle posizioni successive inserisco le curve esterne dei chunk creati ( aperti per definizione)
ICRVCOMPOPOVECTOR vCrvExtProj ; // <---- questo vettore contiene il bordo della superificie ricavata dall'interzione
// quindi in posizione 0 ho una curva con i lati aperti/chiusi già settati
vCrvExtProj.emplace_back( GetCurveComposite( pSfr->GetLoop( 0, 0))) ;
// Clono la superificie di partenza ( per sicurezza lascio invariata quella passata alla funzione)
PtrOwner<ISurfFlatRegion> pSrf_Clone( CloneSurfFlatRegion( pSfr)) ;
if ( IsNull( pSrf_Clone) || ! pSrf_Clone->IsValid())
return false ;
// Creo la superficie che dovrò restiturire alla fine della proiezione
PtrOwner<ISurfFlatRegion> pSrf_Proj_Ext( CreateSurfFlatRegion()) ;
if ( IsNull( pSrf_Proj_Ext))
return false ;
if ( ! ProjectStmOnPlane( pStr_real, plProj, pSrf_Proj_Ext))
return false ;
if ( IsNull( pSrf_Proj_Ext) || ! pSrf_Proj_Ext->IsValid())
return true ;
for ( int c = 0 ; c < pSrf_Proj_Ext->GetChunkCount() ; ++ c) {
for ( int l = 0 ; l < pSrf_Proj_Ext->GetLoopCount( c) ; ++ l) {
PtrOwner<ICurveComposite> pCrvCompoLoop( ConvertCurveToComposite( pSrf_Proj_Ext->GetLoop( c, l))) ;
if ( IsNull( pCrvCompoLoop) || ! pCrvCompoLoop->IsValid())
return false ;
for ( int u = 0 ; u < pCrvCompoLoop->GetCurveCount() ; ++ u)
pCrvCompoLoop->SetCurveTempProp( u, 1, 0) ;
vCrvExtProj.emplace_back( Release( pCrvCompoLoop)) ;
}
}
// creo la vera e propria regione di proiezione, sommando la proiezione esterna con la superficie originale
// da svuotare
PtrOwner<ISurfFlatRegion> pSrf_Proj( CloneSurfFlatRegion( pSrf_Proj_Ext)) ;
if ( IsNull( pSrf_Proj) || ! pSrf_Proj->IsValid())
return false ;
pSrf_Proj->Add( *pSfr) ;
// controllo i loop della superificie creata ------------------------
SurfFlatRegionByContours SrfByC ;
for ( int c = 0 ; c < pSrf_Proj->GetChunkCount() ; ++ c) {
for ( int l = 0 ; l < pSrf_Proj->GetLoopCount( c) ; ++ l) {
PtrOwner<ICurve> pCrvTmp( pSrf_Proj->GetLoop( c, l)) ;
if ( IsNull( pCrvTmp) || ! pCrvTmp->IsValid() || ! pCrvTmp->IsClosed())
continue ;
double dArea = 0. ;
Plane3d plCheck = plProj ;
if ( pCrvTmp->GetArea( plCheck, dArea) && dArea < 500 * EPS_SMALL)
continue ;
SrfByC.AddCurve( Release( pCrvTmp)) ;
}
}
PtrOwner<ISurfFlatRegion> pSrf_Check( SrfByC.GetSurf()) ;
if ( ! IsNull( pSrf_Check) && pSrf_Check->IsValid())
pSrf_Proj.Set( Release( pSrf_Check)) ;
// ------------------------------------------------------------------
// --------- LA PROIEZIONE DEL GREZZO DEVE ESTENDERE LA MIA SUPERIFCIE ORIGINARIA ( DERIVANTE DALL'INTERSEZIONE) PRESSO
// I LATI APERTI DI ESSA. USO LA FUNZIONE AdjustContourWithOpenEdges FORZADO COME COLLEGAMENTI DELLE RETTE CHIUSE ------
PtrOwner<ICurveComposite> pCrvExt( CloneCurveComposite( vCrvExtProj[0])) ;
if ( IsNull( pCrvExt) || ! pCrvExt->IsValid())
return false ;
ICRVCOMPOPOVECTOR vCrvNull ;
// allargo la copia della superificie iniziale estendendola presso i lati aperti
// ( semplice AdjustContourWithOpenEdges, senza grezzo e senza isole, verrà tutto fatto in seguito)
if ( AdjustContourWithOpenEdges( pCrvExt, vCrvNull, m_dMaxLenRawProj, 0.0, 0.0, V_NULL, nullptr, true)) {
// la curva restitutita presenta i lati aperti/chiusi impostati ( all'originale si lasciano invariati i chiusi,
// gli aperrti vengono Offsettati e i raccordi sono lineari mediante rette chiuse
// ( NB. Se le rette di raccordo fossero settate aperte, rischierei di rovinare parti di grezzo al
// di fuori di lati chiusi ( tutto dipende dell'angolo di inclinazione della superificie originale rispetto
// ad ogni singola faccia del grezzo ).
PtrOwner<ISurfFlatRegion> pSrfWithOEModified( CreateSurfFlatRegion()) ;
if ( IsNull( pSrfWithOEModified))
return false ;
// sistemo le rette ottenute per allargare la superificie presso i lati aperti
pSrfWithOEModified->AddExtLoop( Release( pCrvExt)) ; // la modifico con la curva appena restituita
// ( allargata dai lati aperti)
if ( pSrfWithOEModified->IsValid()) { // se la superificie ottenuta è valida...
// ... la clono...
PtrOwner<ISurfFlatRegion> pSfrProj_Clone( CloneSurfFlatRegion( pSrf_Proj)) ;
if ( IsNull( pSfrProj_Clone) || ! pSfrProj_Clone->IsValid())
return false ;
// controllo che le normali siano compatibili
if ( AreOppositeVectorApprox( pSfrProj_Clone->GetNormVersor(), pSrfWithOEModified->GetNormVersor()))
pSfrProj_Clone->Invert() ;
// ... e Interseco la superificie di proiezione con questa nuova superificie
// NB. L'intersezione mi permette di tenere solo le parti che sono sia nella regione di incidenza che nella
// estensione della superificie originali presso i lati aperti
if ( pSfrProj_Clone->Intersect( *pSrfWithOEModified) && ! IsNull( pSfrProj_Clone) && pSfrProj_Clone->IsValid()) {
// adatto la FlatRegion con la superificie iniziale per non sbordare dai chiusi
// La superficie che ottengo rischia comunque di essere esterna a dei lati chiusi originali ( questo
// accade quando si generano dei lati aperti mediante l'intersezione con il grezzo e la regione di incidenza
// ha un raggio di ricerca molto grande... oppure quando semplicemente il grezzo contiene un'isola in cui
// una faccia è diretta verso un pezzo di chiuso della curva esterna ( infatti le rette di raccordo chiuse
// seguono la tangenza dei lati chiusi adiancenti ai tratti aperti
PtrOwner<ISurfFlatRegion> pSrfProj_Clone_Clone( CloneSurfFlatRegion( pSfrProj_Clone)) ;
if ( ! CutProjectionToFitShape( pSfrProj_Clone, pSrfOrig))
return false ;
// Recupero le TmpProp e creo la nuova superificie mediante questo loop esterno
PtrOwner<ICurve> pCrv_NewExt( pSfrProj_Clone->GetLoop( 0, 0)) ;
if ( IsNull( pCrv_NewExt) || ! pCrv_NewExt->IsValid())
return false ;
PtrOwner<ICurveComposite> pCrvCompo_NewExt( CreateCurveComposite()) ; // trasformo in composita
if ( IsNull( pCrvCompo_NewExt))
return false ;
pCrvCompo_NewExt->AddCurve( Release( pCrv_NewExt)) ;
// Imposto le temp prop
if ( pCrvCompo_NewExt->IsValid()) {
if ( ! SetTmpPropWithRawProjectedFaces( pCrvCompo_NewExt, vCrvExtProj, pSfr->GetNormVersor()) ||
! CheckSmallPartsForOpenEdge( pCrvCompo_NewExt))
return false ;
// creo la superificie finale
PtrOwner<ISurfFlatRegion> pSrfProj_Final( CreateSurfFlatRegion()) ;
if ( IsNull( pSrfProj_Final))
return false ;
pSrfProj_Final->AddExtLoop( Release( pCrvCompo_NewExt)) ;
// aggiusto la normale se necessario
if ( pSrfProj_Final->IsValid()) {
if ( AreOppositeVectorApprox( pSrfProj_Final->GetNormVersor(), pSfr->GetNormVersor()))
pSrfProj_Final->Invert() ;
}
// sostituisco questa superficie a quella passata dalla funzione ed esco
pSfrRawBoxProj->Clear() ;
pSfrRawBoxProj->CopyFrom( pSrfProj_Final) ;
return pSfrRawBoxProj->IsValid() ;
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::CutProjectionToFitShape( ISurfFlatRegion* pSrfProjected, const ISurfFlatRegion* pSrfOrig)
{
// controllo validità dei parametri
if ( pSrfProjected == nullptr || ! pSrfProjected->IsValid() || pSrfProjected->GetChunkCount() == 0 ||
pSrfOrig == nullptr || ! pSrfOrig->IsValid() || pSrfOrig->GetChunkCount() == 0)
return false ;
// ricavo i tratti tutti i possibili aperti della superificie
ICURVEPOVECTOR vCrvAllClose ;
for ( int c = 0 ; c < pSrfOrig->GetChunkCount() ; ++ c) { // per ogni Chunk c
for ( int l = 0 ; l < pSrfOrig->GetLoopCount( c) ; ++ l) { // per ogni Loop l
// estraggo la curva di bordo
PtrOwner<ICurveComposite> pCrvCompo( GetCurveComposite( pSrfOrig->GetLoop( c, l ))) ;
if ( IsNull( pCrvCompo) || ! pCrvCompo->IsValid() || pCrvCompo->GetCurveCount() == 0)
return false ;
ICURVEPOVECTOR vCrvOpen, vCrvClose ;
if ( ! GetHomogeneousParts( pCrvCompo, vCrvOpen, vCrvClose, true))
return false ;
// se nessun lato aperto, esco
if (( int)vCrvClose.size() == 0)
continue ;
else
for ( int u = 0 ; u < ( int)vCrvClose.size() ; ++ u)
vCrvAllClose.emplace_back( Release( vCrvClose[u])) ;
}
}
// se nessun lato aperto, esco
if (( int)vCrvAllClose.size() == 0)
return true ;
// trasformo la superificie di proiezione in Trimesh
PtrOwner<ISurfTriMesh> pStmProj( CloneSurfTriMesh( pSrfProjected->GetAuxSurf())) ;
if ( IsNull( pStmProj) || ! pStmProj->IsValid() || pStmProj->GetTriangleCount() == 0)
return false ;
// recupero il centroide della superificie ( o un punto generico sulla superificie)
Point3d ptC ; pSrfProjected->GetCentroid( ptC) ;
// creo una Frame con questo vettore
Frame3d frPock ; frPock.Set( ptC, pSrfOrig->GetNormVersor()) ;
if ( ! frPock.IsValid())
return true ;
// porto tutto in questo frame
ICRVCOMPOPOVECTOR vCrvClose_c ;
for ( int i = 0 ; i < ( int)vCrvAllClose.size() ; ++ i) {
PtrOwner<ICurveComposite> pCrvClose_i( CloneCurveComposite( vCrvAllClose[i])) ;
if ( IsNull( pCrvClose_i) || ! pCrvClose_i->IsValid() || pCrvClose_i->GetCurveCount() == 0)
return false ;
pCrvClose_i->ToLoc( frPock) ;
vCrvClose_c.emplace_back( Release( pCrvClose_i)) ;
}
pStmProj->ToLoc( frPock) ;
// abbasso leggermente ls superificie di proiezione per evitatare triangoli sovrapposti
pStmProj->Translate( Z_AX * 10 * EPS_SMALL) ;
// per ogni curva chiusa di bordo
for ( int i = 0 ; i < ( int)vCrvClose_c.size() ; ++ i) {
// creo la sua estrusione
PtrOwner<ISurfTriMesh> pStmClosedEdge( GetSurfTriMeshByExtrusion( vCrvClose_c[i], Z_AX * 1000, false)) ;
// controllo la validità dell'estrusione
if ( IsNull( pStmClosedEdge) || ! pStmClosedEdge->IsValid() || pStmClosedEdge->GetTriangleCount() == 0)
continue ;
// tengo una copia della trimesh della proiezione per sicurezza, nel caso il taglio non funzioni
PtrOwner<ISurfTriMesh> pStmProj_clone( CloneSurfTriMesh( pStmProj)) ;
if ( IsNull( pStmProj_clone) || ! pStmProj_clone->IsValid() || pStmProj_clone->GetTriangleCount() == 0)
return false ;
// taglio la supericie con questo lato
if ( pStmProj_clone->CutWithOtherSurf( *pStmClosedEdge, true, true) &&
! IsNull( pStmProj_clone) && pStmProj_clone->IsValid() && pStmProj_clone->GetTriangleCount() != 0)
// se il taglio funziona, sostituisco la superificie
pStmProj.Set( Release( pStmProj_clone)) ;
}
// se la superificie finale è valida...
if ( IsNull( pStmProj) || ! pStmProj->IsValid())
return true ;
// ... ricoverto La Trimesh in FlatRegione
PtrOwner<ISurfFlatRegion> pSfrProj( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrProj))
return false ;
Plane3d plPlane ; plPlane.Set( ORIG, Z_AX) ;
if ( ! GetSfrByStm( pStmProj, pSfrProj, plPlane, V_NULL, 0.))
return false ;
// la risporto in globale e sostituisco
pSfrProj->ToGlob( frPock) ;
pSrfProjected->Clear() ;
pSrfProjected->CopyFrom( pSfrProj) ;
return pSrfProjected != nullptr && pSrfProjected->IsValid() && pSrfProjected->GetChunkCount() > 0 ;
}
//----------------------------------------------------------------------------
bool
Pocketing::ProjectRaw( ISurfFlatRegion* pSrf, const Vector3d& vtTrasl,
const ISurfTriMesh* pStmRaw, int nId, const ISurfFlatRegion* pSrfOrig,
int nStep, double dStep, double dAreaToll)
{
// controllo se funzione necessaria
if ( ! m_bProjectRaw)
return true ;
// controllo dei parametri
if ( pSrf == nullptr || ! pSrf->IsValid() || pSrf->GetChunkCount() == 0 ||
pStmRaw == nullptr || ! pStmRaw->IsValid() || pStmRaw->GetTriangleCount() == 0)
return false ;
// NB. La proiezione è fatta allargando la superificie attuale di svuotatura.
// Come bordo esterno limite si utlizza la curva della FlatRegion della proiezione della parte di grezzo nel
// semipiano positivo sopra allo step attuale della svuotatura.
// 1) se un chunk non ha lati aperti, allora non serve proiettare nulla per tale chunk
BOOLVECTOR vbSkip ; // vettore di Flag per capire se un chunk va modificato o meno
bool bAllChunk_Closed = true ;
int nProp = -1 ;
for ( int c = 0 ; c < pSrf->GetChunkCount() ; ++ c) {
bool bAllClosed = true ;
PtrOwner<ICurveComposite> pCrvFC( GetCurveComposite( pSrf->GetLoop( c, 0))) ;
if ( IsNull( pCrvFC) || ! pCrvFC->IsValid())
return false ;
pCrvFC->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ;
for ( int u = 0 ; u < pCrvFC->GetCurveCount() && bAllClosed ; ++ u) {
if ( pCrvFC->GetCurveTempProp( u, nProp, 0) && nProp == 1) {
bAllClosed = false ;
bAllChunk_Closed = false ;
}
}
vbSkip.push_back( bAllClosed) ;
}
// se tutti i chunk sono chiusi, esco
if ( bAllChunk_Closed)
return true ;
// copio la superficie da modificare
PtrOwner<ISurfFlatRegion> pSrf_clone( CloneSurfFlatRegion( pSrf)) ;
if ( IsNull( pSrf_clone))
return false ;
// traslo la superificie allo step corrente
pSrf_clone->Translate( vtTrasl) ;
// superificie finale della proizione ( per tutti i chunk)
PtrOwner<ISurfFlatRegion> pSrf_Final( CreateSurfFlatRegion()) ;
if ( IsNull( pSrf_Final))
return false ;
// vettore delle superificie ricavate da ogni chunk
ISURFFRPOVECTOR vSfr_gained ;
// vettore delle isole in ogni Chunk per lo step corrente
ICRVCOMPOPOVECTOR vCrvIsl ;
// per ogni chunk della superificie originaria da svuotare
for ( int c = 0 ; c < pSrf_clone->GetChunkCount() ; ++ c) {
// inserisco l'isola nel vettore
for ( int l = 1 ; l < pSrf_clone->GetLoopCount( c) ; ++ l)
vCrvIsl.emplace_back( ConvertCurveToComposite( pSrf_clone->GetLoop( c, l))) ;
// clono il chunk c-esimo
PtrOwner<ISurfFlatRegion> pSrf_clone_ChunkC( pSrf_clone->CloneChunk( c)) ;
// NB. Nella Travi ci possono essere dei lati aperti dovuti all'allineamento di più TriMesh per una
// svuotatura lunga in una direzione, questi li considero chiusi per la proeizione...
PtrOwner<ISurfFlatRegion> pSfr_Act( CreateSurfFlatRegion()) ;
if ( IsNull( pSfr_Act))
return false ;
if ( ! CloseOpenSidesInsideRawForProjection( pSrf_clone_ChunkC, pStmRaw, pSfr_Act))
return false ;
pSrf_clone_ChunkC.Set( Release( pSfr_Act)) ;
// ricavo la FlatRegion della proiezione di ogni faccia del grezzo tagliato dal
// semipiano positivo definito dal chunk c allo step attuale ( vtTrasl)
PtrOwner<ISurfFlatRegion> pSrfOnPlPlus( CreateSurfFlatRegion()) ;
if ( IsNull( pSrfOnPlPlus) ||
! GetProjStmOnSfr( pSrf_clone_ChunkC, pStmRaw, pSrfOrig, nStep, dStep, vtTrasl, pSrfOnPlPlus))
return false ;
if ( IsNull( pSrfOnPlPlus) || ! pSrfOnPlPlus->IsValid() || pSrfOnPlPlus->GetChunkCount() == 0)
pSrfOnPlPlus.Set( pSrf_clone_ChunkC) ;
// inserisco nel vettore
vSfr_gained.emplace_back( pSrfOnPlPlus->Clone()) ;
// sommo il nuovo chunk ottenuto alla regione finale di proiezione
if ( pSrf_Final->GetChunkCount() == 0)
pSrf_Final.Set( Release( pSrfOnPlPlus)) ;
else {
// ----- Questo è un controllo di maggiore sicurezza e precisione ----------
if ( ! pSrf_Final->Add( *pSrfOnPlPlus)) {
// ricavo il piano di svuotatura, estrusione e spessore
Plane3d plPock ;
PtrOwner<ICurve> pCrvH( pSrf->GetLoop( 0, 0)) ;
if ( IsNull( pCrvH) || ! pCrvH->IsValid())
return false ;
Point3d ptC ;
if ( ! pCrvH->GetCentroid( ptC))
if ( ! pCrvH->GetStartPoint( ptC))
return false ;
Vector3d vtN = pSrf->GetNormVersor() ;
plPock.Set( ptC, vtN) ;
if ( ! plPock.IsValid())
return false ;
plPock.Translate( vtTrasl) ;
Vector3d vtExtr ; pCrvH->GetExtrusion( vtExtr) ;
double dThick ; pCrvH->GetThickness( dThick) ;
// converto le due regioni in Trimesh
PtrOwner<ISurfTriMesh> pStm1( CloneSurfTriMesh( pSrf_Final->GetAuxSurf())) ;
PtrOwner<ISurfTriMesh> pStm2( CloneSurfTriMesh( pSrfOnPlPlus->GetAuxSurf())) ;
if ( ! IsNull( pStm1) && ! IsNull( pStm2) && pStm1->IsValid() && pStm2->IsValid()) {
// controllo validità delle normali
Vector3d vtN1, vtN2 ;
if ( pStm1->GetFacetNormal( 0, vtN1) && pStm2->GetFacetNormal( 0, vtN2) &&
AreOppositeVectorApprox( vtN1, vtN2))
pStm2->Invert() ;
// creo la Zuppa di triangoli
StmFromTriangleSoup sTM_TSoup ;
sTM_TSoup.Start() ;
sTM_TSoup.AddSurfTriMesh( *Release( pStm1)) ;
sTM_TSoup.AddSurfTriMesh( *Release( pStm2)) ;
sTM_TSoup.End() ;
// ricavo la Trimesh della zuppa di triangoli
PtrOwner<ISurfTriMesh> pStmResult( sTM_TSoup.GetSurf()) ;
if ( ! IsNull( pStmResult) && pStmResult->IsValid()) {
// dalla TriMesh ricavata ne estraggo la FlatRegion
PtrOwner<ISurfFlatRegion> pSfrResult( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrResult))
return false ;
if ( GetSfrByStm( pStmResult, pSfrResult, plPock, vtExtr, dThick))
pSrf_Final.Set( Release( pSfrResult)) ;
}
}
}
// --------------------------------------------------------------------------------
}
}
// può capitare che da due Chunk distinti, mediante la proeizione questi si uniscano formandone uno solo...
// Imposto nuovamente le Temp Prop
PtrOwner<ISurfTriMesh> pStmRaw_clone( CloneSurfTriMesh( pStmRaw)) ;
PtrOwner<ISurfFlatRegion> pSrf_Final_WithOCEdge( CreateSurfFlatRegion()) ;
if ( IsNull( pSrf_Final_WithOCEdge))
return false ;
for ( int c = 0 ; c < pSrf_Final->GetChunkCount() ; ++ c) {
PtrOwner<ISurfFlatRegion> pSrfChunk_c( pSrf_Final->CloneChunk( c)) ;
if ( IsNull( pSrfChunk_c) || ! pSrfChunk_c->IsValid())
return false ;
for ( int i = 0 ; i < ( int)vSfr_gained.size() ; ++ i) {
// porto le superifici alla base della svuotatura...
pSrfChunk_c->Translate( - vtTrasl) ;
vSfr_gained[i]->Translate( - vtTrasl) ;
SetOpenOrCloseEdge( pSrfChunk_c, vSfr_gained[i], pSrfOrig, true, pStmRaw_clone,
vtTrasl, i == ( int)vSfr_gained.size() -1) ;
// ...le riporto allo step corrente
pSrfChunk_c->Translate( vtTrasl) ;
vSfr_gained[i]->Translate( vtTrasl) ;
}
if ( pSrf_Final_WithOCEdge->GetChunkCount() == 0)
pSrf_Final_WithOCEdge.Set( Release( pSrfChunk_c)) ;
else
pSrf_Final_WithOCEdge->Add( *pSrfChunk_c) ;
}
// aggiungo tutte le isole...
for ( int is = 0 ; is < ( int)vCrvIsl.size() ; ++ is)
pSrf_Final_WithOCEdge->AddIntLoop( Release( vCrvIsl[is])) ;
if ( ! IsNull( pSrf_Final_WithOCEdge) && pSrf_Final_WithOCEdge->IsValid()) {
// Controllo delle aree, se alla fine di tutto sono ancora uguali, allora esco
double dArea_orig = 0 ;
double dArea_finale = 0 ;
if ( pSrf_Final_WithOCEdge->GetArea( dArea_finale) && pSrf->GetArea( dArea_orig) && abs( dArea_orig - dArea_finale) < dAreaToll)
return true ; // esco, alla fine non ho modificato la superificie originale mediante la proiezione con il grezzo
pSrf->Clear() ;
pSrf->CopyFrom( pSrf_Final_WithOCEdge) ;
pSrf->Translate( - vtTrasl) ; // ritraslo la superificie come in origine ( alla base)
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::CloseOpenSidesInsideRawForProjection( const ISurfFlatRegion* pSfrAct, const ISurfTriMesh* pStmRaw,
ISurfFlatRegion* pSfrMod)
{
// NB. I LATI APERTI INIZIALI INTERNI AL GREZZO HANNO TmpProp0 = 1 e TmpProp1 = -2
// controllo dei parametri
if ( pSfrAct == nullptr || ! pSfrAct->IsValid() || pSfrAct->GetChunkCount() == 0)
return false ;
if ( pStmRaw == nullptr)
return true ;
else if ( ! pStmRaw->IsValid() || pStmRaw->GetTriangleCount() == 0)
return false ;
// inzialmente la nuova superficie è uguale alla precedente
pSfrMod->CopyFrom( pSfrAct) ;
// FlatRegion finale da restituire
SurfFlatRegionByContours SfrBC_Final ;
// per ogni Chunk-c
bool bIsChaned = false ; // flag per campire se qualche curva aperta è stata chiusa
for ( int c = 0 ; c < pSfrAct->GetChunkCount() ; ++ c) {
// estraggo il bordo esterno ( controllo solo quello )
PtrOwner<ICurveComposite> pCrvExt( ConvertCurveToComposite( pSfrAct->GetLoop( c, 0))) ;
if ( IsNull( pCrvExt) || ! pCrvExt->IsValid())
return false ;
// scorro tutte le curve
for ( int u = 0 ; u < pCrvExt->GetCurveCount() ; ++ u) {
// ricavo la curva u-esima
PtrOwner<ICurve> pCrv_u( pCrvExt->GetCurve( u)->Clone()) ;
if ( IsNull( pCrv_u) || ! pCrv_u->IsValid())
return false ;
// chiudo la curva u-esima solo se lato aperto ( TmpProp0 = 1) e da chiudere ( TmpProp1 = -2 )
if ( pCrv_u->GetTempProp( 0) == 1 && pCrv_u->GetTempProp( 1) == -2) {
pCrvExt->SetCurveTempProp( u, 0, 0) ; // chiudo temporaneamente
bIsChaned = true ;
}
}
// aggiungo il loopEsterno modificato
SfrBC_Final.AddCurve( Release( pCrvExt)) ;
// aggiungo eventuali isole
for ( int l = 1 ; l < pSfrAct->GetLoopCount( c) ; ++ l)
SfrBC_Final.AddCurve( pSfrAct->GetLoop( c, l)) ;
}
// se nulla è stato modificato, allora esco
if ( ! bIsChaned)
return true ;
// altrimenti, ritorno la superificie con i lati aperti interni al grezzo ( TmpProp0 = 1 e TmpProp1 = 1 ) modificati a chiusi
PtrOwner<ISurfFlatRegion> pSfrFinal( SfrBC_Final.GetSurf()) ;
if ( ! IsNull( pSfrFinal) && pSfrFinal->IsValid()) {
pSfrMod->Clear() ;
pSfrMod->CopyFrom( pSfrFinal) ;
}
return pSfrMod != nullptr && pSfrMod->IsValid() && pSfrMod->GetChunkCount() != 0 ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AjustCurveForProjRawOnFace( const ICurveLine* pL1, ICurveLine* pL2, const ICurveComposite* pCrvBorder,
ICurveComposite* pCompo, int nStat, PNTVECTOR vPtTan, ISurfFlatRegion* pSrfProjRaw)
{
Point3d ptS, ptJ1A, ptJ1B, ptJ2A, ptJ2B ;
// controllo parametri
if ( pCrvBorder == nullptr || pCrvBorder->GetCurveCount() == 0 || ! pCrvBorder->IsValid() ||
pCompo == nullptr || pCompo->GetCurveCount() == 0 || ! pCompo->IsValid() ||
pSrfProjRaw == nullptr || ! pSrfProjRaw->IsValid() || pSrfProjRaw->GetChunkCount() == 0 ||
! pCompo->GetStartPoint( ptS))
return false ;
// controllo nel caso di rette valide che la loro intersezione non sia dentro alla proiezione del grezzo
bool bIntersInside = false ;
Point3d ptInt ;
if ( nStat == 0) {
IntersCurveCurve intCC( *pL1, *pL2) ;
if ( intCC.GetIntersCount() > 0) {
IntCrvCrvInfo aInfo ;
if ( intCC.GetIntCrvCrvInfo( 0, aInfo)) {
DistPointSurfTm dPStm( aInfo.IciA[0].ptI, *pSrfProjRaw->GetAuxSurf()) ;
double dDist ;
if ( dPStm.GetDist( dDist) && dDist < 50 * EPS_SMALL) {
bIntersInside = true ;
ptInt = aInfo.IciA[0].ptI ;
}
}
}
}
// paramentro per gestione casi degeneri
switch ( nStat)
{
case 0 : // le rette sono entrambe valide
if ( ! pL1->GetStartPoint( ptJ1A) || ! pL1->GetEndPoint( ptJ1B) ||
! pL2->GetStartPoint( ptJ2A) || ! pL2->GetEndPoint( ptJ2B))
return false ;
break ;
case 1 : // solo la prima retta è degenere ad un punto
ptJ1A = vPtTan[0] ;
ptJ1B = vPtTan[0] ;
if( ! pL2->GetStartPoint( ptJ2A) || ! pL2->GetEndPoint( ptJ2B))
return false ;
break ;
case 2 : // solo la seconda retta è degenere ad un punto
ptJ2A = vPtTan[1] ;
ptJ2B = vPtTan[1] ;
if( ! pL1->GetStartPoint( ptJ1A) || ! pL1->GetEndPoint( ptJ1B))
return false ;
break ;
case 3 : // entrambe le rette sone degeneri ad un punto
if( AreSamePointApprox( vPtTan[0], vPtTan[1])) // tutti punti coicidenti, non cambio nulla della pCompo
return true ;
ptJ1A = vPtTan[0] ;
ptJ1B = vPtTan[0] ;
ptJ2A = vPtTan[1] ;
ptJ2B = vPtTan[1] ;
break ;
default:
break ;
}
if ( bIntersInside ) { // caso C)
double dU ;
pL1->GetParamAtPoint( ptInt, dU, EPS_SMALL) ;
PtrOwner<ICurveLine> pL1New( GetCurveLine( pL1->CopyParamRange( 0, dU))) ; // segmento retta 1
pL2->GetParamAtPoint( ptInt, dU, EPS_SMALL) ;
PtrOwner<ICurveLine> pL2New( GetCurveLine( pL2->CopyParamRange( 0, dU))) ; // segmento retta 2
pCompo->GetParamAtPoint( ptJ1A, dU) ;
PtrOwner<ICurveComposite> pCrvA( GetCurveComposite( pCompo->CopyParamRange( 0, dU))) ; // tratto curva interna iniziale
pCompo->GetParamAtPoint( ptJ2A, dU) ;
// tratto curva interna finale
PtrOwner<ICurveComposite> pCrvB( GetCurveComposite( pCompo->CopyParamRange( dU, dU < EPS_SMALL ? .0 : pCompo->GetCurveCount()))) ;
if( dU < EPS_SMALL)
pCrvB.Set( CreateCurveComposite()) ;
pCompo->Clear() ;
pCompo->AddCurve( Release( pCrvA)) ;
pCompo->AddCurve( Release( pL1New)) ;
pL2New->Invert() ;
pCompo->AddCurve( Release( pL2New)) ;
pCompo->AddCurve( Release( pCrvB)) ;
return pCompo->IsValid() && pCompo->IsClosed() ;
}
// controllo validità dei punti sul contorno esterno ( se le rette non toccano, allora non modifico nulla ed esco)
if ( ! pCompo->IsPointOn( ptJ1A, EPS_SMALL) ||
! pCompo->IsPointOn( ptJ2A, EPS_SMALL) ||
! pCrvBorder->IsPointOn( ptJ1B, EPS_SMALL) ||
! pCrvBorder->IsPointOn( ptJ2B, EPS_SMALL))
return true ;
// copio il bordo esterno
PtrOwner<ICurveComposite> pCrvExt( CloneCurveComposite( pCrvBorder)) ;
if ( IsNull( pCrvExt))
return false ;
// ricavo il tratto da aggiungere alla curva interna
double dUS = 0 ; double dUE = 0 ;
pCrvExt->GetParamAtPoint( ptJ1B, dUS) ;
pCrvExt->ChangeStartPoint( dUS) ;
pCrvExt->GetParamAtPoint( ptJ2B, dUE, EPS_SMALL) ;
PtrOwner<ICurveComposite> pCrvBorderPart( GetCurveComposite( pCrvExt->CopyParamRange( 0, dUE))) ;
if ( IsNull( pCrvBorderPart) || ! pCrvBorderPart->IsValid() || pCrvBorderPart->GetCurveCount() == 0)
return false ;
// setto aperte tutte le curve del bordo sulla curva esterna
for ( int i = 0 ; i < ( int)pCrvBorderPart->GetCurveCount() ; ++ i)
pCrvBorderPart->SetCurveTempProp( i, 1) ;
// ricompongo la curva interna
pCompo->GetParamAtPoint( ptJ1A, dUE) ;
PtrOwner<ICurveComposite> pCrvA( GetCurveComposite( pCompo->CopyParamRange( 0, dUE))) ;
pCompo->GetParamAtPoint( ptJ2A, dUS) ;
PtrOwner<ICurveComposite> pCrvB( GetCurveComposite( pCompo->CopyParamRange( dUS, dUS < EPS_SMALL ? .0 : pCompo->GetCurveCount()))) ;
if ( dUS < EPS_SMALL)
pCrvB.Set( CreateCurveComposite()) ;
PtrOwner<ICurveComposite> pCrvInt( CreateCurveComposite()) ;
if ( IsNull( pCrvInt))
return false ;
pCrvInt->AddCurve( Release( pCrvA)) ; // aggiungo il primo tratto di curva interna
if ( nStat == 0 || nStat == 2)
pCrvInt->AddCurve( pL1->Clone()) ; // aggiungo il primo segmento ( se valido )
pCrvInt->AddCurve( Release( pCrvBorderPart)) ; // aggiungo il tratto di curva esterno
if ( nStat == 0 || nStat == 1) {
pL2->Invert() ;
pCrvInt->AddCurve( pL2->Clone()) ; // aggiungo il secondo segmento ( se valido )
}
pCrvInt->AddCurve( Release( pCrvB)) ; // aggiungo il secondo tratto di curva interna
// torno al punto iniziale originale
pCrvInt->GetParamAtPoint( ptS, dUS, EPS_SMALL) ;
pCrvInt->ChangeStartPoint( dUS) ;
// ritorno la nuova curva pCompo
pCompo->Clear() ;
pCompo->AddCurve( Release( pCrvInt)) ;
return pCompo->IsValid() && pCompo->IsClosed() ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetParamForPtStartOnEdge( const ICurve* pCrvCheck, const ICurveComposite* pCrvCompo,
const ICRVCOMPOPOVECTOR& vOtherCrv, double& dPar)
{
// ==================== INFO ================================================================
// pCrvCheck -> sottocurva di pCrvCompo su cui cercare il parametro ideale per ingresso
// vOtherCrv -> tutte le altre curve che non devono essere intersecate durante l'ingresso
// ( questo vettore è stato riempito con tutti loop della superificie da
// lavorare, i quali Offset non hanno generato alcuna curva di pCrvCheck )
// ==========================================================================================
// controllo dei parametri
if ( pCrvCheck == nullptr || ! pCrvCheck->IsValid() ||
pCrvCompo == nullptr || ! pCrvCompo->IsValid() || pCrvCompo->GetCurveCount() == 0)
return false ;
// clono le curve
PtrOwner<ICurve> pCrv( pCrvCheck->Clone()) ;
PtrOwner<ICurveComposite> pCompo( CloneCurveComposite( pCrvCompo)) ;
if ( IsNull( pCrv) || IsNull( pCompo))
return false ;
ICRVCOMPOPOVECTOR vCrvNoInters ;
for ( int i = 0 ; i < ( int)vOtherCrv.size() ; ++ i)
vCrvNoInters.emplace_back( ConvertCurveToComposite( vOtherCrv[i]->Clone())) ;
// ricavo l'estrusione della curva composita
Vector3d vtExtr ;
if ( ! pCompo->GetExtrusion( vtExtr))
vtExtr = Z_AX ;
// ricavo il centroide o il punto iniziale della curva composita
Point3d ptCen ;
if ( ! pCompo->GetCentroid( ptCen))
if ( ! pCompo->GetStartPoint( ptCen))
return false ;
// creo un frame locale per creare l'ombra del tool e intersecarla con la curva
Frame3d frLoc ;
frLoc.Set( ptCen, vtExtr) ;
// porto le curve in questo sistema di riferimento
pCrv->ToLoc( frLoc) ;
pCompo->ToLoc( frLoc) ;
for ( int i = 0 ; i < ( int)vCrvNoInters.size() ; ++i)
vCrvNoInters[i]->ToLoc( frLoc) ;
// fisso il diametro del tool ( più grande per sicurezza )
double dDiam = m_TParams.m_dDiam * 2.15 + 2 * GetOffsR() + 5 * EPS_SMALL ;
double dLen ;
if ( ! pCrv->GetLength( dLen))
return false ;
double dSubArc = -1 ;
if ( pCrv->GetType() == CRV_ARC) {
PtrOwner<ICurveArc> pCrvArc( GetCurveArc( pCrv->Clone())) ;
if ( IsNull( pCrvArc) || ! GetCoeffLinArc( pCrvArc, dDiam, dSubArc))
return false ;
}
double dDiv = dSubArc < 0 ? dDiam : dSubArc ;
double dMaxInt = floor( dLen / dDiv) ;
//if ( dMaxInt < EPS_SMALL)
// return false ;
int nDen = 2 ; // intervalli in cui suddivido la curva
dMaxInt = max( 2.0, dMaxInt) ; // così se entra una volta controllo sempre dParT = 0.5
while ( nDen < dMaxInt + EPS_SMALL) { // EPS_SMALL per comprendere l'uguaglianza
for ( int i = 1 ; i < nDen ; ++i) {
if ( int( i % nDen) == 0)
continue ;
double dNum = 1.0 * i ;
double dParT = dNum / nDen ;
Point3d ptTest ;
Vector3d vtPerpIn ;
if ( pCrv->GetPointD1D2( dParT, ICurve::FROM_PLUS, ptTest, &vtPerpIn)) {
PtrOwner<ICurveComposite> pCompoClone( CloneCurveComposite( pCompo)) ;
if ( IsNull( pCompoClone))
return false ;
double dU ;
pCompoClone->GetParamAtPoint( ptTest, dU) ;
pCompoClone->ChangeStartPoint( dU) ;
if ( pCrv->GetTempProp() == 0) {
// se la curva è chiusa sposto il centro verso l'interno.
// Devo essere sicuro di essere su una curva di Offset interno, altrimenti potrebbe essere valido
// il punto trovato, però facendo poi il primo offeset tale punto potrebbe diventare un punto
// di convergenza tra più chunks...
vtPerpIn.Normalize() ;
vtPerpIn.Rotate( Z_AX, 0, 1) ; // cos( pi/2) = 0, sin( pi/2) = 1
vtPerpIn *= (( m_TParams.m_dDiam + GetOffsR() + 50 * EPS_SMALL)) ;
ptTest = ptTest + vtPerpIn ;
}
// creo una circonferenza ( ombra del tool ) centrata su ptTest
PtrOwner<ICurveArc> pCrvToolShape( CreateCurveArc()) ;
pCrvToolShape->Set( ptTest, Z_AX, 0.5 * dDiam) ;
if ( ! pCrvToolShape->IsValid())
return false ;
// interseco la curva composita con l'ombra del tool
CRVCVECTOR ccClass ;
IntersCurveCurve intCC( *pCompoClone, *pCrvToolShape) ;
if ( intCC.GetCurveClassification( 0, EPS_SMALL, ccClass)) {
// se ho solo due intersezioni, controllo di non intersecare isole ( In-Out-In)
if ( int( ccClass.size() == 3)) {
bool bOk = true ;
for ( int j = 0 ; j < ( int)vCrvNoInters.size() && bOk ; ++ j) {
IntersCurveCurve intCCI( *vCrvNoInters[j], *pCrvToolShape) ;
if ( intCCI.GetCurveClassification( 0, EPS_SMALL, ccClass)) {
if (( int)ccClass.size() > 1)
bOk = false ;
}
else
return false ;
}
if ( bOk) {
dPar = dParT ;
return true ;
}
}
}
else
return false ;
}
}
++nDen ;
}
return false ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetCoeffLinArc( const ICurveArc* pArc, double dDiam, double& dSubArc) {
// controllo parametri
if ( pArc == nullptr || ! pArc->IsValid())
return false ;
Point3d ptMid ;
if ( ! pArc->GetMidPoint( ptMid))
return false ;
// creo l'ombra del tool nel punto medio
PtrOwner<ICurveArc> pCrvTool( CreateCurveArc()) ;
pCrvTool->Set( ptMid, Z_AX, dDiam) ;
if ( ! pCrvTool->IsValid())
return false ;
IntersCurveCurve intCC( *pArc, *pCrvTool) ;
CRVCVECTOR ccClass ;
if( intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) && ( int)ccClass.size() == 3 && ccClass[1].nClass == CRVC_IN) {
Point3d ptS, ptE ;
pCrvTool->GetPointD1D2( ccClass[1].dParS, ICurve::FROM_MINUS, ptS) ;
pCrvTool->GetPointD1D2( ccClass[1].dParE, ICurve::FROM_PLUS, ptE) ;
Vector3d vtS = ptS - pArc->GetCenter() ;
Vector3d vtE = ptE - pArc->GetCenter() ;
double dTheta ;
vtS.GetAngle( vtE, dTheta) ;
dTheta = abs( dTheta) ;
dSubArc = pArc->GetRadius() * DEGTORAD * dTheta ;
}
else
return false ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::SetBetterPtStartForSubChunks( ICurveComposite* pCrvOffsAct, const ISurfFlatRegion* pSrfToWork,
Point3d& ptStart, Vector3d& vtMidOut, bool& bMidOut)
{
// ============================= INFO ==============================================================
// pCrvOffsAct -> Curva di Offset su cui cercare ptStart, vtMidOut, bMidOpen
// pSrfToWork -> Superificie originaria da lavorare
// ( questa superificie ha i flag di lati aperti/chiusi settati nei loops)
// =================================================================================================
// controllo dei parametri
if ( pCrvOffsAct == nullptr || ! pCrvOffsAct->IsValid() || pCrvOffsAct->GetCurveCount() == 0 ||
pSrfToWork == nullptr || ! pSrfToWork->IsValid() || pSrfToWork->GetChunkCount() != 1)
return false ;
// clono le curva su cui devo entrare
PtrOwner<ICurveComposite> pCrv( CloneCurveComposite( pCrvOffsAct)) ;
if ( IsNull( pCrv))
return false ;
bool bSomeOpen = false ; // flag per presenza di lati aperti
// creo un vettore di Loops della superificie, ordinati
ICRVCOMPOPOVECTOR vCrvLoops ;
for ( int l = 0 ; l < pSrfToWork->GetLoopCount( 0) ; ++ l)
vCrvLoops.emplace_back( ConvertCurveToComposite( pSrfToWork->GetLoop( 0, l))) ;
// creo un vettore di indici. Questi indici si riferiscono alle posizioni di vCrvLoops i quali offset
// hanno generato delle curve sulla pCrv ( curva da cui devo entrare )
INTVECTOR vIndex ;
// scorro tutte le curve presenti in pCrv ( curva da cui devo entrare )
for ( int i = 0 ; i < ( int)pCrv->GetCurveCount() ; ++ i) {
// nProp0 -> #curva il cui Offset ha generato la curva i-esima di pCrv
int nProp0 ; pCrv->GetCurveTempProp( i, nProp0, 0) ;
// nProp1 -> #loop che contiene la curva espressa in nProp0
int nProp1 ; pCrv->GetCurveTempProp( i, nProp1, 1) ;
if ( nProp0 > 0) { // se questa curva non è un "raccordo" di Offset
// controllo per maggiore sicurezza che effettivamente nProp1 sia un indice valido per il vettore dei Loops e
// che nProp0 non sia maggiore del numero di curve del loop nProp1-esimo del vettore dei Loops della pSrfToWork
if ( nProp1 >= 0 && nProp1 < ( int)vCrvLoops.size() && nProp0 < vCrvLoops[nProp1]->GetCurveCount()) {
// aggiorno il vettore di indici ...
if ( find( vIndex.begin(), vIndex.end(), nProp1) == vIndex.end())
vIndex.push_back( nProp1) ;
// aggiorno la proprietà della curva da cui devo entrare
int nTempProp ; vCrvLoops[nProp1]->GetCurveTempProp( nProp0 - 1, nTempProp, 0) ;
pCrv->SetCurveTempProp( i, nTempProp, 0) ;
// se la curva è aperta, aggiorno il Flag
if ( nTempProp == 1 && ! bSomeOpen)
bSomeOpen = true ;
}
else
pCrv->SetCurveTempProp( i, 0, 0) ;
}
else
pCrv->SetCurveTempProp( i, 1, 0) ; // <- tmp prop = 0
}
// cambio il punto iniziale della curva all'inizio del lato aperto più lungo ( se presente)
double dLenMax = EPS_SMALL ;
int nCrvForMax = 0 ;
if ( bSomeOpen) {
for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) {
int nTmpProp = 0 ;
double dLenAct = EPS_SMALL ;
if ( pCrv->GetCurveTempProp( u, nTmpProp, 0) && nTmpProp == 1 &&
pCrv->GetCurve( u)->GetLength( dLenAct) && dLenAct > dLenMax) {
dLenMax = dLenAct ;
nCrvForMax = u ;
}
}
pCrv->ChangeStartPoint( nCrvForMax) ;
}
// creo un vettore con tutti i Loops della pSwfToWork per i quali, mediante l'Offset, non hanno
// generato alcuna curva presente nella pCrv ( quella da cui devo entrare )
ICRVCOMPOPOVECTOR vOtherCrv ;
for ( int i = 0 ; i < ( int)vCrvLoops.size() ; ++ i) {
bool bOk = true ;
for ( int j = 0 ; j < ( int)vIndex.size() && bOk ; ++ j) {
if ( i == vIndex[j])
bOk = false ;
}
if ( bOk)
vOtherCrv.emplace_back( ConvertCurveToComposite( vCrvLoops[i]->Clone())) ;
}
// cerchiamo un punto valido per l'entrata ...
bMidOut = false ;
if ( bSomeOpen) // se ho dei lati aperti, cerco il più lungo
bMidOut = GetParamOnOpenSide( pCrv, vOtherCrv, ptStart, vtMidOut) ;
if ( bMidOut) { // se ho trovato e valido, allora imposto il punto inziale trovato
const double LEN_OUT = 5 ;
double dPar ; int nFlag ;
bMidOut = ( DistPointCurve( ptStart + LEN_OUT * vtMidOut, *pCrv).GetParamAtMinDistPoint( 0, dPar, nFlag)
&& pCrv->ChangeStartPoint( dPar)) ;
}
if ( ! bMidOut) // alla peggio, ordino i lati lunghi per lunghezza e cerco un'entrata valida
AdjustContourStart( pCrv, vOtherCrv, true) ;
// ora che ho deciso quale sia il punto iniziale, lo imposto effettivamente sulla curva di Offset passata alla funzione
double dUS ;
pCrv->GetStartPoint( ptStart) ;
pCrvOffsAct->GetParamAtPoint( ptStart, dUS) ;
pCrvOffsAct->ChangeStartPoint( dUS) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AdjustAngleForProjectedFace( const ISurfFlatRegion* pSrfFaceT, ICurveComposite* pCrvEdgeBorder, double dAngle)
{
// W.I.P
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::CheckSimpleOverlap( const ICurve* pCrv, const ICurveComposite* pCrvOri, int& nStat, double dToll)
{
// controllo dei parametri
if (( pCrv == nullptr || pCrvOri == nullptr || dToll < EPS_SMALL))
return false ;
nStat = 1 ; // 0 -> no overlap | 1 -> overlap
// controllo se una sottocurva della composita è abbastanza vicina a tutti i punti trovati
const double nMAX = 10.0 ;
for ( int i = 0 ; i <= nMAX ; ++i) {
double dPar = i / nMAX ;
Point3d ptC ; pCrv->GetPointD1D2( dPar, ICurve::FROM_PLUS, ptC) ;
if ( ! pCrvOri->IsPointOn( ptC, dToll)) {
nStat = 0 ;
return true ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::SetTmpPropByOverlap( ICurveComposite* pCrv_, int nInd, const ICurveComposite* pCrvOri, int& nStat,
double dToll)
{
// controllo dei parametri
if (( pCrv_ == nullptr || pCrvOri == nullptr || nInd < 0 || nInd > pCrv_->GetCurveCount() || dToll < EPS_SMALL))
return false ;
nStat = 1 ; // 0 -> no overlap | 1 -> overlap | 2 -> undefinded
// ricavo la curva da controllare
PtrOwner<ICurveComposite> pCrv( GetCurveComposite( pCrv_->CopyParamRange( nInd, nInd + 1))) ;
if ( IsNull( pCrv))
return false ;
// controllo se la curva fa overlap
if ( ! CheckSimpleOverlap( pCrv, pCrvOri, nStat, dToll))
return false ;
if ( nStat == 0)
return true ;
// ricavo i parametri sulla curva originale di vicinanza
double dUS = 0 ; double dUE = 0 ;
Point3d ptS ; pCrv->GetStartPoint( ptS) ;
Point3d ptE ; pCrv->GetEndPoint( ptE) ;
pCrvOri->GetParamAtPoint( ptS, dUS, dToll) ;
pCrvOri->GetParamAtPoint( ptE, dUE, dToll) ;
// controllare questa funzione
int nRealDUS = ( int)floor( dUS) ;
int nRealDUE = ( int)ceil( dUE) ;
if ( ceil( dUS) - dUS < EPS_SMALL)
nRealDUS = ( int)ceil( dUS) ;
if ( dUE - floor( dUE) < EPS_SMALL)
nRealDUE = ( int)floor( dUE) ;
if ( nRealDUS == pCrvOri->GetCurveCount())
nRealDUS = 0 ;
// controllo subito se tocco più curve sulla originale con stesse temp prop
bool bHasAllSameProp = true ;
int nProp_prec ; pCrvOri->GetCurveTempProp( nRealDUS, nProp_prec, 0) ;
for ( int u = nRealDUS + 1 ; u < nRealDUE && bHasAllSameProp ; ++ u) {
int nProp_act ;
pCrvOri->GetCurveTempProp( u, nProp_act, 0) ;
if ( nProp_prec != nProp_act)
bHasAllSameProp = false ;
}
if ( bHasAllSameProp) {
int nCrv = nRealDUS ;
int nProp0 = 0 ; pCrvOri->GetCurveTempProp( nCrv, nProp0, 0) ;
int nProp1 = 0 ; pCrvOri->GetCurveTempProp( nCrv, nProp1, 1) ;
pCrv_->SetCurveTempProp( nInd, nProp0, 0) ;
pCrv_->SetCurveTempProp( nInd, nProp1, 1) ;
return true ;
}
// copio le sottocurve toccate
PtrOwner<ICurveComposite> pCrvOriRange( CloneCurveComposite( pCrvOri)) ;
if ( ! pCrvOriRange->TrimStartEndAtParam( floor( dUS), ceil( dUE)))
pCrvOriRange->Clear() ;
if ( ! pCrvOriRange->IsValid()) {
nStat = 2 ;
return true ;
}
// curva finale da resitutire
PtrOwner<ICurveComposite> pCrvFinal( CreateCurveComposite()) ;
if ( IsNull( pCrvFinal))
return false ;
// per ogni sottocurva...
double dUProjS = 0 ; double dUProjE = 0 ;
for ( int u = 0 ; u < pCrvOriRange->GetCurveCount() ; ++ u) {
Point3d ptCrvOriE ;
pCrvOriRange->GetPointD1D2( u + 1, ICurve::FROM_MINUS, ptCrvOriE) ;
if ( u == 0)
dUProjS = 0 ;
else
dUProjS = dUProjE ;
if ( u == pCrvOriRange->GetCurveCount() - 1)
dUProjE = 1 ;
else
pCrv->GetParamAtPoint( ptCrvOriE, dUProjE, dToll) ;
PtrOwner<ICurveComposite> pCrvRange( GetCurveComposite( pCrv->CopyParamRange( dUProjS, dUProjE))) ;
if ( ! IsNull( pCrvRange) && pCrvRange->IsValid()) {
int nProp0 = 0 ; pCrvOriRange->GetCurveTempProp( u, nProp0, 0) ;
int nProp1 = -1 ; pCrvOriRange->GetCurveTempProp( u, nProp1, 1) ;
pCrvRange->SetCurveTempProp( 0, nProp0, 0) ;
pCrvRange->SetCurveTempProp( 0, nProp1, 1) ;
pCrvFinal->AddCurve( Release( pCrvRange)) ;
}
else {
nStat = 2 ;
return true ;
}
}
// controllo che la curva ottenuta sia valida ...
if ( ! IsNull( pCrvFinal) && pCrvFinal->GetCurveCount() > 0 && pCrvFinal->IsValid()) {
Point3d ptSCheck ; Point3d ptECheck ;
pCrvFinal->GetStartPoint( ptSCheck) ;
pCrvFinal->GetEndPoint( ptECheck) ;
if ( ! AreSamePointApprox( ptS, ptSCheck) || ! AreSamePointApprox( ptE, ptECheck))
nStat = 2 ;
}
else
nStat = 2 ;
// ritorno la curva modificata
if ( nStat != 2) {
pCrvFinal->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ;
PtrOwner<ICurveComposite> pCrvToReturn( CreateCurveComposite()) ;
if( IsNull( pCrvToReturn))
return false ;
// PRIMO TRATTO
PtrOwner<ICurveComposite> pCrvA( GetCurveComposite( pCrv_->CopyParamRange( 0, nInd))) ;
if ( ! IsNull( pCrvA) && pCrvA->GetCurveCount() > 0 && pCrvA->IsValid()) {
if ( ! pCrvToReturn->AddCurve( Release( pCrvA))) {
nStat = 2 ;
return true ;
}
}
// NUOVO TRATTO
if( ! pCrvToReturn->AddCurve( Release( pCrvFinal))) {
nStat = 2 ;
return true ;
}
// ULTIMO TRATTO
PtrOwner<ICurveComposite> pCrvB( GetCurveComposite( pCrv_->CopyParamRange( nInd + 1, pCrv_->GetCurveCount()))) ;
if ( ! IsNull( pCrvB) && pCrvB->GetCurveCount() > 0 && pCrvB->IsValid())
if( ! pCrvToReturn->AddCurve( Release( pCrvB))) {
nStat = 2 ;
return true ;
}
if ( pCrvToReturn->GetCurveCount() > 0 && pCrvToReturn->IsValid()) {
double dThick ; pCrv_->GetThickness( dThick) ;
Vector3d vtExtr ; pCrv_->GetExtrusion( vtExtr) ;
int nProp0 = pCrv_->GetTempProp( 0) ;
int nProp1 = pCrv_->GetTempProp( 1) ;
pCrv_->Clear() ;
pCrv_->AddCurve( Release( pCrvToReturn)) ;
pCrv_->SetExtrusion( vtExtr ) ;
pCrv_->SetThickness( dThick) ;
pCrv_->SetTempProp( nProp0, 0) ;
pCrv_->SetTempProp( nProp1, 1) ;
}
else
nStat = 2 ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::SetTmpPropWithRawProjectedFaces( ICurveComposite* pCrvCompo_NewExt, ICRVCOMPOPOVECTOR& vCrvExtProj,
const Vector3d& vtN, double dToll)
{
// controllo validità parametri
if ( pCrvCompo_NewExt == nullptr || dToll < EPS_SMALL || vtN.IsSmall())
return false ;
// recupero le proprietà
int nTmpProp0 = pCrvCompo_NewExt->GetTempProp( 0) ;
int nTmpProp1 = pCrvCompo_NewExt->GetTempProp( 1) ;
Vector3d vtExtr ; pCrvCompo_NewExt->GetExtrusion( vtExtr) ;
double dThick ; pCrvCompo_NewExt->GetThickness( dThick) ;
// creo un frame Locale alla regione di svuotatura
Frame3d frLoc ;
Point3d ptC ;
if ( ! pCrvCompo_NewExt->GetCentroid( ptC))
if ( ! pCrvCompo_NewExt->GetStartPoint( ptC))
return false ;
frLoc.Set( ptC, vtN) ;
if ( ! frLoc.IsValid())
return false ;
// inizialmente imposto tutte le curve come chiuse
for ( int u = 0 ; u < pCrvCompo_NewExt->GetCurveCount() ; ++ u)
pCrvCompo_NewExt->SetCurveTempProp( u, 0, 0) ;
// imposto le proprietà temporanee delle curve
for ( int u = 0 ; u < pCrvCompo_NewExt->GetCurveCount() ; ++ u) {
bool bFound = false ;
for ( int i = 0 ; i < ( int)vCrvExtProj.size() && !bFound ; ++ i) {
int nStat = -1 ;
if ( SetTmpPropByOverlap( pCrvCompo_NewExt, u, vCrvExtProj[i], nStat, dToll) && nStat == 1)
bFound = true ;
}
if ( ! bFound) {
// controllo se fa overlap con più curve di proiezione ( la SetTmpPropByOverlap ritorna Falso se non c'è un
// CheckSimpleOverlap => Se la curva fa Overlap con diversi bordi di proiezione devo settare le temp prop caso
// per caso...
PtrOwner<ICurveComposite> pCrvCompoCurr( CreateCurveComposite()) ;
pCrvCompoCurr->AddCurve( *pCrvCompo_NewExt->GetCurve( u)) ;
if ( IsNull( pCrvCompoCurr) || ! pCrvCompoCurr->IsValid())
return false ;
// scorro il vettore delle curve aperte di proiezione
for ( int i = 0 ; i < ( int)vCrvExtProj.size() ; ++ i) {
PtrOwner<ICurveComposite> pCrvCompoH( CreateCurveComposite()) ;
if ( IsNull( pCrvCompoH))
return false ;
// per ogni sottocurva creata dalla singola curva originale...
for ( int uu = 0 ; uu < pCrvCompoCurr->GetCurveCount() ; ++ uu) {
int nProp_Check = -1 ; int nProp1_Check = -1 ;
// se la curva non è già stata impostata aperta in un passaggio precedente...
if ( pCrvCompoCurr->GetCurveTempProp( uu, nProp_Check, 0) && nProp_Check == 0 &&
pCrvCompoCurr->GetCurveTempProp( uu, nProp1_Check, 1) && nProp1_Check != -999) {
PtrOwner<ICurve> pCrvCurr_Close( pCrvCompoCurr->GetCurve( uu)->Clone()) ;
if ( IsNull( pCrvCurr_Close) || ! pCrvCurr_Close->IsValid())
return false ;
// controllo se il pezzo chiuso fa Overlap con la curva della proiezione i-esima
// porto in locale...
pCrvCurr_Close->ToLoc( frLoc) ;
vCrvExtProj[i]->ToLoc( frLoc) ;
// intersezione...
IntersCurveCurve IntCC( *pCrvCurr_Close, *vCrvExtProj[i]) ;
// riporto in globale...
pCrvCurr_Close->ToGlob( frLoc) ;
vCrvExtProj[i]->ToGlob( frLoc) ;
CRVCVECTOR ccClass ;
// se riesco a classificare...
if ( IntCC.GetCurveClassification( 0, dToll, ccClass)) {
// se questa curva non fa overlap, ma è semplicemente o tutta interna o tutta esterna alla curva
// do bordo della proiezione i-esima, allor apasso a controllare la successiva
if (( int)ccClass.size() == 1 &&
( ccClass[0].nClass == CRVC_IN || ccClass[0].nClass == CRVC_OUT)) {
pCrvCompoH->AddCurve( pCrvCurr_Close->Clone()) ;
continue ;
}
// altrimenti...
for ( int j = 0 ; j < ( int)ccClass.size() ; ++ j) {
PtrOwner<ICurve> pCrv_Step( pCrvCurr_Close->CopyParamRange( ccClass[j].dParS,
ccClass[j].dParE)) ;
if ( IsNull( pCrv_Step) || ! pCrv_Step->IsValid())
continue ;
// chiusa per default...
PtrOwner<ICurveComposite> pCrvCompo_Step( CreateCurveComposite()) ;
pCrvCompo_Step->AddCurve( pCrv_Step->Clone()) ;
int nStat1 = -1 ;
// richiamo la SetTmpPropByOverlap in quanto potrebbe fare overlap con l'indice 0 di vCrvExtProj.
// L'indice 0 contiene il bordo con i lati aperti/chiusi settati della intersezione con il grezzo
if ( SetTmpPropByOverlap( pCrvCompo_Step, 0, vCrvExtProj[i], nStat1, dToll)) {
if ( nStat1 == 1) {
// se c'è overlap, allora la tmp prop l'ho già impostata
// quindi non devo ricontrollare questa curva successivamente
pCrvCompo_Step->SetCurveTempProp( 0, -999 , 1) ;
}
else // chiusa se non c'è Overlap
pCrvCompo_Step->SetCurveTempProp( 0, 0, 0) ;
}
pCrvCompoH->AddCurve( Release( pCrvCompo_Step)) ;
}
}
} // se la curva è aperta la riaggiungo come sottocurva aperta alla composita
else
pCrvCompoH->AddCurve( pCrvCompoCurr->GetCurve( uu)->Clone()) ;
}
// finite le sottocurve, restiruisco la composita finale con il valore delle sottocurve impostate
// la curva originale u-esima è stata scomposta in sottocurve aperte/chiuse a seconda di quali e quanti
// overlap ha fatto con le curve esterne delle proiezioni
pCrvCompoCurr.Set( Release( pCrvCompoH)) ;
}
// sostituisco la CURVA COMPOSITA creata con alla CURVA SEMPLICE originaria
PtrOwner<ICurveComposite> pCrv_Bef( CloneCurveComposite( pCrvCompo_NewExt)) ; // tratto precente
PtrOwner<ICurveComposite> pCrv_Aft( CloneCurveComposite( pCrvCompo_NewExt)) ; // tratto successivo
PtrOwner<ICurveComposite> pCrv_New( CreateCurveComposite()) ;
if ( IsNull( pCrv_Bef) || IsNull( pCrv_Aft) || IsNull( pCrv_New) ||
! pCrv_Bef->IsValid() || ! pCrv_Aft->IsValid())
return false ;
// ricomposizione con tagli per non perdere le proprietà appena impostate
if ( ! pCrv_Bef->TrimEndAtParam( u))
pCrv_Bef->Clear() ;
if ( ! pCrv_Aft->TrimStartAtParam( u + 1))
pCrv_Aft->Clear() ;
if ( ! IsNull( pCrv_Bef) && pCrv_Bef->IsValid())
pCrv_New->AddCurve( Release( pCrv_Bef)) ;
int nCrv = 0 ;
if ( ! IsNull( pCrvCompoCurr) && pCrvCompoCurr->IsValid()) {
nCrv = pCrvCompoCurr->GetCurveCount() ;
pCrv_New->AddCurve( Release( pCrvCompoCurr)) ;
}
if ( ! IsNull( pCrv_Aft) && pCrv_Aft->IsValid())
pCrv_New->AddCurve( Release( pCrv_Aft)) ;
// controllo validità della curva, altrimenti non modifico nulla ed esco ( Avrò un chiuso)
if ( ! IsNull( pCrv_New) && pCrv_New->IsValid() && pCrv_New->IsClosed()) {
pCrvCompo_NewExt->Clear() ;
pCrvCompo_NewExt->AddCurve( Release( pCrv_New)) ;
u += nCrv - 1 ; // " ++u "
}
}
}
pCrvCompo_NewExt->SetTempProp( nTmpProp0, 0) ;
pCrvCompo_NewExt->SetTempProp( nTmpProp1, 1) ;
pCrvCompo_NewExt->SetExtrusion( vtExtr) ;
pCrvCompo_NewExt->SetThickness( dThick) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::CheckSmallPartsForOpenEdge( ICurveComposite* pCrvCompo, double dToll)
{
// controllo validità dei parametri
if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid() || pCrvCompo->GetCurveCount() == 0 || dToll < EPS_SMALL)
return false ;
// sistemo le curve piccole per le quali potrei ever commesso degli errori impostando un lato chiuso
for ( int i = 0 ; i < pCrvCompo->GetCurveCount() ; ++ i) {
const ICurve* pCrvCurr = pCrvCompo->GetCurve( i) ;
if ( pCrvCurr == nullptr)
return false ;
double dLen = EPS_SMALL ;
if ( pCrvCurr->GetLength( dLen) && dLen < dToll && pCrvCurr->GetTempProp( 0) == 0) {
const ICurve* pCrv_Prec = pCrvCompo->GetCurve( i != 0 ? i - 1 : pCrvCompo->GetCurveCount() - 1) ;
const ICurve* pCrv_Succ = pCrvCompo->GetCurve( i != pCrvCompo->GetCurveCount() -1 ? i + 1 : 0 ) ;
if ( pCrv_Prec == nullptr || pCrv_Succ == nullptr)
return false ;
if ( pCrv_Prec->GetTempProp( 0) != pCrv_Succ->GetTempProp( 0)) {
// controllo se la curva attuale è in tangenza con la successiva o la precedente
Vector3d vtDir_prec ; pCrv_Prec->GetEndDir( vtDir_prec) ;
Vector3d vtDir_succ ; pCrv_Succ->GetStartDir( vtDir_succ) ;
Vector3d vtDirStart_Curr ; pCrvCurr->GetStartDir( vtDirStart_Curr) ;
Vector3d vtDirEnd_Curr ; pCrvCurr->GetEndDir( vtDirEnd_Curr) ;
if ( AreSameVectorEpsilon( vtDir_prec, vtDirStart_Curr, 500 * EPS_SMALL))
pCrvCompo->SetCurveTempProp( i, 0, pCrv_Prec->GetTempProp( 0)) ;
else if ( AreSameVectorEpsilon( vtDir_succ, vtDirEnd_Curr, 500 * EPS_SMALL))
pCrvCompo->SetCurveTempProp( i, 0, pCrv_Succ->GetTempProp( 0)) ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::CheckIfOffsetIsNecessary( const ICurveComposite* pCrvOffs, const double dOffs, const int nOffsCount,
const int nIter, const Vector3d& vtN, bool& bInsert)
{
// controllo dei parametri
if ( pCrvOffs == nullptr || ! pCrvOffs->IsValid() || pCrvOffs->GetCurveCount() == 0 || dOffs < EPS_SMALL)
return false ;
bInsert = true ; // di base inserisco
// controllo se richiesta ottimizzazione sul numero di Offsets
if ( ! m_bOptOffset)
return true ;
if ( nIter != 0) { // controllo se sono almeno al secondo offset...
// per ogni curva controllo se il controOffset + 5 * EPS_SMALL genera una regione ...
OffsetCurve OffsCrv ; // considero anche i casi in cui ho bSmallRad
if ( OffsCrv.Make( pCrvOffs, - m_TParams.m_dDiam / 2 + dOffs - 5 * EPS_SMALL , ICurve::OFF_FILLET)) {
// se questa curva sparisce -> non serve inserirla come offset, non svuota parti aggiuntive
if ( OffsCrv.GetCurveCount() == 0) {
bInsert = false ;
return true ;
}
}
else
return true ;
// controllo se richista ottimizzazione per Offsets mediante centroidi e medial Axis
if ( ! m_bOptOffsetCM || OffsCrv.GetCurveCount() > 1)
return true ;
PtrOwner<ICurve> pCrvOffLonger( OffsCrv.GetLongerCurve()) ;
if ( IsNull( pCrvOffLonger) || ! pCrvOffLonger->IsValid())
return true ;
// Immagine del tool con centro nel centroide della zona da svuotare
Point3d ptC ; pCrvOffLonger->GetCentroid( ptC) ;
PtrOwner<ICurveArc> pCrvTool( CreateCurveArc()) ;
if( IsNull( pCrvTool))
return false ;
pCrvTool->SetXY( ptC, m_TParams.m_dDiam / 2 - 5 * EPS_SMALL) ;
CRVCVECTOR ccClass ;
IntersCurveCurve intCC( *pCrvOffLonger, *pCrvTool) ;
intCC.GetCurveClassification( 1, EPS_SMALL, ccClass) ;
if (( int)ccClass.size() == 1 && ccClass[0].nClass == CRVC_OUT) {
// CENTROIDE
bInsert = false ;
return true ;
}
PolyLine pl ;
if ( ! pCrvOffLonger->ApproxWithLines( 100 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, pl))
return true ;
Vector3d vtX ;
double dLen = 0 ; double dHeight = 0 ;
if ( ! pl.GetMinAreaRectangleXY( ptC, vtX, dLen, dHeight))
return true ;
Frame3d frLoc ; frLoc.Set( ptC, vtN, vtX) ;
if ( ! frLoc.IsValid())
return true ;
BBox3d bBox ;
frLoc.Invert() ;
pCrvOffLonger->GetBBox( frLoc, bBox) ;
double dDimX = bBox.GetDimX() ;
double dDimY = bBox.GetDimY() ;
if ( dDimX < m_TParams.m_dDiam - 100 * EPS_SMALL ||
dDimY < m_TParams.m_dDiam - 100 * EPS_SMALL) {
bInsert = false ;
return true ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AssignFeedSpiralOpt( const int nOptType, ICurveComposite* pCrv ) {
// controllo della curva corrente
if ( pCrv == nullptr || !pCrv->IsValid() || pCrv->GetCurveCount() == 0)
return false ;
// controllo se il Flag per assegnare la Feed è attivo
if ( !m_bAssignFeed)
return AssignDefaultFeed( pCrv) ;
switch ( m_Params.m_nSubType )
{
case POCKET_SUB_SPIRALIN :
if ( nOptType == 0) { // Spirale dall'Esterno
for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) {
if ( u == 0) // prima circonferenza
pCrv->SetCurveTempProp( 0, FEED_DIVISOR * GetMinFeed(), 0) ;
else // semi cerchi in tangenza
pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMaxFeed(), 0) ;
}
}
else if ( nOptType == 1) { // Trapezoidi
for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u)
pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ;
}
break ;
/* NB. Essendo la funzione CalcSpiral richiamata sia per lo SpiralIN che per lo SpiralOUT le curve sono sempre
orientate nello stesso modo, solamente alla fine viene invertita la curva finale per la svuotatura... */
case POCKET_SUB_SPIRALOUT :
if ( nOptType == 0) { // Spiral verso l'esterno
for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) {
if ( u > pCrv->GetCurveCount() - 3 ) // prime semi circonferenze
pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ;
else
pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMaxFeed(), 0) ;
}
}
else if ( nOptType == 1) { // Trapezoidi
for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u)
pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ;
}
break ;
default :
break ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AssignFeedZigZagOneWay( ICurveComposite* pCompo, const bool bIsLink, const ICURVEPOVECTOR& vLAbove,
const ICURVEPOVECTOR& vLUnder, const ICRVCOMPOPOVECTOR& vAddedLinks)
{
// controllo che la pCompoLine sia effettivamente una linea valida
if ( pCompo == nullptr || ! pCompo->IsValid())
return false ;
// controllo se il Flag per assegnare la Feed è attivo
if ( !m_bAssignFeed)
return AssignDefaultFeed( pCompo) ;
// inzialmente setto la feed Minima alla curva
for ( int u = 0 ; u < pCompo->GetCurveCount() ; ++ u)
pCompo->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ;
// se è un link tra livelli diversi, allora esco ( con Feed Minima )
if ( bIsLink) {
Point3d ptS_link ; pCompo->GetStartPoint( ptS_link) ;
Point3d ptE_link ; pCompo->GetEndPoint( ptE_link) ;
if ( abs( ptE_link.y - ptS_link.y) > 500 * EPS_SMALL)
return true ;
}
// se la curva è piccola, allora esco ( con Feed Minima)
double dLen = EPS_SMALL ;
if ( ! pCompo->GetLength( dLen) || dLen < 0.6 * m_TParams.m_dDiam)
return true ;
Point3d ptS, ptE ;
pCompo->GetStartPoint( ptS) ;
pCompo->GetEndPoint( ptE) ;
// creo l'intervallo desiderato valutanto le coordinate x
Intervals IntMinFeed ; IntMinFeed.Set( ptS.x, ptE.x) ;
// creo un vettore contenente i tratti sopra e i tratti sotto attivi
ICURVEPOVECTOR vAllInt ; vAllInt.reserve(( int)vLUnder.size() + ( int)vLAbove.size()) ;
for ( int i = 0 ; i < ( int)vLUnder.size() ; ++ i)
vAllInt.emplace_back( vLUnder[i]->Clone()) ;
for ( int i = 0 ; i < ( int)vLAbove.size() ; ++ i)
vAllInt.emplace_back( vLAbove[i]->Clone()) ;
int nDim = ( int)vAllInt.size() ;
// aggiungo le parti dei link interessate
double dCurrY = ptS.y ;
BBox3d bBoxLink ;
for ( int l = 0 ; l < ( int)vAddedLinks.size() ; ++ l) {
vAddedLinks[l]->GetLocalBBox( bBoxLink) ;
if (( dCurrY - bBoxLink.GetMin().y) < GetSideStep() + 50 * EPS_SMALL ||
( dCurrY - bBoxLink.GetMax().y) < GetSideStep() + 50 * EPS_SMALL) {
// determino la direzione del Link
Vector3d vtLinkDir( - 25, 0, 0) ;
Point3d ptS_l ;
vAddedLinks[l]->GetStartPoint( ptS_l) ;
Point3d ptE_l ;
vAddedLinks[l]->GetEndPoint( ptE_l) ;
if ( ptE_l.x - ptS_l.x < EPS_SMALL)
vtLinkDir.x -= ptS_l.x - ptE_l.x ;
PtrOwner<ISurfFlatRegion> pSfrRectUp( GetSurfFlatRegionRectangle( bBoxLink.GetDimX() + 50, GetSideStep())) ;
pSfrRectUp->Translate(( ptS_l - ORIG) + vtLinkDir) ;
// link sopra o sotto alla curva currente ?
bool bIsDown = true ;
if ( dCurrY - ptS_l.y < EPS_SMALL)
bIsDown = false ;
CRVCVECTOR ccClass ;
pSfrRectUp->GetCurveClassification( *vAddedLinks[l], EPS_SMALL, ccClass) ;
for ( int i = 0 ; i < ( int)ccClass.size() ; ++ i) {
if ( ccClass[i].nClass == CRVC_IN && bIsDown ||
ccClass[i].nClass == CRVC_OUT && ! bIsDown)
vAllInt.emplace_back( GetCurveComposite( vAddedLinks[l]->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE))) ;
}
}
}
// scorro tutti i tratti Attivi
for ( int i = 0 ; i < ( int)vAllInt.size() ; ++ i) {
// controllo che il tratto lineare sotto sia sufficientemente lungo
double dLen_iU = EPS_SMALL ;
if ( ! vAllInt[i]->GetLength( dLen_iU) || ( dLen_iU < 1.1 * m_TParams.m_dDiam && i < nDim))
continue ;
Point3d ptS_iU, ptE_iU ;
vAllInt[i]->GetStartPoint( ptS_iU) ;
vAllInt[i]->GetEndPoint( ptE_iU) ;
// la vtDir per Above e Under è sempre invertita rispetto alla linea corrente
// sottraggo questo intervallo a quello originale
IntMinFeed.Subtract( ptS_iU.x, ptE_iU.x) ;
}
// l'intervallo orginale ora conterrà i sottointervalli con feed Minima, tolgo quelli troppo piccoli
Intervals IntMinFeed_noSmall ;
double dParS = EPS_SMALL ; double dParE = EPS_SMALL ;
bool bFound = IntMinFeed.GetFirst( dParS, dParE) ;
while ( bFound) {
if ( dParE - dParS > m_TParams.m_dDiam * 0.5 - 5 * EPS_SMALL)
IntMinFeed_noSmall.Add( dParS, dParE) ;
bFound = IntMinFeed.GetNext( dParS, dParE) ;
}
// ora che ho solo tratti abbastanza lunghi, creo l'intervallo complementare
// questo intervallo contiene tutte le feed Massime
Intervals IntMaxFeed ; IntMaxFeed.Set( ptS.x, ptE.x) ;
IntMaxFeed.Subtract( IntMinFeed_noSmall) ;
// tolgo le parti piccole
Intervals IntMaxFeed_noSmall ;
bFound = IntMaxFeed.GetFirst( dParS, dParE) ;
while ( bFound) {
if ( dParE - dParS > m_TParams.m_dDiam * 0.5 - 5 * EPS_SMALL)
IntMaxFeed_noSmall.Add( dParS, dParE) ;
bFound = IntMaxFeed.GetNext( dParS, dParE) ;
}
// recupero la direzione principale della curva corrente
Vector3d vtDir = X_AX ;
if ( ptE.x - ptS.x < EPS_SMALL)
vtDir = - X_AX ;
// trasformo questi intervalli nei parametri corrispondenti sulla linea originale
bool bFMax = false ;
bFound = IntMaxFeed_noSmall.GetFirst( dParS, dParE) ;
if ( bFound && IntMaxFeed_noSmall.IsInside( ptS.x + vtDir.x * 20 * EPS_SMALL))
bFMax = true ;
if ( ! bFound && bIsLink) // se non ho intervalli a Feed Massima, allora esco ( con Feed Minima)
return true ;
while ( bFound) {
if ( ! bIsLink) { // se segmento di ZigZag
double du_js = EPS_SMALL ; pCompo->GetParamAtPoint( Point3d( dParS, ptS.y, ptS.z), du_js) ;
pCompo->AddJoint( du_js) ;
double du_je = EPS_SMALL ; pCompo->GetParamAtPoint( Point3d( dParE, ptE.y, ptE.z), du_je) ;
pCompo->AddJoint( du_je) ;
}
bFound = IntMaxFeed_noSmall.GetNext( dParS, dParE) ;
}
// aggiorno le proprietà temporanee con la feed
if ( ! bIsLink) {
for ( int u = 0 ; u < pCompo->GetCurveCount() ; ++ u)
{
if ( IsEven( u) == bFMax)
pCompo->SetCurveTempProp( u, FEED_DIVISOR * GetMaxFeed() , 0) ;
else
pCompo->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed() , 0) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AssignFeedOnCorners( ICurveComposite* pCrv, const ICurveComposite* pCrv_orig, const double dLenToll)
{
// controllo sulla curva iniziale
if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0 || ! pCrv->IsClosed())
return false ;
// controllo se Flag per Feed è attivo
if ( !m_bAssignFeed)
return AssignDefaultFeed( pCrv) ;
// nuova curva finale
PtrOwner<ICurveComposite> pCrv_new( CreateCurveComposite()) ;
if ( IsNull( pCrv_new))
return false ;
Intervals IntU ; IntU.Set( 0.0, 1.0 * pCrv->GetCurveCount()) ;
// scorro tutte le curve cercando i punti non C'
for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u ) {
// curva u-esima
const ICurve* pCrv_u = pCrv->GetCurve( u) ;
// curva (u+1)-esima
int u_f = u + 1 ;
if ( u_f == pCrv->GetCurveCount())
u_f = 0 ;
const ICurve* pCrv_uu = pCrv->GetCurve( u_f) ;
// calcolo l'angolo tra le due curve
double dAng = EPS_ANG_ZERO ;
Vector3d dTan_u = V_NULL ; pCrv_u->GetEndDir( dTan_u) ;
Vector3d dTan_uu = V_NULL ; pCrv_uu->GetStartDir( dTan_uu) ;
double dU_S = 0.0 ;
double dU_E = 1.0 ;
if ( ! dTan_u.GetAngle( dTan_uu, dAng) || abs( dAng) > EPS_ANG_SMALL) { // se spigolo...
// ricavo la lunghezza delle due curve e controllo che non siano dei lati aperti
int nStat_u = 0 ;
if ( CheckSimpleOverlap( pCrv_u, pCrv_orig, nStat_u, 50 * EPS_SMALL) && nStat_u != 1) {
double dLen_u = EPS_SMALL ; pCrv_u->GetLength( dLen_u) ;
if ( dLen_u > dLenToll + 500 * EPS_SMALL)
pCrv_u->GetParamAtLength( dLen_u - dLenToll, dU_S) ;
}
int nStat_uu = 0 ;
if ( CheckSimpleOverlap( pCrv_uu, pCrv_orig, nStat_uu, 50 * EPS_SMALL) && nStat_uu != 1) {
double dLen_uu = EPS_SMALL ; pCrv_uu->GetLength( dLen_uu) ;
if ( dLen_uu > dLenToll + 500 * EPS_SMALL)
pCrv_uu->GetParamAtLength( dLenToll, dU_E) ;
}
if ( u_f != 0) {
IntU.Subtract( u + ( nStat_u == 0 ? dU_S : 1), u_f + ( nStat_uu == 0 ? dU_E : 0)) ;
}
else {
if ( nStat_u == 0)
IntU.Subtract( u + dU_S, pCrv->GetCurveCount()) ;
if ( nStat_uu == 0)
IntU.Subtract( 0.0, dU_E) ;
}
}
}
ICRVCOMPOPOVECTOR vCrvMinFeed ;
double dParS = EPS_SMALL ; double dParE = EPS_SMALL ;
Intervals IntMinFeed ; IntMinFeed.Set( 0.0, 1.0 * pCrv->GetCurveCount()) ;
IntMinFeed.Subtract( IntU) ;
bool bFound = IntMinFeed.GetFirst( dParS, dParE) ;
while ( bFound) {
Point3d ptS, ptE ;
vCrvMinFeed.emplace_back( GetCurveComposite( pCrv->CopyParamRange( dParS, dParE))) ;
for ( int u = 0 ; u < vCrvMinFeed.back()->GetCurveCount() ; ++ u)
vCrvMinFeed.back()->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ;
bFound = IntMinFeed.GetNext( dParS, dParE) ;
}
PtrOwner<ICurveComposite> pCrv_clone( pCrv->Clone()) ;
for ( int i = 0 ; i < ( int)vCrvMinFeed.size() ; ++ i) {
PtrOwner<ICurveComposite> pCrv_back( pCrv_clone->Clone()) ;
PtrOwner<ICurveComposite> pCrv_forward( pCrv_clone->Clone()) ;
Point3d ptS, ptE ;
vCrvMinFeed[i]->GetStartPoint( ptS) ;
vCrvMinFeed[i]->GetEndPoint( ptE) ;
double duS ; double duE ;
pCrv_clone->GetParamAtPoint( ptS, duS) ;
pCrv_clone->GetParamAtPoint( ptE, duE) ;
if ( ! pCrv_back->TrimEndAtParam( duS))
pCrv_back->Clear() ;
if ( ! pCrv_forward->TrimStartAtParam( duE))
pCrv_forward->Clear() ;
pCrv_clone->Clear() ;
pCrv_clone->AddCurve( Release( pCrv_back)) ;
pCrv_clone->AddCurve( vCrvMinFeed[i]->Clone()) ;
pCrv_clone->AddCurve( Release( pCrv_forward)) ;
}
pCrv->Clear() ;
pCrv->AddCurve( Release( pCrv_clone)) ;
return false ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetFeedForParam( double& dPar, double& dFeed)
{
/*
feed
^
|
GetFeed() + --------------\
| * \
| * \
| * \
| * \
| * \
GetFeed() * GetSideStep() / d + * *
| * *
0--------------+------+---------------> Working Arc
GetSideStep() d
*/
if ( dPar > m_TParams.m_dDiam || dPar < 0 ) // dominio...
return false ;
if ( m_TParams.m_dDiam - GetSideStep() < 50 * EPS_SMALL) { // se la funzione è costante...
dFeed = GetMaxFeed() ; // non ho scelta ...
return true ;
}
else {
if ( GetSideStep() < dPar + 50 * EPS_SMALL) { // se sono nel tratto lineare discendente ...
// d/2 su parte discendente
dFeed = GetFeed() + ( GetFeed() * ( 1 - ( GetSideStep() / m_TParams.m_dDiam))) *
( dPar - GetSideStep()) / ( GetSideStep() - m_TParams.m_dDiam) ;
}
else
dFeed = GetMaxFeed() ; // se sono nel tratto costante ...
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AssignFeedForOpenEdge( ICurveComposite* pCrv, const ICurveComposite* pCrvOF_orig)
{
if ( !m_bAssignFeed)
return AssignDefaultFeed( pCrv) ;
// controllo se qualche curva passa sopra ad un lato aperto...
if ( pCrvOF_orig != nullptr ) {
for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) {
const ICurve* pCrv_u = pCrv->GetCurve( u) ;
if ( pCrv_u == nullptr)
return false ;
int nStat = -1 ;
if ( CheckSimpleOverlap( pCrv_u, pCrvOF_orig, nStat, 1500 * EPS_SMALL) && nStat == 1) {
double dFeed = GetMinFeed() ;
double dPar = m_TParams.m_dDiam / 2 ;
if ( ! GetFeedForParam( dPar, dFeed))
return false ;
pCrv->SetCurveTempProp( u, FEED_DIVISOR * dFeed, 0) ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AssignFeedForLineInOut( ICurveComposite* pCrv, const bool bIsIn)
{
// controllo parametri
if ( pCrv == nullptr || pCrv->GetCurveCount() < 2)
return false ;
if ( !m_bAssignFeed)
return AssignDefaultFeed( pCrv) ;
if ( bIsIn) // Segmento in ingresso
pCrv->SetCurveTempProp( 0, FEED_DIVISOR * GetMinFeed(), 0) ;
else // Segmento in uscita
pCrv->SetCurveTempProp( pCrv->GetCurveCount() - 1, FEED_DIVISOR * GetMaxFeed(), 0) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AssignFeedForEdgeCleaning( ICurveComposite *pCrv, const ICRVCOMPOPOVECTOR& vCrvOF_orig, int nInd) {
// controllo parametri
if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0)
return false ;
// controllo che la svuotatura sia ZigZag o OneWay
if ( m_Params.m_nSubType == POCKET_SUB_SPIRALIN || m_Params.m_nSubType == POCKET_SUB_SPIRALOUT)
return false ;
// controllo se il Flag per assegnare la Feed è attivo
if ( !m_bAssignFeed)
return AssignDefaultFeed( pCrv) ;
double dCurrFeed = GetMinFeed() ;
if ( m_Params.m_nSubType == POCKET_SUB_ZIGZAG) // se pulitura ZigZag -> posso andare alla FeedMassima
dCurrFeed = GetMaxFeed() ;
// se pulitura OneWay la feed rimane le minima
// assegno a tutte le sottocurve la Feed
for ( int u = 0 ; u < ( int)pCrv->GetCurveCount() ; ++ u)
pCrv->SetCurveTempProp( u, FEED_DIVISOR * dCurrFeed, 0) ;
// controllo se le curve di Bordo passano su una curva originale -> controllo dei lati aperti
if ( m_Params.m_nSubType == POCKET_SUB_ZIGZAG && nInd >= 0)
AssignFeedForOpenEdge( pCrv, vCrvOF_orig[nInd]) ;
else {
for ( int i = 0 ; i < ( int)vCrvOF_orig.size() ; ++ i) // se sono nel caso OneWay ho una regione con più chunk...
AssignFeedForOpenEdge( pCrv, vCrvOF_orig[i]) ;
}
// se sono in una svuotatura a ZigZag, controllo la Feed sugli Angoli
if ( m_Params.m_nSubType == POCKET_SUB_ZIGZAG)
AssignFeedOnCorners( pCrv, vCrvOF_orig[nInd], m_TParams.m_dTDiam) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AssignFeedSpiral( ICurveComposite* pCrv, const ISurfFlatRegion* pSrfRemoved_offs, const bool bIsLink,
const ICRVCOMPOPOVECTOR& vLinks_done, const ICurveComposite* pCrv_orig, double dToll)
{
// controllo la validità della curva
if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0)
return false ;
// controllo se il Flag per assegnare la Feed è attivo
if ( !m_bAssignFeed)
return AssignDefaultFeed( pCrv) ;
// imposto di Default la Feed minima per ogni sottocurva
for ( int u = 0 ; u < ( int)pCrv->GetCurveCount() ; ++ u)
pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ;
// se non ho una superificie svuotata, allora esco ( con Feed Minima)
if ( pSrfRemoved_offs == nullptr || ! pSrfRemoved_offs->IsValid() || pSrfRemoved_offs->GetChunkCount() == 0) {
// controllo eventuali sovrapposizioni con lati aperti
AssignFeedForOpenEdge( pCrv, pCrv_orig) ;
return true ;
}
// clono la superificie ( valida)
PtrOwner<ISurfFlatRegion> pSrf_Removed_offs_clone( CloneSurfFlatRegion( pSrfRemoved_offs)) ;
if ( IsNull( pSrf_Removed_offs_clone) || ! pSrf_Removed_offs_clone->IsValid() ||
pSrf_Removed_offs_clone->GetChunkCount() == 0)
return true ; // esco ( sempre con Feed Minima)
// restringo la superificie in maniera appropriata
if ( bIsLink) { // se curva di Link
if ( ! pSrf_Removed_offs_clone->Offset( - m_TParams.m_dDiam / 2 + 1500 * EPS_SMALL, ICurve::OFF_CHAMFER) ||
! pSrf_Removed_offs_clone->IsValid() || pSrf_Removed_offs_clone->GetChunkCount() == 0)
return true ; // esco ( sempre con Feed Minima)
}
else if ( m_TParams.m_dDiam / 2 < GetSideStep()) { // se curva di Offset e raggio utensile < Side step
if ( ! pSrf_Removed_offs_clone->Offset( GetSideStep() - m_TParams.m_dDiam / 2, ICurve::OFF_CHAMFER) ||
! pSrf_Removed_offs_clone->IsValid() || pSrf_Removed_offs_clone->GetChunkCount() == 0)
return true ; // esco ( sempre con Feed Minima)
}
// classifico le parti interne alla superificie creata solo dagli Offset
CRVCVECTOR ccClass ;
if ( ! pSrf_Removed_offs_clone->GetCurveClassification( *pCrv, EPS_SMALL, ccClass))
return true ; // esco ( sempre con Feed Minima)
// creo la nuova curva con le Feed regolate
PtrOwner<ICurveComposite> pCrv_new( CreateCurveComposite()) ;
if ( IsNull( pCrv_new))
return false ;
for ( int i = 0 ; i < ( int)ccClass.size() ; ++ i) {
double dCurrFeed = GetMinFeed() ;
PtrOwner<ICurveComposite> PCrv_sez( GetCurveComposite( pCrv->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE))) ;
if ( IsNull( PCrv_sez))
continue ;
if ( ccClass[i].nClass == CRVC_IN)
dCurrFeed = GetMaxFeed() ;
for ( int u = 0 ; u < PCrv_sez->GetCurveCount() ; ++ u)
PCrv_sez->SetCurveTempProp( u, FEED_DIVISOR * dCurrFeed, 0) ;
pCrv_new->AddCurve( Release( PCrv_sez)) ;
}
pCrv->Clear() ;
pCrv->AddCurve( Release( pCrv_new)) ;
// controllo eventuali sovrapposizioni tra la curva attuale e i Link in precedenza percorsi
for ( int l = 0 ; l < ( int)vLinks_done.size() ; ++ l) {
IntersCurveCurve intCC( *pCrv, *vLinks_done[l]) ;
for ( int i = 0 ; i < intCC.GetIntersCount() ; ++ i) {
IntCrvCrvInfo aInfo ;
if ( ! intCC.GetIntCrvCrvInfo( i, aInfo) || ! aInfo.bOverlap ||
AreSamePointApprox( aInfo.IciA[0].ptI, aInfo.IciA[1].ptI))
continue ;
PtrOwner<ICurveComposite> pCrv_before( CloneCurveComposite( pCrv)) ;
if ( ! pCrv_before->TrimEndAtParam( aInfo.IciA[0].dU))
pCrv_before->Clear() ;
PtrOwner<ICurveComposite> pCrv_after( CloneCurveComposite( pCrv)) ;
if ( ! pCrv_after->TrimStartAtParam( aInfo.IciA[1].dU))
pCrv_after->Clear() ;
PtrOwner<ICurveComposite> pCrv_overlap( GetCurveComposite( pCrv->CopyParamRange( aInfo.IciA[0].dU, aInfo.IciA[1].dU))) ;
for ( int u = 0 ; u < pCrv_overlap->GetCurveCount() ; ++ u)
pCrv_overlap->SetCurveTempProp( u, FEED_DIVISOR * GetMaxFeed(), 0) ;
pCrv->Clear() ;
pCrv->AddCurve( Release( pCrv_before)) ;
pCrv->AddCurve( Release( pCrv_overlap)) ;
pCrv->AddCurve( Release( pCrv_after)) ;
}
}
if ( ! bIsLink) { // NEL CASO DI OFFSET
// creo un intervallo con tutte le Feed Minime
Intervals IntMinFeed ;
for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) {
int nProp ; pCrv->GetCurveTempProp( u, nProp, 0) ;
if ( abs ( nProp - int( FEED_DIVISOR * GetMinFeed()) < 5 * EPS_SMALL))
IntMinFeed.Add( u, u + 1) ;
}
double dParS = EPS_SMALL ; double dParE = EPS_SMALL ;
// a questo intervallo tolgo tutti i sottotratti di lunghezza inferiore alla tolleranza richiesta
Intervals IntMinFeed_noSmall ;
bool bFound = IntMinFeed.GetFirst( dParS, dParE) ;
while ( bFound) {
PtrOwner<ICurve> pCrv_Crv( pCrv->CopyParamRange( dParS, dParE)) ;
double dLen = EPS_SMALL ; pCrv_Crv->GetLength( dLen) ;
if ( dLen > dToll + 5 * EPS_SMALL)
IntMinFeed_noSmall.Add( dParS, dParE) ;
bFound = IntMinFeed.GetNext( dParS, dParE) ;
}
for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) {
if ( IntMinFeed_noSmall.IsInside( u + 0.5))
pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ;
else
pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMaxFeed(), 0) ;
}
}
else { // NEL CASO DI LINK
// le curve con lunghezza < dToll vanno modificate
for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) {
double dLen = EPS_SMALL ;
pCrv->GetCurve( u)->GetLength( dLen) ;
if ( dLen < dToll + 5 * EPS_SMALL) {
PtrOwner<ICurveComposite> pCrvCompo( CloneCurveComposite( pCrv)) ;
if ( ! pCrvCompo->TrimStartAtParam( u))
pCrvCompo->Clear() ;
if ( ! pCrvCompo->TrimEndAtLen( dLen + m_TParams.m_dDiam))
pCrvCompo->Clear() ;
if ( pCrvCompo->IsValid()) {
bool bFound = false ;
for ( int uu = 1 ; uu < pCrvCompo->GetCurveCount() ; ++ uu) {
double dLenH = EPS_SMALL ; pCrvCompo->GetCurve( uu)->GetLength( dLenH) ;
if ( dLenH < dToll + 5 * EPS_SMALL)
continue ;
// cerco tra le curve successive vicine se ne trovo una con Feed Minima
int nProp ; pCrvCompo->GetCurveTempProp( uu, nProp, 0) ;
if ( abs ( nProp - int( FEED_DIVISOR * GetMinFeed()) < 5 * EPS_SMALL)) {
pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ;
bFound = true ;
break ;
}
}
if ( ! bFound && u != 0) {
// arrivato qui, so che successivamente non ho curve con Feed Minima vicine
int nProp ; pCrv->GetCurveTempProp( u - 1, nProp, 0) ;
if ( abs ( nProp - int( FEED_DIVISOR * GetMaxFeed()) < 5 * EPS_SMALL))
// se anche la precedente ha Feed Massima -> la curva u-esima è piccola ed Isolata
pCrv->SetCurveTempProp( u, nProp, 0) ;
}
}
else
pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ;
}
}
}
// controllo eventuali sovrapposizioni con lati aperti
AssignFeedForOpenEdge( pCrv, pCrv_orig) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AssignFeedForReturnPath( ICurveComposite* pCrv)
{
// controllo curva corrente
if ( pCrv == nullptr || !pCrv->IsValid() || pCrv->GetCurveCount() == 0)
return false ;
// controllo se il Flag per assegnare la Feed è attivo
if ( !m_bAssignFeed)
return AssignDefaultFeed( pCrv) ;
if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0)
return false ;
for ( int u = 0 ; u < ( int)pCrv->GetCurveCount() ; ++ u)
pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMaxFeed(), 0) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AssignFeedCrvOnUnclearedRegions( ICurveComposite* pCrv)
{
// controllo validità della curva
if ( pCrv == nullptr || !pCrv->IsValid() || pCrv->GetCurveCount() == 0)
return false ;
// controllo se il Flag per assegnare la Feed è attivo
if ( !m_bAssignFeed)
return AssignDefaultFeed( pCrv) ;
if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0)
return false ;
for ( int u = 0 ; u < ( int)pCrv->GetCurveCount() ; ++ u)
pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AssignDefaultFeed( ICurveComposite* pCrv) {
if ( pCrv == nullptr || !pCrv->IsValid() || pCrv->GetCurveCount() == 0)
return false ;
for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u)
pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMaxFeed(), 0) ;
return true ;
}
bool
Pocketing::DrawColoredCrvForFeedTest( ICurve* pCurve, double dFeed)
{
return true ;
if ( abs( dFeed - GetMinFeed()) < EPS_SMALL) {
int rosso = m_pGeomDB->AddGeoObj(GDB_ID_NULL, GDB_ID_ROOT, pCurve->Clone()) ;
m_pGeomDB->SetMaterial( rosso, RED) ;
m_pGeomDB->SetStatus( rosso, ( m_Params.m_nSubType == POCKET_SUB_SPIRALIN ||
m_Params.m_nSubType == POCKET_SUB_SPIRALIN) ? GDB_ST_OFF : GDB_ST_ON) ;
} else if ( abs( dFeed - GetMaxFeed()) < EPS_SMALL) {
int verde = m_pGeomDB->AddGeoObj(GDB_ID_NULL, GDB_ID_ROOT, pCurve->Clone()) ;
m_pGeomDB->SetMaterial( verde, GREEN) ;
m_pGeomDB->SetStatus( verde, ( m_Params.m_nSubType == POCKET_SUB_SPIRALIN ||
m_Params.m_nSubType == POCKET_SUB_SPIRALIN) ? GDB_ST_OFF : GDB_ST_ON) ;
}
else {
int giallo = m_pGeomDB->AddGeoObj(GDB_ID_NULL, GDB_ID_ROOT, pCurve->Clone()) ;
m_pGeomDB->SetMaterial( giallo, YELLOW) ;
m_pGeomDB->SetStatus( giallo, ( m_Params.m_nSubType == POCKET_SUB_SPIRALIN ||
m_Params.m_nSubType == POCKET_SUB_SPIRALIN) ? GDB_ST_OFF : GDB_ST_ON) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetNewSrfByAnotherPocketing( ISurfFlatRegion* pSrf, ISurfFlatRegion* pSrf_noOpenEdge, const Vector3d& vtTrasl)
{
// controllo dei parametri
if ( pSrf == nullptr || ! pSrf->IsValid() || pSrf->GetChunkCount() == 0 || m_dDiam_Prec < 0)
return false ;
// se e i parametri ed il tool permettono la nuova lavorazione...
if ( m_TParams.m_dDiam / 2 + GetOffsR() < m_dDiam_Prec / 2 + m_dOffsetR_Prec) {
// clono la superificie ricavata in precedenza ( senza estensione con lati aperti)
PtrOwner<ISurfFlatRegion> pSrf_Sub( CloneSurfFlatRegion( pSrf)) ;
if ( IsNull( pSrf_Sub) || ! pSrf_Sub->IsValid())
return false ;
//int Y = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrf_Sub->Clone()) ;
//m_pGeomDB->SetMaterial( Y, YELLOW) ;
// effettuo un Offset verso l'interno ( curve esterne che percorre il centro del Tool)
if ( pSrf_Sub->Offset( - m_dDiam_Prec / 2 - m_dOffsetR_Prec - 5 * EPS_SMALL, ICurve::OFF_FILLET)) {
// se la superificie sparisce o trovo un chunk non valido, la risvuoto tutta per sicurezza...
if ( ! pSrf_Sub->IsValid() || pSrf_Sub->GetChunkCount() == 0)
return true ;
// effettuo un Offset del raggio del tool precedente per ricavare la regione svuotata in precedenza
PtrOwner<ISurfFlatRegion> pSrfHelp( CloneSurfFlatRegion( pSrf_Sub)) ;
if ( ! pSrf_Sub->Offset( m_dDiam_Prec / 2 + 20 * EPS_SMALL, ICurve::OFF_FILLET)) {
//int nbadOffs = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrfHelp->Clone()) ;
//m_pGeomDB->Save( nbadOffs, "C:\\Users\\riccardo.elitropi\\Desktop\\Err_offs" + ToString( nbadOffs) + "__m" + ToString( m_dDiam_Prec / 2 + 20 * EPS_SMALL) + ".nge") ;
return false ;
}
//int r = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrf_Sub->Clone()) ;
//m_pGeomDB->SetMaterial( r, RED) ;
//int v = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrf_noOpenEdge->Clone()) ;
//m_pGeomDB->SetMaterial( v, GREEN) ;
PtrOwner<ISurfFlatRegion> pSrf_clone( CloneSurfFlatRegion( pSrf_noOpenEdge)) ;
if ( pSrf_clone->Subtract( *pSrf_Sub)) {
if ( ! pSrf_clone->IsValid() || pSrf_clone->GetChunkCount() == 0) {
pSrf->Clear() ;
return true ;
}
//int l = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrf_clone->Clone()) ;
//m_pGeomDB->SetMaterial( l, LIME) ;
// ricavo la curva esterna originale
PtrOwner<ICurveComposite> pCrvExt_orig( GetCurveComposite( pSrf->GetLoop( 0, 0))) ;
// superificie finale da restituire ...
PtrOwner<ISurfFlatRegion> pSrf_Final( CreateSurfFlatRegion()) ;
if ( IsNull( pSrf_Final))
return false ;
// tolgo dalla superificie le parti al di fuori del grezzo
bool bIsChanged ;
// per ogni chunk della superificie ricavata....
for ( int c = 0 ; c < pSrf_clone->GetChunkCount() ; ++ c) {
// singolo chunk della superificie modificato per i lati aperti...
PtrOwner<ISurfFlatRegion> pChunk_WithOpenEdges( CreateSurfFlatRegion()) ;
if ( IsNull( pChunk_WithOpenEdges))
return false ;
int nStat = 0 ;
PtrOwner<ICurveComposite> pCrvExt( GetCurveComposite( pSrf_clone->GetLoop( c, 0))) ;
// setto tutte le sottocurve aperte
for ( int u = 0 ; u < pCrvExt->GetCurveCount() ; ++ u) {
pCrvExt->SetCurveTempProp( u, 1, 0) ;
const ICurve* pCrv_u = pCrvExt->GetCurve( u) ;
for ( int cu = 0 ; cu < pSrf->GetChunkCount() ; ++ cu) {
for ( int l = 1 ; l < pSrf->GetLoopCount( cu) ; ++ l) {
PtrOwner<ICurveComposite> pCrvCompo_isl( GetCurveComposite( pSrf->GetLoop( cu, l))) ;
// se overlap con un' isola -> curva chiusa
if ( CheckSimpleOverlap( pCrv_u, pCrvCompo_isl, nStat) && nStat == 1)
pCrvExt->SetCurveTempProp( u, 0, 0) ;
}
}
for ( int cu = 0 ; cu < pSrf_noOpenEdge->GetChunkCount() ; ++ cu) {
for ( int l = 0 ; l < pSrf_noOpenEdge->GetLoopCount( cu) ; ++ l) {
// se overlap con curva della superficie originale -> copio la rispettiva temp prop
PtrOwner<ICurveComposite> pCrvCompo( GetCurveComposite( pSrf_noOpenEdge->GetLoop( cu, l))) ;
SetTmpPropByOverlap( pCrvExt, u, pCrvCompo, nStat) ;
}
}
}
bool bSomeOpen = false ;
int nProp0 = -1 ;
for ( int u = 0 ; u < pCrvExt->GetCurveCount() && !bSomeOpen ; ++ u) {
if ( pCrvExt->GetCurveTempProp( u, nProp0, 0) && nProp0 == 1)
bSomeOpen = true ;
}
ICRVCOMPOPOVECTOR vCrvIsl ;
for ( int l = 1 ; l < pSrf_clone->GetLoopCount( c) ; ++ l)
vCrvIsl.emplace_back( GetCurveComposite( pSrf_clone->GetLoop( c, l))) ;
if ( bSomeOpen) { // se trovo dei lati aperti
if ( ! AdjustContourWithOpenEdges( pCrvExt, vCrvIsl, m_TParams.m_dDiam, GetOffsR(), GetSideStep(), vtTrasl)) {
m_pMchMgr->SetLastError( 2430, "Error in Pocketing : adjust open edges failed") ;
return false ;
}
}
// Chunk modificato con i lati aperti
pChunk_WithOpenEdges->AddExtLoop( Release( pCrvExt)) ; // aggiungo la curva esterna
for ( int i = 1 ; i < int( vCrvIsl.size()) ; ++ i)
pChunk_WithOpenEdges->AddIntLoop( Release( vCrvIsl[i])) ; // aggiungo le eventuali isole
// aggiungo questo Chunk alla superificie finale ( potrebbero essere sovrapposti per alcune parti...)
if ( pSrf_Final->GetChunkCount() == 0)
pSrf_Final.Set( pChunk_WithOpenEdges) ;
else
pSrf_Final->Add( *pChunk_WithOpenEdges) ;
}
pSrf->Clear() ;
pSrf->CopyFrom( pSrf_Final) ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetDynamicClearedRegion( ISurfFlatRegion* pSrfPrec, const ICurveComposite* pCrv)
{
for ( int i = 0 ; i < pCrv->GetCurveCount() ; ++ i) {
const ICurve* pCrvPath = pCrv->GetCurve( i) ;
if ( pCrvPath != nullptr) {
PtrOwner<ICurve> pCrv_i( pCrvPath->Clone()) ;
if ( IsNull( pCrv_i))
return false ;
PtrOwner<ISurfFlatRegion> PSrfRemoved( GetSurfFlatRegionFromFatCurve( Release( pCrv_i), m_TParams.m_dDiam / 2, false, false)) ;
if ( pSrfPrec->GetChunkCount() == 0)
pSrfPrec->CopyFrom( PSrfRemoved) ;
else
pSrfPrec->Add( *PSrfRemoved) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetSfrByStm( const ISurfTriMesh* pStm, ISurfFlatRegion* pSfr, const Plane3d plPock,
const Vector3d& vtExtr, const double dThick, double dToll)
{
// controllo validità dei parametri
if ( pStm == nullptr || ! pStm->IsValid() ||
! plPock.IsValid())
return false ;
// creo un Frame per il sistema di Riferimento Locale
Frame3d frPock ; frPock.Set( plPock.GetPoint(), plPock.GetVersN()) ;
if ( ! frPock.IsValid())
return false ;
// creo la FlatRegion da resitutiure
SurfFlatRegionByContours SrfChunkDef ;
// recupero i Loop della TriMesh salvandoli in un vettore di PolyLine
POLYLINEVECTOR vPl ;
pStm->GetLoops( vPl) ;
// per ogni PolyLine...
for ( int i = 0 ; i < ( int)vPl.size() ; ++ i) {
// recupero la curva composita
PolyLine PL = vPl[i] ;
PtrOwner<ICurveComposite> pCrv( CreateCurveComposite()) ;
pCrv->FromPolyLine( PL) ;
// 0) Controllo se l'area ha senso
double dAreaStart = 0. ;
double dLenStart = 0. ;
Plane3d plUseless ;
pCrv->GetArea( plUseless, dAreaStart) ;
pCrv->GetLength( dLenStart) ;
if ( dAreaStart < 50 * EPS_SMALL || dLenStart < 50 * EPS_SMALL)
continue ;
// essendo una curva derivante da un'intersezione di Trimesh ho una composita derivante da una polyLine,
// devo recuperare gli archi
PolyArc PA ;
// 1) Mergiamo per uniformità
pCrv->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ;
// 2) Rimuoviamo Spikes o Curve a Z
if ( ! pCrv->RemoveSmallDefects( 150 * EPS_SMALL, 2 * ANG_TOL_STD_DEG, true))
return false ;
// 3) Interpoliamo mediante Linee ed Archi
pCrv->ToLoc( frPock) ;
pCrv->ApproxWithArcsEx( 500 * EPS_SMALL, ANG_TOL_STD_DEG, LIN_FEA_STD, PA) ;
pCrv->Clear() ;
pCrv->FromPolyArc( PA) ;
pCrv->ToGlob( frPock) ;
// 4) Estrusione e Thickness della curva
pCrv->SetExtrusion( vtExtr) ;
pCrv->SetThickness( dThick) ;
// la converto in una semplice cruva per proiettarla su piano della svuotatura
// dato che le curve sono prese da una trimesh, le proietto sul piano per sicurezza e per evitare approssimazioni
double dS, dE ;
pCrv->GetDomain( dS, dE) ;
PtrOwner<ICurve> pCrv_c( pCrv->CopyParamRange( dS, dE)) ;
if ( IsNull( pCrv_c) || ! pCrv_c->IsValid())
return false ;
// se la curva è "stretta" la trascuro, rende solo difficili i conti senza dare valore aggiunto
PtrOwner<ICurve> pCrv_proj( ProjectCurveOnPlane( *pCrv_c, plPock)) ;
double dAreaCheck = EPS_SMALL ; Plane3d plCheck ;
if ( ! IsNull( pCrv_proj) &&
pCrv_proj->IsClosed() &&
pCrv_proj->GetArea( plCheck, dAreaCheck) &&
dAreaCheck <= 50 * EPS_SMALL) {
continue ;
}
SrfChunkDef.AddCurve( Release( pCrv_proj)) ; // aggiungo le curve proiettate
}
// recupero la FlatRegion
PtrOwner<ISurfFlatRegion> pSrfByCurves( SrfChunkDef.GetSurf()) ;
if ( IsNull( pSrfByCurves) || pSrfByCurves->GetChunkCount() == 0) // controllo validità della FlatRegion
return true ; // non ho ricavato nulla, la TriMesh è troppo sottile o piccola
// controllo quante facce ottengo per uniformità con la proeizione
PtrOwner<ISurfFlatRegion> pSrfByAdd( CreateSurfFlatRegion()) ;
if ( IsNull( pSrfByAdd))
return false ;
while ( ! IsNull( pSrfByCurves)) {
if ( ! pSrfByAdd->IsValid() || pSrfByAdd->GetChunkCount() == 0)
pSrfByAdd.Set( Release( pSrfByCurves)) ;
else
if ( ! pSrfByAdd->Add( *pSrfByCurves))
return false ;
pSrfByCurves.Set( SrfChunkDef.GetSurf()) ;
}
// superificie regolare senza Chunk piccoli aggiuntivi
SurfFlatRegionByContours SFRFINAL ;
for ( int c = 0 ; c < pSrfByAdd->GetChunkCount() ; ++ c) {
for ( int l = 0 ; l < pSrfByAdd->GetLoopCount( c) ; ++ l) {
PtrOwner<ICurve> pCrvLoop( ConvertCurveToComposite( pSrfByAdd->GetLoop( c, l))) ;
if ( IsNull( pCrvLoop))
return false ;
double dArea = EPS_SMALL ;
double dLen = EPS_SMALL ;
Plane3d plCheck ;
if ( pCrvLoop->GetArea( plCheck, dArea) && dArea > 500 * EPS_SMALL &&
pCrvLoop->GetLength( dLen) && dLen > 500 * EPS_SMALL)
SFRFINAL.AddCurve( Release( pCrvLoop)) ;
}
}
pSrfByCurves.Set( SFRFINAL.GetSurf()) ;
if ( IsNull( pSrfByCurves) || pSrfByCurves->GetChunkCount() == 0) // controllo ancora validità della FlatRegion
return true ; // non ho ricavato nulla, la TriMesh è troppo sottile o piccola
// restituisco la FlatRegion
pSfr->Clear() ;
pSfr->CopyFrom( pSrfByCurves) ;
return pSfr != nullptr && pSfr->IsValid() ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetHomogeneousParts( ICurveComposite* pCrvCompo, ICURVEPOVECTOR& vCrvOpen, ICURVEPOVECTOR& vCrvClose,
bool bCallAdjust)
{
// controllo dei parametri
vCrvClose.clear() ;
vCrvClose.clear() ;
if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid() || pCrvCompo->GetCurveCount() == 0) // se curva non valida
return true ;
if ( ! pCrvCompo->IsClosed())
bCallAdjust = false ;
// controllo se la curva ha solo tratti aperti o tratti chiusi ---------------------
int nFirstTmpProp = -1 ;
int nCheckTmpProp = -1 ;
bool bIsHomogenous = true ;
for ( int u = 0 ; u < pCrvCompo->GetCurveCount() && bIsHomogenous ; ++ u) {
pCrvCompo->GetCurveTempProp( u, nCheckTmpProp, 0) ;
if ( u == 0)
nFirstTmpProp = nCheckTmpProp ;
else
if ( nFirstTmpProp != nCheckTmpProp)
bIsHomogenous = false ;
}
if ( bIsHomogenous) {
if ( nFirstTmpProp == 0)
vCrvClose.emplace_back( pCrvCompo->Clone()) ;
else if ( nFirstTmpProp == 1)
vCrvOpen.emplace_back( pCrvCompo->Clone()) ;
else
return false ;
return true ;
}
// ---------------------------------------------------------------------------------
// la curva ha sia tratti aperti che tratti chiusi, quindi sposto l'inizio a metà del tratto più lungo ( se richisto)...
if ( bCallAdjust) {
ICRVCOMPOPOVECTOR vCrvNULL ;
AdjustContourStart( pCrvCompo, vCrvNULL) ;
}
ICURVEPOVECTOR vCrvClose_tmp ;
// estraggo parti con proprietà uniforme in un vettore
int nCurrTempProp ;
int nParStart = 0 ;
for ( int i = 0 ; i < pCrvCompo->GetCurveCount() ; ++ i) {
int nTempProp ;
pCrvCompo->GetCurveTempProp( i, nTempProp) ;
if ( i == 0) {
nCurrTempProp = nTempProp ;
nParStart = i ;
}
else if ( nCurrTempProp != nTempProp) {
PtrOwner<ICurve> pCrv( pCrvCompo->CopyParamRange( nParStart, i)) ;
if ( IsNull( pCrv))
return false ;
pCrv->SetTempProp( nCurrTempProp) ;
PtrOwner<ICurveComposite> pCrvSameTmpProp( CreateCurveComposite()) ;
pCrvSameTmpProp->AddCurve( Release( pCrv)) ;
pCrvSameTmpProp->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ;
if ( nCurrTempProp == 1)
vCrvOpen.emplace_back( Release( pCrvSameTmpProp)) ; // se aperta
if ( nCurrTempProp == 0)
vCrvClose_tmp.emplace_back( Release( pCrvSameTmpProp)) ; // se chiusa
nCurrTempProp = nTempProp ;
nParStart = i ;
}
}
// unisco il primo e l'ultimo tratto chiuso, avendo cambiato l'inizio e la fine
if ( vCrvClose.size() > 0 && bCallAdjust) {
PtrOwner<ICurveComposite> pCrvCompoFirstLast( CreateCurveComposite()) ;
if ( IsNull( pCrvCompoFirstLast))
return false ;
pCrvCompoFirstLast->AddCurve( vCrvClose.back()->Clone()) ;
pCrvCompoFirstLast->AddCurve( vCrvClose.front()->Clone()) ;
vCrvClose.front().Set( Release( pCrvCompoFirstLast)) ;
vCrvClose.pop_back() ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetOptCrvIndex( const vector<ICRVCOMPOPOVECTOR>& vCrvOEWithFlags, int nStep, ISurfFlatRegion* pSrfChunkFinal,
int& nIndex)
{
// controllo dei parametri
if ( int( vCrvOEWithFlags.size()) == 0 || pSrfChunkFinal == nullptr || ! pSrfChunkFinal->IsValid())
return false ;
// cerco la curva originale del chunk (cc)-esimo ( per casi ottimizzati)
if (( int)vCrvOEWithFlags[nStep-1].size() == 1)
nIndex = 0 ;
else {
for ( int k = 0 ; k < ( int)vCrvOEWithFlags[nStep-1].size() ; ++k) {
CRVCVECTOR ccClass ;
if ( pSrfChunkFinal->GetCurveClassification( *vCrvOEWithFlags[nStep-1][k], EPS_SMALL, ccClass)) {
bool bIsThis = true ;
for ( int kk = 0 ; kk < ( int)ccClass.size() && bIsThis ; ++kk) {
if ( ccClass[kk].nClass == CRVC_OUT)
bIsThis = false ;
}
if ( bIsThis) {
nIndex = k ;
break ;
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, double dDiam, ICurveComposite* pCrvTrap,
Frame3d& frTrap, double& dPocketSize, int& nBase, int& nSecondBase)
{
// controllo parametri
if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid())
return false ;
pCrvTrap->Clear() ; // resterà vuota se il caso non è ottimizzato
nBase = -1 ;
nSecondBase = -1 ;
// se la curva è già un trapezio, non sempre devo adattarla...
Point3d pt ; Vector3d vtDir, vtB2, vtOtherDir ;
if ( pCrvCompo->IsATrapezoid( 100 * EPS_SMALL, pt, vtDir, vtOtherDir, vtB2)) {
pCrvTrap->AddCurve( pCrvCompo->Clone()) ;
// se parallelogramma scelgo come base i lati lunghi
Vector3d vtL2( - vtDir + vtOtherDir + vtB2) ;
if ( AreSameOrOppositeVectorApprox( vtOtherDir, vtL2)) {
if ( vtOtherDir.Len() > vtDir.Len())
swap( vtDir, vtOtherDir) ;
}
vtDir.Normalize() ;
Vector3d vtOrtho = OrthoCompo( vtOtherDir, vtDir) ;
dPocketSize = vtOrtho.Len() ;
// eventuale approssimazione della curva con polyline per ottenere la stessa curva calcolata in ICurveComposite::IsATrapezoid
if ( pCrvCompo->GetCurveCount() > 4) {
PolyLine PL ;
if ( ! pCrvCompo->ApproxWithLines( 100 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, PL))
return false ;
pCrvTrap->FromPolyLine( PL) ;
}
if ( ! CalcTrapezoidSpiralLocalFrame( pCrvTrap, vtDir, frTrap))
return false ;
// recupero flag aperto/chiuso dei lati
if ( pCrvTrap->GetCurve( 1)->GetTempProp( 0) == 0 && pCrvTrap->GetCurve( 3)->GetTempProp( 0) == 0) {
double dLen0, dLen2 ;
pCrvTrap->GetCurve( 0)->GetLength( dLen0) ;
pCrvTrap->GetCurve( 2)->GetLength( dLen2) ;
if ( dLen0 < dDiam - EPS_SMALL || dLen2 < dDiam - EPS_SMALL)
pCrvTrap->Clear() ;
}
// imposto le basi
nBase = 0 ;
nSecondBase = 2 ;
return true ;
}
// controllo il numero di lati chiusi e salvo i loro indici
int nClosedSide = 0 ;
INTVECTOR vIndClosedSides ;
for ( int u = 0 ; u < pCrvCompo->GetCurveCount() ; ++ u) {
int nTmpProp ;
if ( pCrvCompo->GetCurveTempProp( u, nTmpProp, 0) && nTmpProp == 0) {
++nClosedSide ;
vIndClosedSides.push_back( u) ;
}
}
// clono la curva Compo
PtrOwner<ICurveComposite> pCrvCompo_c( CloneCurveComposite( pCrvCompo)) ;
if ( IsNull( pCrvCompo_c))
return false ;
// tolleranza
const double TOLL = 50 * EPS_SMALL ;
// se tutti lati aperti
if ( nClosedSide == 0) {
// ricavo il box minimo della curva aperta ( passo dalla polyLine)
PolyLine PL ; Point3d ptCen ; double dWidth ;
if ( ! pCrvCompo->ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, PL) ||
! PL.GetMinAreaRectangleXY( ptCen, vtDir, dWidth, dPocketSize))
return false ;
// controllo dimY ( dHeight), se troppo estesa, non è un caso ottimizzato
if ( dPocketSize > dDiam + TOLL)
return true ;
// inverto il frame attuale
frTrap.Set( ptCen, Z_AX, vtDir) ;
if ( ! frTrap.IsValid())
return false ;
// creo il rettangolo del Box
pCrvTrap->AddPoint( Point3d( - 0.5 * dWidth, - 0.5 * dPocketSize, 0)) ;
pCrvTrap->AddLine( Point3d( 0.5 * dWidth, - 0.5 * dPocketSize, 0)) ;
pCrvTrap->AddLine( Point3d( 0.5 * dWidth, 0.5 * dPocketSize, 0)) ;
pCrvTrap->AddLine( Point3d( - 0.5 * dWidth, 0.5 * dPocketSize, 0)) ;
pCrvTrap->Close() ;
pCrvTrap->ToGlob( frTrap) ;
Point3d ptNewOrig ; pCrvTrap->GetStartPoint( ptNewOrig) ;
frTrap.Set( ptNewOrig, Z_AX, vtDir) ;
// imposto tutte le 4 curve come aperte
for ( int u = 0 ; u < pCrvTrap->GetCurveCount() ; ++ u)
pCrvTrap->SetCurveTempProp( u, 1, 0) ;
// imposto le basi
nBase = 0 ;
nSecondBase = 2 ;
}
// se un lato chiuso
else if ( nClosedSide == 1) {
// prendo l'unica curva chiusa
const ICurve* pCrvCurr = pCrvCompo->GetCurve( vIndClosedSides[0]) ;
if ( pCrvCurr == nullptr)
return false ;
// controllo se lineare ( altrimenti non è ottimizzato)
if ( pCrvCurr->GetType() != CRV_LINE)
return true ;
// prendo la direzione del tratto lineare
pCrvCurr->GetStartDir( vtDir) ;
// prendo il punto iniziale
Point3d ptStart ; pCrvCurr->GetStartPoint( ptStart) ;
// creo il riferimento basato su questo tratto
frTrap.Set( ptStart, Z_AX, vtDir) ;
if ( ! frTrap.IsValid())
return false ;
// porto la curva Compo ( clonandola) nel frame
pCrvCompo_c->ToLoc( frTrap) ;
// ricavo il box complessivo in questo frame
BBox3d BBox ;
pCrvCompo_c->GetLocalBBox( BBox) ;
// controllo dimY ( se troppo grande o lato chiuso non sul bordo del box => caso non ottimizzato)
if (( BBox.GetDimY() < dDiam + TOLL || BBox.GetDimX() < dDiam + TOLL) && BBox.GetMin().y > - TOLL) {
// creo il rettangolo del Box
pCrvTrap->AddPoint( BBox.GetMin()) ;
pCrvTrap->AddLine( BBox.GetMin() + BBox.GetDimX() * X_AX) ;
pCrvTrap->AddLine( BBox.GetMax()) ;
pCrvTrap->AddLine( BBox.GetMax() - BBox.GetDimX() * X_AX) ;
pCrvTrap->Close() ;
// porto in globale
pCrvTrap->ToGlob( frTrap) ;
// imposto tutte le curve come aperte tranne la prima ( estendo il solo lato chiuso come base del Box)
for ( int u = 0 ; u < pCrvTrap->GetCurveCount() ; ++ u)
pCrvTrap->SetCurveTempProp( u, u == 0 ? 0 : 1, 0) ;
// memorizzo la dimensione Y
dPocketSize = BBox.GetDimY() ;
// se il lato chiuso non può essere la base, allora sarà l'aperto ( del box)
if ( BBox.GetDimY() > dDiam + TOLL) {
dPocketSize = BBox.GetDimX() ;
pCrvTrap->ChangeStartPoint( 1.) ;
Point3d ptORIG ; pCrvTrap->GetStartPoint( ptORIG) ;
pCrvTrap->GetStartDir( vtDir) ;
frTrap.Set( ptORIG, Z_AX, vtDir) ;
}
}
// imposto le basi
nBase = 0 ;
nSecondBase = 2 ;
}
else {
// cerco la base
// Def di base :
// lato lineare chiuso, box nella sua direzione con DimY < 1.5 dDiam, box dei restanti chiusi ( almeno 1)
// con dimY < dDiam e lato lineare come lato del box ( è possibile trovare una seconda base, come altro lato chiuso
// parallelo alla base principale con distanza da essa circa il dDiam)
bool bBaseFound = false ; // flag per individuare base principale
BBox3d BBox ; // Box per base principale
// scorro i chiusi alla ricerca di una possibile base principale
for ( int i = 0 ; i < pCrvCompo->GetCurveCount() && ! bBaseFound ; ++ i) {
nBase = i ; // aggiorno l'indice
// prendo la curva
const ICurve* pCrvCurr = pCrvCompo->GetCurve( i) ;
if ( pCrvCurr == nullptr)
return false ;
// controllo se lineare, altrimenti passo alla successiva
if ( pCrvCurr->GetType() != CRV_LINE)
continue ;
// prendo la direzione del tratto lineare
pCrvCurr->GetStartDir( vtDir) ;
// prendo il punto iniziale
Point3d ptStart ; pCrvCurr->GetStartPoint( ptStart) ;
// creo il riferimento basato su questo tratto
frTrap.Set( ptStart, Z_AX, vtDir) ;
if ( ! frTrap.IsValid())
return false ;
// porto la curva Compo ( clonandola) nel frame
pCrvCompo_c.Set( pCrvCompo->Clone()) ;
pCrvCompo_c->ToLoc( frTrap) ;
// calcolo il box
pCrvCompo_c->GetLocalBBox( BBox) ;
// controllo dimY e dimX per il box
bool bDimYOk = BBox.GetDimY() < dDiam + TOLL && BBox.GetMin().y > - TOLL ;
bool bDimXOk = BBox.GetDimX() < dDiam + TOLL && BBox.GetMin().y > - TOLL ;
// se entrambe le dimensioni superano il diametro, questo lato non è la base, cerco il successivo
if ( !bDimXOk && !bDimYOk)
continue ;
// se dimY accettabile
if ( bDimYOk) {
bool bOk = false ;
if ( ! CheckTrapezoidClosedEdgePosition( pCrvCompo_c, i, BBox.GetDimY(), vIndClosedSides, bOk, pCrvTrap))
return false ;
if ( bOk) {
// pCrvTrap contiene il trapezio
nBase = 0 ;
nSecondBase = 2 ;
dPocketSize = BBox.GetDimY() ;
pCrvTrap->ToGlob( frTrap) ;
bBaseFound = true ;
}
else {
// cerco la seconda base
if ( ! CheckSecondBaseTrapezoid( pCrvCompo_c, i, nSecondBase))
return false ;
if ( nSecondBase != -1) {
// se ho trovato la seconda base
if ( ! PreparareTrapezoidTwoBases( pCrvCompo_c, BBox, i, nSecondBase, bOk, pCrvTrap))
return false ;
if ( bOk) {
// pCrvTrap contiene il trapezio
nBase = 0 ;
dPocketSize = BBox.GetDimY() ;
pCrvTrap->ToGlob( frTrap) ;
bBaseFound = true ;
}
}
}
}
// se dimX accettabile
if ( bDimYOk) {
// TODO :
}
}
// se non ho trovato una base principale => non è ottimizzato
if ( ! bBaseFound)
return true ;
}
// se parametro MaxOptSize non compatibile => non è ottimizzato
double dMaxOptSize ;
FromString( ExtractInfo( m_Params.m_sUserNotes, "MaxOptSize="), dMaxOptSize) ;
if ( FromString( ExtractInfo( m_Params.m_sUserNotes, "MaxOptSize="), dMaxOptSize) && dPocketSize > dMaxOptSize)
pCrvTrap->Clear() ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::CheckTrapezoidClosedEdgePosition( const ICurveComposite* pCrvCompo, const int nCrvInd, const double dDimBoxY,
INTVECTOR& vIndClosedSides, bool& bOk, ICurveComposite* pCrvTrap)
{
// controllo dei parametri
if ( pCrvCompo == nullptr)
return false ;
bOk = false ;
// controllo che ci siano due o tre lati chiusi
int nClosedEdge = int( vIndClosedSides.size()) ;
if ( nClosedEdge != 3)
return true ;
// TO DO se 2 chiusi consecutivi + gesitone archi
// prendo i 3 lati chiusi
const ICurve* pCrv0 = pCrvCompo->GetCurve( vIndClosedSides[0]) ;
const ICurve* pCrv1 = pCrvCompo->GetCurve( vIndClosedSides[1]) ;
const ICurve* pCrv2 = pCrvCompo->GetCurve( vIndClosedSides[2]) ;
if ( pCrv0 == nullptr || pCrv1 == nullptr || pCrv2 == nullptr)
return false ;
// controllo che siano lineari
if ( pCrv0->GetType() != CRV_LINE || pCrv1->GetType() != CRV_LINE || pCrv2->GetType() != CRV_LINE)
return true ;
// prendo i punti iniziali e finali
Point3d ptStart0 ; pCrv0->GetStartPoint( ptStart0) ;
Point3d ptEnd0 ; pCrv0->GetEndPoint( ptEnd0) ;
Point3d ptStart1 ; pCrv1->GetStartPoint( ptStart1) ;
Point3d ptEnd1 ; pCrv1->GetEndPoint( ptEnd1) ;
Point3d ptStart2 ; pCrv2->GetStartPoint( ptStart2) ;
Point3d ptEnd2 ; pCrv2->GetEndPoint( ptEnd2) ;
// controllo che siano consecutivi e cambio l'ordine se necessario
if ( AreSamePointApprox( ptEnd0, ptStart1) && AreSamePointApprox( ptEnd1, ptStart2))
;
else if ( AreSamePointApprox( ptEnd1, ptStart2) && AreSamePointApprox( ptEnd2, ptStart0)) {
swap( vIndClosedSides[0], vIndClosedSides[1]) ;
swap( vIndClosedSides[1], vIndClosedSides[2]) ;
}
else if ( AreSamePointApprox( ptEnd2, ptStart0) && AreSamePointApprox( ptEnd0, ptStart1)) {
swap( vIndClosedSides[0], vIndClosedSides[2]) ;
swap( vIndClosedSides[2], vIndClosedSides[1]) ;
}
else // se non consecutivi
return true ;
// se sono consecuti, ma la base non è il lato centrale, esco ( la ritroverò successivamente)
if ( vIndClosedSides[1] != nCrvInd)
return true ;
// parametri lavorazione
double dDiam = m_dDiam_Prec > 0 ? m_dDiam_Prec : m_TParams.m_dDiam ;
double dOffsR = m_dDiam_Prec > 0 ? m_dOffsetR_Prec : GetOffsR() ;
double dRad = 0.5 * dDiam + dOffsR ;
// -------------- creo il bordo del trapezio estendendo i lati obliqui se possibile ------------------------
// estendo
PtrOwner<ICurve> pEdge0( pCrvCompo->GetCurve( vIndClosedSides[0])->Clone()) ;
PtrOwner<ICurve> pEdge2( pCrvCompo->GetCurve( vIndClosedSides[2])->Clone()) ;
Point3d ptS0 ; pEdge0->GetStartPoint( ptS0) ;
Point3d ptE2 ; pEdge2->GetEndPoint( ptE2) ;
if ( abs( ptS0.y - dDimBoxY) > TOLL_TRAPEZOID) {
Vector3d vtDir ; pEdge0->GetStartDir( vtDir) ;
double dSinT = sqrt( 1 - vtDir.x * vtDir.x) ;
if ( dSinT > TOLL_TRAPEZOID) {
pEdge0->ExtendStartByLen(( dDimBoxY - ptS0.y) / dSinT) ;
pEdge0->GetStartPoint( ptS0) ;
}
}
if ( abs( ptE2.y - dDimBoxY) > TOLL_TRAPEZOID) {
Vector3d vtDir ; pEdge2->GetStartDir( vtDir) ;
double dSinT = sqrt( 1 - vtDir.x * vtDir.x) ;
if ( dSinT > TOLL_TRAPEZOID) {
pEdge2->ExtendEndByLen(( dDimBoxY - ptE2.y) / dSinT) ;
pEdge2->GetEndPoint( ptE2) ;
}
}
// creo il bordo del trapezio esteso
PtrOwner<ICurveComposite> pCrvTrapBorder( CreateCurveComposite()) ;
if ( IsNull( pCrvTrapBorder))
return false ;
pCrvTrapBorder->AddPoint( ptS0) ;
pCrvTrapBorder->AddCurve( Release( pEdge0)) ;
pCrvTrapBorder->AddCurve( pCrvCompo->GetCurve( vIndClosedSides[1])->Clone()) ;
pCrvTrapBorder->AddCurve( Release( pEdge2)) ;
pCrvTrapBorder->Close() ;
// ----------------------------------------------------------------------------------------------------------
// verifico dimensione x della svuotatura
double dLen0 = 0, dLen2 = 0 ;
pCrvTrapBorder->GetCurve( 0)->GetLength( dLen0) ;
pCrvTrapBorder->GetCurve( 2)->GetLength( dLen2) ;
if ( dLen0 < dDiam - EPS_SMALL || dLen2 < dDiam - EPS_SMALL)
return true ;
// creo un piccolo Offset e controllo che il trapezio non intersechi la curva Compo
OffsetCurve OffsCrv ;
if ( ! OffsCrv.Make( pCrvTrapBorder, TOLL_TRAPEZOID, ICurve::OFF_EXTEND)) {
m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ;
return false ;
}
PtrOwner<ICurve> pCrvOffs( OffsCrv.GetLongerCurve()) ;
if ( IsNull( pCrvOffs))
return false ;
IntersCurveCurve IntCC( *pCrvOffs, *pCrvCompo) ;
CRVCVECTOR ccClass ;
// se c'è intersezione, esco
if ( IntCC.GetRegionCurveClassification() != CCREGC_IN2)
return true ;
// costruisco il trapezio
pCrvCompo->GetCurve( vIndClosedSides[0])->GetStartPoint( ptS0) ;
pCrvTrap->AddPoint( ptS0) ;
pCrvTrap->AddCurve( pCrvCompo->GetCurve( vIndClosedSides[0])->Clone()) ;
pCrvTrap->AddCurve( pCrvCompo->GetCurve( vIndClosedSides[1])->Clone()) ;
pCrvTrap->AddCurve( pCrvCompo->GetCurve( vIndClosedSides[2])->Clone()) ;
pCrvTrap->Close() ;
pCrvTrap->SetCurveTempProp( pCrvTrap->GetCurveCount() - 1, 1, 0) ;
pCrvTrap->ChangeStartPoint( 1.) ; // la base è sempre la curva 0
bOk = true ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::CheckSecondBaseTrapezoid( const ICurveComposite* pCrvCompo, const int nCrvInd, int& nSecondBase)
{
// controllo parametri
if ( pCrvCompo == nullptr)
return false ;
// parametri lavorazione
double dDiam = m_dDiam_Prec > 0 ? m_dDiam_Prec : m_TParams.m_dDiam ;
double dOffsR = m_dDiam_Prec > 0 ? m_dOffsetR_Prec : GetOffsR() ;
double dRad = 0.5 * dDiam + dOffsR ;
nSecondBase = -1 ;
// scorro le altre curve lineari chiuse
for ( int u = 0 ; u < pCrvCompo->GetCurveCount() && nSecondBase == -1 ; ++ u) {
if ( u == nCrvInd || pCrvCompo->GetCurve( u)->GetType() != CRV_LINE)
continue ;
// recupero la direzione del tratto
Vector3d vtCurr_dir ; pCrvCompo->GetCurve( u)->GetStartDir( vtCurr_dir) ;
// direzioni parallele ma opposte
if ( AreOppositeVectorApprox( vtCurr_dir, X_AX)) {
// se le direzioni sono compatibili, controllo che la distanza sia ammissibile
const ICurve* pCrvCurr = pCrvCompo->GetCurve( nCrvInd) ;
Point3d ptS0, ptS1 ;
pCrvCurr->GetStartPoint( ptS0) ;
pCrvCompo->GetCurve( u)->GetStartPoint( ptS1) ;
if ( abs( ptS1.y - dDiam) < TOLL_TRAPEZOID)
nSecondBase = u ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::PreparareTrapezoidTwoBases( const ICurveComposite* pCrvCompo, BBox3d BBox, const int nBase, int& nSecondBase,
bool& bOk, ICurveComposite* pCrvTrap)
{
// controllo parametri
if ( pCrvCompo == nullptr)
return false ;
bOk = false ;
// le parti tra le due basi devono essere tutte omogenee ( o tutte aperte o tutte chiuse)
// pCrvTest0 sarà la parte destra, pCrvTest1 la parte sinistra
Point3d ptSB0, ptSB1 ;
PtrOwner<ICurveComposite> pCrvTest0( CloneCurveComposite( pCrvCompo)) ;
PtrOwner<ICurveComposite> pCrvTest1( CloneCurveComposite( pCrvCompo)) ;
pCrvCompo->GetCurve( nBase)->GetStartPoint( ptSB0) ;
pCrvCompo->GetCurve( nSecondBase)->GetStartPoint( ptSB1) ;
pCrvTest0->ChangeStartPoint( nBase) ;
pCrvTest1->ChangeStartPoint( nSecondBase) ;
double dUTrim0, dUTrim1 ;
pCrvTest0->GetParamAtPoint( ptSB1, dUTrim0) ;
pCrvTest1->GetParamAtPoint( ptSB0, dUTrim1) ;
pCrvTest0->TrimStartEndAtParam( 1, dUTrim0) ;
pCrvTest1->TrimStartEndAtParam( 1, dUTrim1) ;
// controllo che la parte destra si uniforme per le TmpProp
for ( int u = 0 ; u < pCrvTest0->GetCurveCount() - 1 ; ++ u) {
int nPropAct, nPropSucc ;
if ( pCrvTest0->GetCurveTempProp( u, nPropAct, 0) &&
pCrvTest0->GetCurveTempProp( u + 1, nPropSucc, 0) &&
nPropAct != nPropSucc)
return true ; // se TmpProp diverse => non è un caso ottimizzato
}
// controllo che la parte sinistra sia uniforme per le TmpProp
for ( int u = 0 ; u < pCrvTest1->GetCurveCount() - 1 ; ++ u) {
int nPropAct, nPropSucc ;
if ( pCrvTest1->GetCurveTempProp( u, nPropAct, 0) &&
pCrvTest1->GetCurveTempProp( u + 1, nPropSucc, 0) &&
nPropAct != nPropSucc)
return true ; // se TmpProp diverse => non è un caso ottimizzato
}
// parametri lavorazione
double dDiam = m_dDiam_Prec > 0 ? m_dDiam_Prec : m_TParams.m_dDiam ;
double dOffsR = m_dDiam_Prec > 0 ? m_dOffsetR_Prec : GetOffsR() ;
double dRad = 0.5 * dDiam + dOffsR ;
// creo la base principale e secondaria
PtrOwner<ICurve> pCrvBase0( pCrvCompo->GetCurve( nBase)->Clone()) ;
PtrOwner<ICurve> pCrvBase1( pCrvCompo->GetCurve( nSecondBase)->Clone()) ;
// ricavo i nuovi estremi
Point3d ptEB0, ptEB1 ;
pCrvBase0->GetStartPoint( ptSB0) ;
pCrvBase0->GetEndPoint( ptEB0) ;
pCrvBase1->GetStartPoint( ptSB1) ;
pCrvBase1->GetEndPoint( ptEB1) ;
// se lato destro aperto ( estendo il punto finale della base principale e il punto iniziale
// della base secondaria fino al lato destro del box)
bool bCopyRight = false ;
if ( pCrvTest0->GetCurve( 0)->GetTempProp( 0) == 1) {
ptEB0 = BBox.GetMin() + X_AX * BBox.GetDimX() ;
ptSB1 = ptEB0 + dDiam * Y_AX ;
}
// se lato destro chiuso
else
bCopyRight = true ;
// se lato sinistro aperto ( estendo il punto finale della base secondaria e il punto iniziale
// della base primaria dino al lato sinistro del box)
bool bCopyLeft = false ;
if ( pCrvTest1->GetCurve( 0)->GetTempProp( 0) == 1) {
ptSB0 = BBox.GetMin() ;
ptEB1 = BBox.GetMin() + dDiam * Y_AX ;
}
// se lato sinistro chiuso
else
bCopyLeft = true ;
// creo la curva da restituire
pCrvTrap->AddPoint( ptSB0) ;
pCrvTrap->AddLine( ptEB0) ;
if ( bCopyRight)
pCrvTrap->AddCurve( Release( pCrvTest0)) ;
else {
pCrvTrap->AddLine( ptSB1) ;
pCrvTrap->SetCurveTempProp( pCrvTrap->GetCurveCount() - 1, 1, 0) ; // aperta
}
nSecondBase = pCrvTrap->GetCurveCount() ;
pCrvTrap->AddLine( ptEB1) ;
if ( bCopyLeft)
pCrvTrap->AddCurve( Release( pCrvTest1)) ;
else {
pCrvTrap->Close() ;
pCrvTrap->SetCurveTempProp( pCrvTrap->GetCurveCount() - 1, 1, 0) ; // aperta
}
// verifico dimensione x della svuotatura nel caso tutto chiuso
if ( bCopyLeft && bCopyRight) {
double dLen0 = 0, dLen1 = 0 ;
pCrvBase0->GetLength( dLen0) ;
pCrvBase1->GetLength( dLen1) ;
if ( dLen0 < dDiam - EPS_SMALL || dLen1 < dDiam - EPS_SMALL) {
pCrvTrap->Clear() ;
return true ;
}
}
bOk = true ;
return true ;
}