Files
EgtMachKernel/Pocketing.cpp
T
Riccardo Elitropi e04805a99a EgtMachKernel :
- migliorie codice proiezione con grezzo.
2023-06-27 13:43:26 +02:00

12238 lines
513 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 <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"
// 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 ;
//----------------------------------------------------------------------------
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) ;
// 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 lavorazione (Cutter Location)
int nClId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_CL) ;
// se non c'è, lo aggiungo
if ( nClId == GDB_ID_NULL) {
nClId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ;
if ( nClId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nClId, MCH_CL) ;
}
// altrimenti lo svuoto
else
m_pGeomDB->EmptyGroup( nClId) ;
// lavoro ogni singola 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 ;
// 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 ;
}
// 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, 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) ;
// 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) ;
else
// salvo come prop 1 la faccia adiacente
pCrvCompo->SetCurveTempProp( nInd, nFlag, 1) ;
}
// passo al successivo
++nInd ;
bFound = vPL[i].GetNextU( dPar, true) ;
}
// assegno l'estrusione dalla normale alla faccia
pCrvCompo->SetExtrusion( vtN) ;
// --------------------------------- Proiezioni lati adiacenti --------------------------------------
// 1) Creo una regione piana dalla curva esterna
PtrOwner<ISurfFlatRegion> pSrfpCompo( CreateSurfFlatRegion()) ;
if ( IsNull( pSrfpCompo))
return false ;
pSrfpCompo->AddExtLoop( pCrvCompo->Clone()) ;
if ( IsNull( pSrfpCompo) || pSrfpCompo->GetChunkCount() == 0)
return false ;
bool bIspCompoMod = false ;
INTVECTOR vBannedId{ -1, nFacet} ;
// 2) scorro tutte le curve del bordo esterno
for ( int j = 0 ; j < pCrvCompo->GetCurveCount() ; ++ j) {
int nProp = 0 ;
// 3) controllo che nella seconda temp prop ho una faccia adiancente non già considerata da un altro bordo
// e creo un vettore con gli Id delle facce del bordo laterale adiacente alla curva j della pCrvCompo
if ( pCrvCompo->GetCurveTempProp( j, nProp, 1) && nProp != -1 //-> se la curva j ha una faccia adiacente...
&& find( vBannedId.begin(), vBannedId.end(), nProp) == vBannedId.end() //-> ...non già considerata da altre curve...
&& GetSurfByAdj( pSurf, vBannedId, nProp)) { //-> ...e riesco a ricavare tutte le facce del bordo
// 4) creo una regione piana con tutte le facce proiettate contenute
PtrOwner<ISurfFlatRegion> pSfrProj( CreateSurfFlatRegion()) ;
if ( ! IsNull( pSfrProj) && ProjectEdgesOnSelFace( pSrfpCompo, pSurf, vBannedId, nFacet, pSfrProj)) {
// sto modificando le singole superifici, quindi superificie del bordo esterno e superificie delle isole
if ( i == 0) {
if ( ! pSrfpCompo->Subtract( *pSfrProj))
return false ;
}
else {
if ( ! pSrfpCompo->Add( *pSfrProj))
return false ;
}
bIspCompoMod = true ;
}
}
}
// Ho creato una nuova FlatRegion.
// *** Se la curva originale è quella esterna -> tolgo le proiezioni ( non devo passare con il tool in quelle aree )
// *** Se la curva originale è quella di un'isola -> aggiungo le proiezioni ( così estraendo poi la curva mi trovo
// con un'isola più grande, comprendendo quindi le parti proiettare dove il tool non può passare )
// se questa nuova superificie è modificata rispetto a quella selezionata, devo aggiornare le curve, con quelle
// della nuova FlatRegion
if ( bIspCompoMod) {
// scorro ora il bordo della mia superificie
if( pSrfpCompo->GetChunkCount() == 0)
return false ;
PtrOwner<ICurveComposite> pCrvBorder( GetCurveComposite( pSrfpCompo->GetLoop( 0, 0))) ;
if ( IsNull( pCrvBorder) || pCrvBorder->GetCurveCount() == 0)
return false ;
for ( int c = 0 ; c < pCrvBorder->GetCurveCount() ; ++ c) {
int nStat = 0 ;
if ( ! SetTmpPropByOverlap( pCrvBorder, c, pCrvCompo, nStat))
return false ;
if ( nStat == 0 || nStat == 2) { // se non c'è overlap o geometria complessa
pCrvBorder->SetCurveTempProp( c, 0, 0) ; // lato chiuso
pCrvBorder->SetCurveTempProp( c, -1, 1) ; // lato esterno non definito
}
}
// risetto le proprietà iniziali della curva
pCrvCompo->Clear() ;
pCrvCompo->AddCurve( Release( pCrvBorder)) ;
}
// ------------------------------------------------------------------------------------------
// 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( CreateCurveComposite()) ;
if ( IsNull( pCrvCompo) || ! pCrvCompo->AddCurve( 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, ICurve* pCurve)
{
if ( pCurve == nullptr)
return false ;
// reset proprietà temporanee
ResetCurveAllTempProp( pCurve) ;
// verifico se presenti info per lati aperti
if ( ! 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)
pCC->SetCurveTempProp( j, 1) ;
}
// altrimenti
else {
if ( ! vOpen.empty() && vOpen[0] == 0)
pCurve->SetTempProp( 1) ;
}
return true ;
}
//----------------------------------------------------------------------------
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) ;
pCC->SetCurveTempProp( i, -1, 1) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::Chain( int nGrpDestId)
{
// vettore puntatori alle curve
ICURVEPOVECTOR vpCrvs ;
vpCrvs.reserve( m_vId.size()) ;
// vettore selettori delle curve originali
SELVECTOR vInds ;
// recupero tutte le curve e le porto in globale
for ( const auto& Id : m_vId) {
// prendo le curve
ICURVEPLIST lstPC ;
if ( ! GetCurves( Id, lstPC)) {
string sInfo = "Warning in 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) ;
const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( nPi) ;
if ( pGObj == nullptr)
return false ;
const ICurve* pOriCurve = ::GetCurve( pGObj) ;
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
bool bSomeOpen = m_pGeomDB->ExistsInfo( nPi, KEY_OPEN) ;
if ( bSomeOpen) {
int nOpen ;
if ( FromString( ExtractInfo( m_Params.m_sUserNotes, "Open="), nOpen) && nOpen == 0)
bSomeOpen = false ;
}
// annullo i flag di tratto aperto
for ( int i = 0 ; i < int( pCompoOriCrv->GetCurveCount()) ; ++i)
pCompoOriCrv->SetCurveTempProp( i, 0, 0) ; // alla sottocurva
// aggiorno flag per lati aperti
if ( bSomeOpen) {
INTVECTOR vOpen ;
m_pGeomDB->GetInfo( nPi, KEY_OPEN, vOpen) ;
for ( int j : vOpen)
pCompoOriCrv->SetCurveTempProp( j, 1, 0) ; // alla sottocurva
}
// 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 )
//int r = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompoOriCrv->Clone()) ;
//m_pGeomDB->SetMaterial( r, RED) ;
// 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 ;
}
// 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, 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, dOkStep, bSplitArcs))
return false ;
break ;
case POCKET_SUB_SPIRALOUT:
if ( ! AddSpiralOut( pSrfPock, vtTool, vtExtr, dDepth, dElev, dOkStep, bSplitArcs))
return false ;
break ;
}
}
m_nPockets++ ;
return true ;
}
//----------------------------------------------------------------------------
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 ;
// Campiono il contorno
int nMaxInd = pCompo->GetCurveCount() - 1 ;
for ( int i = 0 ; i <= nMaxInd ; ++ i) {
// curva corrente
const ICurve* pCrvC = pCompo->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 ; pCompo->GetCentroid( ptCen) ;
frPocket.Set( ptCen, vtTool) ;
// copio il contorno e lo porto nel riferimento
PtrOwner<ICurveComposite> pCompoL( pCompo->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 = 50 ;
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) {
Point3d ptStart ;
pLine->GetPointD1D2( ccOne.dParS, ICurve::FROM_PLUS, ptStart) ;
ptStart.ToGlob( frPocket) ;
Point3d ptEnd ;
pLine->GetPointD1D2( ccOne.dParE, ICurve::FROM_MINUS, 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 ;
}
}
}
}
// 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 ;
}
//----------------------------------------------------------------------------
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 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) ;
int nChunks = 0 ; // indica il numero di Chunk che ottengo effettuando l'offset per i percorsi a ZigZag
for( int c = 0 ; c < pSrfPock->GetChunkCount() ; ++ c) {
// copio il chunk c-esimo
PtrOwner<ISurfFlatRegion> pSrfChunk(( pSrfPock->CloneChunk( c))) ;
if ( IsNull( pSrfChunk))
return false ;
// --------------------------------------------------------------------------------------------------------
// 1) traslo il chunk c-esimo a seconda dello step e salvo la flat Region interna al grezzo
// ( evito di lavorare nel vuoto sempre la stessa faccia )
// 2) Proietto il Box del grezzo del semipiano positivo definito della Flat Region ottenuta in precedenza
// allargando in tangenza i lati chiusi fino al bordo di tale proiezione
// ( evito di trascurare parti di grezzo nella tasche con normale non parallela alla faccia del grezzo )
ISURFFRPOVECTOR vSrfSliced( nStep) ;
vector<ICRVCOMPOPOVECTOR> vCrvOEWithFlags( nStep) ;
BOOLVECTOR vbChangedPrec( nStep, false) ;
for ( int j = 1 ; j <= nStep ; ++ j) {
// controllo l'intersezione/proiezione tra la superificie e il grezzo
PtrOwner<ICurveComposite> pCrvOPF( CreateCurveComposite()) ;
Vector3d vtTrasl = -vtTool * ( dDepth - dElev + j * dStep) ;
ICRVCOMPOPOVECTOR vCrvOEF ;
bool bChanged = false ;
PtrOwner<ISurfFlatRegion> pSrfToAdapt( CloneSurfFlatRegion( pSrfChunk)) ;
if ( AdaptSfrWithRaw( pSrfToAdapt, vtTrasl, vCrvOEF, bChanged)) {
vSrfSliced[j-1].Set( pSrfToAdapt->Clone()) ;
// la superificie potrebbe non essere valida, 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( Release( vCrvOEF[h])) ;
// 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 ;
}
}
// ---------------------------------------------------------------------------------------------
// 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 ;
// ciclo su tutti i chunk della superificie per lo step j-esimo
for( int cc = 0 ; cc < vSrfSliced[j-1]->GetChunkCount() ; ++cc) {
// copio il Chunk (c)-esimo allo step (j)-esimo
PtrOwner<ISurfFlatRegion> pSrfChunkFinal(( vSrfSliced[j-1]->CloneChunk( cc))) ;
if ( IsNull( pSrfChunkFinal))
return false ;
// superficie per ingressi ed uscite
PtrOwner<ISurfFlatRegion> pSrfLeanInOut( CloneSurfFlatRegion( pSrfChunkFinal)) ;
if( IsNull( pSrfLeanInOut))
return false ;
// ----------------------------------------------------------------------------------
// Dopo che il chunk c-esimo è stato intersecato con il grezzo e allargato grazie alla proiezione,
// salvo il bordo ( con i flag dei lati aperti ) per il caso del trapezio ottimizzato.
// tuttavia, nel caso di più Chunks, devo individuare la curva originaria relativa al chunk cc-esimo
// ... il chunk cc-esimo non può avere parti esterne alla sua curva originaria
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 ;
}
}
}
}
// ------------------------------------------------------------------------------------
// 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) ;
// frame originario ( il frame frPocket viene modificato dalla Optmized ZigZag per orientare le
// passate a seconda di some sono disposti i lati aperti)
Frame3d frPocketOriByOpt ;
frPocketOriByOpt.Set( frPocket.Orig(), frPocket.VersX(), frPocket.VersY(), frPocket.VersZ()) ;
// porto la superificie nel nuovo sistema di riferimento
pSrfChunkFinal->ToLoc( frPocket) ;
// verifico se si tratta di caso ottimizzato
bool bOptimizedZigZag = false ;
bool bOutRawLeadIn = false ;
ICRVCOMPOPOVECTOR vpCrvs ; // vettore con i paths a ZigZag per il Chunk (c)-esimo allo step (j)-esimo
double dOptZigZagOffs ;
if ( ! OptimizedZigZag( pSrfChunkFinal, vtTool, dDepth, dSafeZ, frPocket, vCrvOEWithFlags[j-1][nInd], bOptimizedZigZag, vpCrvs, dOptZigZagOffs))
return false ;
if ( bOptimizedZigZag && ! vpCrvs.empty()) {
// se sono in un caso ottimizzato ...
nChunks = 1 ; // fisso il numero di chunk ad 1 per i bordi esterni ( che non verranno percorsi )
// verifico se attacco fuori dal grezzo
Point3d ptStart ;
vpCrvs[0]->GetStartPoint( ptStart) ;
Vector3d vtDir ;
vpCrvs[0]->GetStartDir( vtDir) ;
ptStart += -vtDir * ( m_TParams.m_dDiam / 2 - dOptZigZagOffs + dSafeZ) ;
ptStart.ToGlob( frPocket) ;
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)
vpCrvs[0]->ExtendStartByLen( m_TParams.m_dDiam / 2 - dOptZigZagOffs + dSafeZ) ;
}
// se non sono nel caso ottimizzato e ho un utensile che non lavora di testa
// poichè ingresso non fuori dal pezzo ... -> errore
if (( ! bOptimizedZigZag || ! ( bOutRawLeadIn || m_bOpenOutRaw)) && m_TParams.m_nType == TT_MILL_NOTIP) {
if ( ! LeadInRawIsOk()) {
m_pMchMgr->SetLastError( 2431, "Error in Pocketing : LeadIn with Mill NoTip in material") ;
return false ;
}
}
// se non sono nel caso ottimizzato, 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 ( ! bOptimizedZigZag) {
if ( ! pSrfZigZag->Offset( - dOffs - dExtra, ICurve::OFF_FILLET)) {
m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ;
return false ;
}
nChunks = pSrfZigZag->GetChunkCount() ; // facendo il primo Offset il Chunk (c)-esimo può generare altri Chunks...
}
// 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 )
// 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 ;
}
// memorizzo il numero di Chunks che ottengo effettuando Quest'ultimo Offset
int nChunksForCrv = pSrfForCrv->GetChunkCount() ;
// 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 < nChunksForCrv ; ++ cfc) { // scorro i chunk della superificie per i bordi
for ( int cfz = 0 ; cfz < nChunks ; ++ cfz) { // scorro i chunk della superificie per i percorsi ZigZag
// Se sono in un caso ottimizzato, ho già ottenuto il percorso a ZigZag, quindi non devo calcolare nulla
// Se invece non sono nel caso ottimizzato
if ( ! bOptimizedZigZag) {
// 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 ;
}
// 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
if ( m_TParams.m_nType == TT_MILL_POLISHING) {
// ciclo sui percorsi
for ( int k = 0 ; k < int( vpCrvs.size()) ; ++k) {
// se attacco a scivolo
if ( GetLeadInType() == POCKET_LI_GLIDE) {
double dU;
vpCrvs[k]->GetParamAtLength( m_Params.m_dLiTang, dU) ;
vpCrvs[k]->AddJoint( dU) ;
Point3d ptStart ;
vpCrvs[k]->GetStartPoint( ptStart) ;
vpCrvs[k]->ModifyStart( ptStart + vtTool * m_Params.m_dLiElev) ;
}
// se uscita a scivolo
if ( GetLeadOutType() == POCKET_LO_GLIDE) {
double dLen, dU ;
vpCrvs[k]->GetLength( dLen) ;
vpCrvs[k]->GetParamAtLength(dLen - m_Params.m_dLoTang, dU) ;
vpCrvs[k]->AddJoint( dU) ;
Point3d ptEnd ;
vpCrvs[k]->GetEndPoint( ptEnd) ;
vpCrvs[k]->ModifyEnd( ptEnd + vtTool * m_Params.m_dLiElev) ;
}
}
}
// ---------------------------- Disegno le curve a ZigZag (vpCrv) -------------------------
bool bStart = true ;
// ciclo sui percorsi
int nPath = int( vpCrvs.size());
for ( int k = 0 ; k < nPath ; ++ k) {
// ciclo sulle curve elementari
int nMaxInd = vpCrvs[k]->GetCurveCount() - 1 ;
for ( int i = 0 ; i <= nMaxInd ; ++ i) {
// curva corrente
const ICurve* pCrvC = vpCrvs[k]->GetCurve( i) ;
// copio la curva nel frame e nello step richiesto
PtrOwner<ICurve> pCurve( pCrvC->Clone()) ;
if ( IsNull( pCurve))
return false;
pCurve->ToGlob( frPocket) ;
pCurve->Translate( - vtTool * ( dDepth - dElev + j * dStep)) ;
// --- 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 ;
if ( ! GetElevation( m_nPhase, ptStart - 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)
dStElev = max( dStElev, j * dStep) ;
dStElev -= ( ptP1 - ptStart) * vtExtr ;
// se ottimizzata e attacco nel grezzo
if ( bOptimizedZigZag && !( 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 ;
}
}
Vector3d vtDirS, vtDirE ;
vpCrvs[0]->GetStartDir( vtDirS) ;
vpCrvs.back()->GetEndDir( vtDirE) ;
if ( nStep > 1 && j > 1 && AreOppositeVectorApprox( vtDirS, vtDirE) && bOutRawLeadIn
&& ( int)vpCrvs.size() == 1 && bOptimizedZigZag) {
dStElev = 0 ;
ptP1 = ptStart ;
}
// se inizio, approccio globale al punto iniziale
if ( bStart) {
//if ( k == 0 && j > 1 && vbChangedPrec[j-1])
// dStElev -= ( j-1) * dStep ;
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 && AreOppositeVectorApprox( vtDirS, vtDirE) && bOutRawLeadIn
&& ( int)vpCrvs.size() == 1 && bOptimizedZigZag)) {
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()) ;
//GetCurrPos( ptP1) ; // <----- ????
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) ;
DrawColoredCrvForFeedTest( pCurve, dFeed) ;
if ( pCurve->GetType() == CRV_LINE) {
ICurveLine* pLine = GetCurveLine( pCurve) ;
Point3d ptP3 = pLine->GetEnd() ;
//SetFeed( 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( GetFeed()) ;
if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL)
return false ;
}
// --- se ULTIMA ENTITA' ---
if ( i == nMaxInd) {
// per caso ottimizzato --------------
Vector3d vtDirS, vtDirE ;
vpCrvs[0]->GetStartDir( vtDirS) ;
vpCrvs.back()->GetEndDir( vtDirE) ;
if( nStep > 1 && j < nStep && AreOppositeVectorApprox( vtDirS, vtDirE) && bOutRawLeadIn
&& ( int)vpCrvs.size() == 1 && bOptimizedZigZag)
continue ;
// -----------------------------------
// dati fine entità
Point3d ptEnd ;
pCurve->GetEndPoint( ptEnd) ;
Vector3d vtEnd ;
pCurve->GetEndDir( vtEnd) ;
// aggiungo uscita
double dEndElev ;
if ( ! GetElevation( m_nPhase, ptEnd - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dEndElev))
dEndElev = j * dStep ;
dEndElev = max( dEndElev, j * dStep) ;
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 ;
}
//dEndElev = max( dEndElev, j * dStep) ;
// se lucidatura o caso ottimizzato e ultimo percorso di ultimo step, aggiungo retrazione
if (( m_TParams.m_nType == TT_MILL_POLISHING || bOptimizedZigZag) && k == nPath - 1 && 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 ;
}
}
}
}
}
}
// ------------------------------------------------------------------------------
// 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
// NB. se sono in un caso ottimizzato uso solo i loop interni
ICRVCOMPOPOVECTOR vAllCrv ;
for ( int l = bOptimizedZigZag ? 1 : 0 ; l < pSrfForCrv->GetLoopCount( cfc) ; ++ l) {
vAllCrv.emplace_back( GetCurveComposite( pSrfForCrv->GetLoop( cfc, l))) ;
}
// 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) ;
// se sono in un caso ottimizzato e non ho isole non ho bisogno di fare nulla...
if ( ! ( bOptimizedZigZag && ( int)vAllCrv.size() == 0)) { // ... altrimenti
// scorro tutte le curve da percorrere e calcolo gli ingressi...
for ( int u = 0 ; u < ( int)vAllCrv.size() ; ++u) {
// per ogni curva di bordo...
bool bOutTmp = false ;
if( ! SetBetterPtStartForSubChunks( vAllCrv[u], pSrfChunkFinal,
vPtStart[u], vVtMidOut[u], bOutTmp, dOffs))
return false ;
vbMidOut[u] = bOutTmp ; // vector<bool>::reference da Bit a Bool
// riporto i valori nel sistema di riferimento corretto
vPtStart[u].ToGlob( bOptimizedZigZag ? frPocketOriByOpt : frPocket) ;
vVtMidOut[u].ToGlob( bOptimizedZigZag ? frPocketOriByOpt : frPocket) ;
vAllCrv[u]->ToGlob( bOptimizedZigZag ? frPocketOriByOpt : frPocket) ;
// 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], nInd) ;
// 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;
}
}
}
}
// 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)
vpCrvs.back()->GetEndPoint( ptEnd) ;
if ( ! OrderCurvesByLastPntOfPath( vAllCrv, ptEnd, vPtStart, vVtMidOut, vbMidOut, vbForcedOutStart))
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 ;
// 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 ;
// copio la curva nel frame e nello step richiesto
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, 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, ptStart - 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)
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 ( ! AddLinkApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, vbMidOut[u] || vbForcedOutStart[u])) {
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, 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
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()) ;
if ( AddLinearMove( ptP3) == GDB_ID_NULL)
return false ;
}
else if ( pCurve->GetType() == CRV_ARC) {
ICurveArc* pArc( GetCurveArc( pCurve)) ;
Point3d ptCen = pArc->GetCenter() ;
double dAngCen = pArc->GetAngCenter() ;
Vector3d vtN = pArc->GetNormVersor() ;
Point3d ptP3 ;
pArc->GetEndPoint( ptP3) ;
//SetFeed( GetFeed());
if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL)
return false ;
}
// se ultima entità
if ( i == nMaxInd) {
// 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
double dEndElev ;
if ( ! GetElevation( m_nPhase, ptEnd - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dEndElev))
dEndElev = dStep ;
dEndElev = max( dEndElev, j * dStep) ;
SetFeed( GetEndFeed()) ;
if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, nullptr, bSplitArcs, false, ptP1, dEndElev, ( u == ( int)vAllCrv.size()))) {
m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ;
return false ;
}
// se ci sono ancora curve, aggiungo retrazione di collegamento
if ( pOffs->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 ;
}
}
//}
}
}
}
// --------------------------------------------------------------------------------
} // chiusura ciclo sui chunk cfc della superificie con Offset per contorni
} // chiusura ciclo sui chunk della superificie tagliata con il grezzo
} // chiusura ciclo sugli step
} // chiusura ciclo sui chunks
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) ;
vpCrvs.back()->TrimEndAtParam( dUS_Link) ;
//AssignFeedZigZagLink( pCrvLink) ; // assegno la Feed al Link
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())) {
pCrv1->TrimEndAtParam( dUE1) ;
pCrvLink->Clear() ;
pCrvLink->AddCurve( Release( pCrvTempLink)) ;
pCrv2->TrimStartAtParam( dUS2) ;
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) ;
pCrv1->TrimEndAtParam( dULink_s) ;
pCrvH2->GetStartPoint( ptCrv2_s) ;
pCrv2->GetParamAtPoint( ptCrv2_s, dULink_e) ;
pCrv2->TrimStartAtParam( dULink_e) ;
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,
double& dOffs)
{
// 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) ;
// setto proprietà sulle curve
if ( ! bSrfOriIsCut)
SetCurveAllTempProp( nCrvId, 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) ;
}
int nClosedSides = vnInfoClosed.size() ;
// modifico pCrvPocket per poterla passare a CalcZigZag
bool bTwoOpposite ;
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 ;
}
if ( ! bOptimizedZigZag)
return true ;
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( Release( pCrvPocket)) ; // la curva esterna modificata
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) ;
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 ;
}
ICRVCOMPOPOVECTOR vCrvAllLoops ;
double dMaxArea = -INFINITO; int nIndex = -1; int p = 0 ; // p è il # di loop totali
for ( int cu = 0 ; cu < pSrfPocketClone->GetChunkCount() ; ++ cu) {
for ( int l = 0 ; l < pSrfPocketClone->GetLoopCount( cu) ; ++ l) {
// inserisco i loops portandoli nel nuovo sistema di riferimento
PtrOwner<ICurveComposite> pCrvLoop( GetCurveComposite( pSrfPocketClone->GetLoop( cu, l))) ;
if ( IsNull( pCrvLoop))
return false ;
pCrvLoop->ToGlob( frameH) ;
pCrvLoop->ToLoc( frPocket) ;
double dArea ; pCrvLoop->GetAreaXY( dArea) ;
if ( dArea > dMaxArea) {
dMaxArea = dArea ;
nIndex = p ;
}
vCrvAllLoops.emplace_back( Release( pCrvLoop)) ;
p++ ;
}
}
for ( int i = 0 ; i < int( vCrvAllLoops.size()) ; ++ i) {
if ( i != nIndex) {
vFirstOffsets.emplace_back( vCrvAllLoops[i]->Clone()) ;
}
}
// creo la superficie da svuotare ottimizzata
SurfFlatRegionByContours pSrfMod ;
for ( int i = 0 ; i < int( vFirstOffsets.size()) ; ++ i)
pSrfMod.AddCurve( vFirstOffsets[i]->Clone()) ;
PtrOwner<ISurfFlatRegion> pSrfZigZag( pSrfMod.GetSurf()) ;
if ( IsNull( pSrfZigZag))
return false ;
if ( AreOppositeVectorApprox( vtExtr, pSrfZigZag->GetNormVersor()))
pSrfZigZag->Invert() ;
// calcolo il percorso di svuotatura
if ( ! CalcZigZag( pSrfZigZag, vpCrvs))
return false ;
// se un lato chiuso
if ( nClosedSides == 1) {
// inverto il percorso
vpCrvs[0]->Invert() ;
// verifico se attacco fuori dal grezzo
Point3d ptStart ;
vpCrvs[0]->GetStartPoint( ptStart) ;
Vector3d vtDir ;
vpCrvs[0]->GetStartDir( vtDir) ;
Point3d ptTest = ptStart + ( - vtDir) * ( m_TParams.m_dDiam / 2 - dOffs + dSafeZ) ;
ptTest.ToGlob( frPocket) ;
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 - dOffs, vtTool, dTestElev) && dTestElev > EPS_SMALL) {
Vector3d vtDirO = vtDir ;
vtDirO.Rotate( Z_AX, ( m_Params.m_bInvert ? -90 : 90)) ;
Point3d ptTestO = ptStart + vtDirO * ( m_TParams.m_dDiam / 2 - dOffs + dSafeZ) ;
ptTestO.ToGlob( frPocket) ;
ptTestO += - vtTool * dDepth ;
double dTestElevO ;
// se è fuori dal grezzo uso inizio ruotato
if ( ! GetElevation( m_nPhase, ptTestO, vtTool, m_TParams.m_dDiam / 2 - dOffs, vtTool, dTestElevO) || dTestElevO < EPS_SMALL) {
Point3d ptNewStart = ptStart + vtDirO ;
vpCrvs[0]->AddLine( ptNewStart, false) ;
}
}
}
// se due lati chiusi consecutivi o tre lati chiusi...
else if (( nClosedSides == 2 || nClosedSides == 3) && ! bTwoOpposite) {
// inverto il percorso
vpCrvs[0]->Invert() ;
// allungo opportunamente inizio e fine
Point3d ptStart ;
vpCrvs[0]->GetStartPoint( ptStart) ;
Vector3d vtDir ;
vpCrvs[0]->GetStartDir( vtDir) ;
vtDir.Rotate( Z_AX, ( m_Params.m_bInvert ? -90 : 90)) ;
ptStart += vtDir ;
Point3d ptEnd ;
vpCrvs[0]->GetEndPoint( ptEnd) ;
ptEnd += OrthoCompo( ptStart - ptEnd, X_AX) ;
vpCrvs[0]->AddLine( ptEnd, true) ;
vpCrvs[0]->AddLine( ptStart, false) ;
}
// estendo la fine del percorso
if ( ! ( nClosedSides == 3 && bTwoOpposite))
vpCrvs[0]->ExtendEndByLen( max( m_TParams.m_dDiam / 4 - dOffs, 0.0)) ;
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)
{
// ricavo l'estrusione
Vector3d vtExtr ; pCrvPocket->GetExtrusion( vtExtr) ;
// ricavo la Thickness
double dThick ; pCrvPocket->GetThickness( dThick) ;
// aggiusto offset
dOffs = m_TParams.m_dDiam / 2 + 5 * EPS_SMALL ;
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()) ;
pCrvPocket->SetExtrusion( vtExtr) ;
pCrvPocket->SetThickness( dThick) ;
}
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) ;
for ( int j = 1 ; j <= nStep ; ++ j) {
// controllo l'intersezione/proiezione tra la superificie e il grezzo
PtrOwner<ICurveComposite> pCrvOPF( CreateCurveComposite()) ;
Vector3d vtTrasl = -vtTool * ( dDepth - dElev + j * dStep) ;
ICRVCOMPOPOVECTOR vCrvOEF ;
bool bChanged = false ;
PtrOwner<ISurfFlatRegion> pSrfToAdapt( CloneSurfFlatRegion( pSrfIdeal)) ;
if ( AdaptSfrWithRaw( pSrfToAdapt, vtTrasl, vCrvOEF, bChanged)) {
vSrfSliced[j-1].Set( pSrfToAdapt->Clone()) ;
if ( ! IsNull( vSrfSliced[j-1])) {
for ( int h = 0 ; h < ( int)vCrvOEF.size() ; ++h)
vCrvOEWithFlags[j-1].emplace_back( Release( vCrvOEF[h])) ;
// 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 ;
}
}
Point3d ptP1 ;
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, dOffs))
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, vbForcedOutStart))
return false ;
// -------------------------------------------------------------------------------
// coefficiente di riduzione feed di lavorazione di questa curva
//double dFeedRid = min( GetSideStep() / m_TParams.m_dDiam, 1.0) ;
// creo la superificie svuotata ( per Feed )
//PtrOwner<ISurfFlatRegion> pSrfRemoved( CreateSurfFlatRegion()) ;
//if ( IsNull( pSrfRemoved))
// return false ;
//for ( int u = 0 ; u < vAllCrv.size() ; ++ u)
// GetDynamicClearedRegion( pSrfRemoved, vAllCrv[u]) ;
// ---------------------------- 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)
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, /*PNTVECTOR vPtStart,*/ const Vector3d& vtTool, const Vector3d& vtExtr,
double dDepth, double dElev, double dOkStep, bool bSplitArcs/*, BOOLVECTOR vbMidOpen,
PNTVECTOR vPtMidOpen, VCT3DVECTOR vVtMidOut, int nPathId*/)
{
// 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 ;
// --------------------------------------------------------------------------------------------------------
// 1) traslo il chunk c-esimo a seconda dello step e salvo la flat Region interna al grezzo
// ( evito di lavorare nel vuoto sempre la stessa faccia )
// 2) Proietto il Box del grezzo del semipiano positivo definito della Flat Region ottenuta in precedenza
// allargando in tangenza i lati chiusi fino al bordo di tale proiezione
// ( evito di trascurare parti di grezzo nella tasche con normale non parallela alla faccia del grezzo )
ISURFFRPOVECTOR vSrfSliced( nStep) ;
vector<ICRVCOMPOPOVECTOR> vCrvOEWithFlags( nStep) ;
BOOLVECTOR vbChangedPrec( nStep, false) ;
for ( int j = 1 ; j <= nStep ; ++ j) {
// controllo l'intersezione/proiezione tra la superificie e il grezzo
PtrOwner<ICurveComposite> pCrvOPF( CreateCurveComposite()) ;
Vector3d vtTrasl = -vtTool * ( dDepth - dElev + j * dStep) ;
ICRVCOMPOPOVECTOR vCrvOEF ;
bool bChanged = false ;
PtrOwner<ISurfFlatRegion> pSrfToAdapt( CloneSurfFlatRegion( pSrfChunk)) ;
if ( AdaptSfrWithRaw( pSrfToAdapt, vtTrasl, vCrvOEF, bChanged)) {
vSrfSliced[j-1].Set( pSrfToAdapt->Clone()) ;
// la superificie potrebbe non essere valida, 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( Release( vCrvOEF[h])) ;
// 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 ;
}
}
// ---------------------------------------------------------------------------------------------
Point3d ptP1 ; // per LeadIn
// 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 ;
for ( int cc = 0 ; cc < ( int)pSrfFinal->GetChunkCount() ; ++ cc) { // per ogni suo chunk cc-esimo...
// il numero di chunk dopo aver intersecato e proiettato con/il grezzo 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 ;
}
// 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 ;
}
bool bOptimizedTrap = false ;
// ----------------------------------------------------------------------------------
// Dopo che il chunk c-esimo è stato intersecato con il grezzo e allargato grazie alla proiezione,
// salvo il bordo ( con i flag dei lati aperti ) per il caso del trapezio ottimizzato.
// tuttavia, nel caso di più Chunks, devo individuare la curva originaria relativa al chunk cc-esimo
// ... il chunk cc-esimo non può avere parti esterne alla sua curva originaria
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 ;
}
}
}
}
// ------------------------------------------------------------------------------------
Point3d ptStart ; // punto iniziale del percorso
Vector3d vtMidOut ; // vettore verso l'esterno nel caso di entrata da fuori ammissibile
bool bMidOut ; // ammissibilità entrata da fuori
int nRegTot = nReg ;
//int k = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrfChunkFinal->Clone()) ;
//m_pGeomDB->SetMaterial( k, WHITE) ;
// calcolo il percorso di svuotatura
if ( ! CalcSpiral( pSrfChunkFinal, nRegTot, ptStart, vtMidOut, bMidOut, bSplitArcs, pMCrv, pRCrv, vCrvOEWithFlags[j-1][nInd], bOptimizedTrap))
return false ;
// se terminate le regioni, esco
if ( pMCrv->GetCurveCount() == 0)
break ; // passo al chunk originale successivo
++nReg ;
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 ;
}
}
// controlli per entrate da fuori al grezzo
bool 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( -vtTool * ( dDepth - dElev + j * dStep)) ; // 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( vtTool * ( dDepth - dElev + j * dStep)) ; // 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
bool 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 ( 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 ;
}
}
int nMaxInd = pMCrv->GetCurveCount() - 1 ;
int nMaxRInd = pRCrv->GetCurveCount() - 1 ;
// 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() ;
// 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( -vtTool * (dDepth - dElev + j * dStep)) ;
// 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 ;
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 )
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, bOutStart || bForcedOutStart)) {
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 || 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( -vtTool * ( dDepth - dElev + j * dStep)) ;
// 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)
pRet->TrimEndAtLen( dLen - m_Params.m_dLiTang) ;
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 = j * dStep ;
SetFeed( GetEndFeed()) ;
if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, pRCrv, bSplitArcs, false, ptP1, dEndElev, false)) {
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 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 ;
// --------------------------------------------------------------------------------------------------------
ISURFFRPOVECTOR vSrfSliced( nStep) ;
vector<ICRVCOMPOPOVECTOR> vCrvOEWithFlags( nStep) ;
BOOLVECTOR vbChangedPrec( nStep, false) ;
for ( int j = 1 ; j <= nStep ; ++ j) {
// controllo l'intersezione/proiezione tra la superificie e il grezzo
PtrOwner<ICurveComposite> pCrvOPF( CreateCurveComposite()) ;
Vector3d vtTrasl = -vtTool * ( dDepth - dElev + j * dStep) ;
ICRVCOMPOPOVECTOR vCrvOEF ;
bool bChanged = false ;
PtrOwner<ISurfFlatRegion> pSrfToAdapt( CloneSurfFlatRegion( pSrfChunk)) ;
if ( AdaptSfrWithRaw( pSrfToAdapt, vtTrasl, vCrvOEF, bChanged)) {
vSrfSliced[j-1].Set( pSrfToAdapt->Clone()) ;
// la superificie potrebbe non essere valida, 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( Release( vCrvOEF[h])) ;
// 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 ;
}
}
// ---------------------------------------------------------------------------------------------
Point3d ptP1 ;
// 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 ;
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 ;
}
// 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
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 ;
}
}
}
}
Point3d ptStart ;
Vector3d vtMidOut ;
bool bMidOut ;
int nRegToT = nReg ;
if ( ! CalcSpiral( pSrfChunkFinal, nRegToT, ptStart, vtMidOut, bMidOut, bSplitArcs, pMCrv, pRCrv, vCrvOEWithFlags[j-1][nInd], bOptimizedTrap))
return false ;
// se terminate le regioni, esco
if ( pMCrv->GetCurveCount() == 0)
break ;
++nReg ;
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 ;
}
}
// nel caso ottimizzato verifico se posso entrare e uscire fuori dal grezzo
bool 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() ;
}
int nMaxInd = pMCrv->GetCurveCount() - 1 ;
int nMaxRInd = pRCrv->GetCurveCount() - 1 ;
// ciclo sugli step
if ( bOptimizedTrap && nOutsideRaw != 1 && j > 1)
pMCrv->Invert() ;
// 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( -vtTool * (dDepth - dElev + j * dStep)) ;
// 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 || ( bOutStart && !m_bAboveHead))
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( -vtTool * ( dDepth - dElev + j * dStep)) ;
// 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)
pRet->TrimEndAtLen( dLen - m_Params.m_dLiTang) ;
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 = j * dStep ;
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& 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;
// controllo se ho isole per i casi ottimizzati
bool bHasIsland = pSrfPock->GetLoopCount( 0) > 1 ;
// se non ho isole allora controllo casi ottimizzati
if ( ! bHasIsland) {
// caso spirale
PtrOwner<ICurveComposite> pCrvBorder( GetCurveComposite( pSrfPock->GetLoop( 0, 0))) ;
Point3d ptCen ; Vector3d vtN ; double dRad ; bool bCCW ;
m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvBorder->Clone()) ;
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
pCrvOEWithFlags->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ;
Point3d pt ; Vector3d vtB1, vtL1, vtB2 ;
if ( pCrvOEWithFlags->IsATrapezoid( 100 * EPS_SMALL, pt, vtB1, vtL1, vtB2)) {
Vector3d vtDir( vtB1), vtOtherDir( vtL1) ;
// se parallelogramma scelgo come base i lati lunghi
Vector3d vtL2( - vtB1 + vtL1 + vtB2) ;
if ( AreSameOrOppositeVectorApprox( vtL1, vtL2)) {
if ( vtL1.Len() > vtB1.Len())
swap( vtDir, vtOtherDir) ;
}
vtDir.Normalize() ;
Vector3d vtOrtho = OrthoCompo( vtOtherDir, vtDir) ;
double dPocketSize = vtOrtho.Len() ;
double dMaxOptSize ;
FromString( ExtractInfo( m_Params.m_sUserNotes, "MaxOptSize="), dMaxOptSize) ;
if ( dPocketSize < m_TParams.m_dDiam + EPS_SMALL &&
( ! FromString( ExtractInfo( m_Params.m_sUserNotes, "MaxOptSize="), dMaxOptSize) ||
dPocketSize < dMaxOptSize)) {
if ( nReg == 0) {
CalcTrapezoidSpiral( pCrvOEWithFlags, vtDir, dPocketSize, pMCrv, pRCrv, bOptimizedTrap) ;
if ( bOptimizedTrap) {
nReg = 1 ;
return true ;
}
}
else
return true ;
}
}
}
// 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) ;
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, dOffR))
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 basi 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, dUS, dUE ;
vCurves[nIndex]->GetParamAtPoint( ptCL, dUTan) ;
pCrv1->AddCurve( vCurves[nIndex]->Clone()) ;
pCrv1->TrimEndAtParam( dUTan) ;
pCrv2->AddCurve( vCurves[nIndex]->Clone()) ;
pCrv2->TrimStartAtParam( dUTan) ;
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 dUS, dUE, dUTan ;
vCurves[nIndex]->GetParamAtPoint( ptCL, dUTan) ;
pCrv1->AddCurve( vCurves[nIndex]->Clone()) ;
pCrv1->TrimEndAtParam( dUTan) ;
pCrv2->AddCurve( vCurves[nIndex]->Clone()) ;
pCrv2->TrimStartAtParam( dUTan) ;
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 ;
// creo un percorso chiuso ...
//PtrOwner<ICurveComposite> pCrvPathClosed( CloneCurveComposite( pCrvPath)) ;
//if ( IsNull( pCrvPathClosed))
// return false ;
//pCrvPathClosed->AddCurve( pCrvCoBackLink->Clone()) ; // percorso chiuso con tutti i medial Axis Collegati
// 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 Vector3d& vtDir, double dPocketSize,
ICurveComposite* pMCrv, ICurveComposite* pRCrv, bool& bOptimizedTrap)
{
bOptimizedTrap = false ;
Vector3d vtExtr ; pCrvPocket->GetExtrusion( vtExtr) ;
// eventuale approssimazione della curva con polyline per ottenere la stessa curva calcolata in ICurveComposite::IsATrapezoid
if ( pCrvPocket->GetCurveCount() > 4) {
PolyLine PL ;
if ( ! pCrvPocket->ApproxWithLines( 100 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, PL))
return false ;
pCrvPocket->Clear() ;
pCrvPocket->FromPolyLine( PL) ;
pCrvPocket->SetExtrusion( vtExtr) ;
}
// sistemo senso antiorario visto dalla direzione di estrusione
Plane3d plPlane ; double dArea ;
pCrvPocket->GetArea( plPlane, dArea) ;
if ( plPlane.GetVersN() * vtExtr * dArea < 0)
pCrvPocket->Invert() ;
// 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
Frame3d frLoc ;
if ( ! CalcTrapezoidSpiralLocalFrame( pCrvPocket, vtDir, frLoc))
return false ;
pCrvPocket->ToLoc( frLoc) ;
// recupero flag aperto/chiuso dei lati (0=chiuso, 1=aperto)
INTVECTOR vnProp( 4, 0) ;
for ( int i = 0 ; i < 4 ; i++)
pCrvPocket->GetCurveTempProp( i, vnProp[i]) ;
// verifico le dimensioni della svuotatura
double dLen0 = 0, dLen2 = 0 ;
pCrvPocket->GetCurve( 0)->GetLength( dLen0) ;
pCrvPocket->GetCurve( 2)->GetLength( dLen2) ;
if ( vnProp[0] == 0 && abs( dPocketSize - m_TParams.m_dDiam) > EPS_SMALL)
return false ;
if ( vnProp[1] == 0 && vnProp[3] == 0) {
if ( dLen0 < m_TParams.m_dDiam - EPS_SMALL || dLen2 < m_TParams.m_dDiam - EPS_SMALL)
return false ;
}
// calcolo la larghezza massima della svuotatura (riferimento con X parallelo a primo lato chiuso)
Point3d ptOrig ;
pCrvPocket->GetCurve( 1)->GetStartPoint( ptOrig) ;
Vector3d vtX ;
pCrvPocket->GetCurve( 1)->GetStartDir( vtX) ;
Frame3d frDim ; frDim.Set( ptOrig, Z_AX, vtX) ; frDim.Invert() ;
BBox3d b3Dim ;
pCrvPocket->GetBBox( frDim, b3Dim, BBF_EXACT) ;
double dMaxLarg = b3Dim.GetDimY() ;
// calcolo percorso di svuotatura
// se lati obliqui sono entrambi chiusi e dimensione svuotatura è maggiore di diametro fresa e minore del doppio gestione speciale
if ( vnProp[0] != 0 && vnProp[2] != 0 && vnProp[3] == 0 && vnProp[1] == 0 &&
dMaxLarg > m_TParams.m_dDiam + 10 * EPS_SMALL && max( dLen0, dLen2) < 2 * m_TParams.m_dDiam + EPS_SMALL) {
if ( ! SpecialAdjustTrapezoidSpiralForAngles( pMCrv, pCrvPocket)) {
pMCrv->Clear() ;
return false ;
}
}
else {
double dYCoord = dPocketSize - 0.5 * m_TParams.m_dDiam ;
if ( vnProp[0] != 0)
dYCoord -= GetOffsR() ;
if ( vnProp[0] != 0 && vnProp[2] != 0)
dYCoord = 0.5 * dPocketSize ; // se entrambi i lati paralleli sono aperti mi posiziono a metà della svuotatura
double dXCoordStart, dXCoordEnd ;
if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, true, dYCoord, dXCoordStart, dPocketSize))
return false ;
if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, 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 ( vnProp[0] != 0) {
if ( vnProp[3] == 0 && ! AdjustTrapezoidSpiralForAngles( pMCrv, pCrvPocket, true)) {
pMCrv->Clear() ;
return false ;
}
if ( vnProp[1] == 0 && ! AdjustTrapezoidSpiralForAngles( pMCrv, pCrvPocket, false)) {
pMCrv->Clear() ;
return false ;
}
}
}
}
if ( pMCrv->GetCurveCount() == 0)
return true ;
pMCrv->ToGlob( frLoc) ;
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* pCrvPocket, const Vector3d& vtDir, Frame3d& frLoc)
{
// cerco i lati paralleli a vtDir
int nBaseId = -1 ;
for ( int i = 0 ; i < pCrvPocket->GetCurveCount() ; i ++) {
Vector3d vtEdge ;
pCrvPocket->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 (possibilmente aperto)
int nProp0, nProp2 ;
pCrvPocket->GetCurveTempProp( nBaseId, nProp0) ;
pCrvPocket->GetCurveTempProp( nBaseId + 2, nProp2) ;
if ( nProp0 == 0 && nProp2 != 0)
pCrvPocket->ChangeStartPoint( nBaseId + 2) ;
else
pCrvPocket->ChangeStartPoint( nBaseId) ;
Point3d ptOrig ;
pCrvPocket->GetStartPoint( ptOrig) ;
Vector3d vtExtr ;
pCrvPocket->GetExtrusion( vtExtr) ;
Vector3d vtX ;
pCrvPocket->GetStartDir( vtX) ;
return frLoc.Set( ptOrig, vtExtr, vtX) ;
}
//------------------------------------------------------
bool
Pocketing::CalcTrapezoidSpiralXCoord( const ICurveComposite* pCrvPocket, bool bStart, double dYCoord, double& dXCoord, double dPocketSize)
{
// se open
int nCrvId = ( bStart ? 3 : 1) ;
int nProp ;
if ( pCrvPocket->GetCurveTempProp( nCrvId, nProp) && nProp != 0) {
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 {
double dRad = 0.5 * m_TParams.m_dDiam + GetOffsR() ;
double dVal ;
Vector3d vtRef ;
pCrvPocket->GetCurve( nCrvId)->GetStartDir( vtRef) ;
double dCosAlpha = vtRef * X_AX ;
if ( dRad * dCosAlpha < dYCoord && dYCoord < dPocketSize + dRad * dCosAlpha) {
double dSinAlpha = ( vtRef ^ X_AX).Len() ;
if ( abs( dSinAlpha) < EPS_SMALL)
return false ;
dVal = 1.0 / dSinAlpha * ( dRad - dYCoord * dCosAlpha) ;
}
else if ( dYCoord < dRad * dCosAlpha)
dVal = sqrt( dRad * dRad - dYCoord * dYCoord) ;
else {
double dLen ;
pCrvPocket->GetCurve( nCrvId)->GetLength( dLen) ;
dVal = - dLen * dCosAlpha + sqrt( dRad * dRad - dYCoord * dYCoord) ;
}
Point3d ptRef ;
if ( bStart) {
pCrvPocket->GetCurve( nCrvId)->GetEndPoint( ptRef) ;
dXCoord = ptRef.x + dVal ;
}
else {
pCrvPocket->GetCurve( nCrvId)->GetStartPoint( ptRef) ;
dXCoord = ptRef.x - dVal ;
}
}
return true ;
}
//----------------------------------------------------
bool
Pocketing::AdjustTrapezoidSpiralForAngles( ICurveComposite* pMCrv, const ICurveComposite* pCrvPocket, bool bStart)
{
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( - 0.5 * m_TParams.m_dDiam - GetOffsR()) ;
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 * m_TParams.m_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( m_TParams.m_dDiam * m_TParams.m_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) ;
}
pMCrv->TrimStartAtParam( dPar) ;
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) ;
pMCrv->TrimStartAtParam( dPar) ;
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 - m_TParams.m_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 ICurveComposite* pCrvPocket)
{
// calcolo gli offset dei lati obliqui
PtrOwner<ICurveLine> pLineS( GetCurveLine( pCrvPocket->GetCurve( 3)->Clone())) ;
pLineS->SimpleOffset( - 0.5 * m_TParams.m_dDiam - GetOffsR()) ;
pLineS->Invert() ;
PtrOwner<ICurveLine> pLineE( GetCurveLine( pCrvPocket->GetCurve( 1)->Clone())) ;
pLineE->SimpleOffset( - 0.5 * m_TParams.m_dDiam - GetOffsR()) ;
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->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, 0, 0.5)) ;
// secondo raccordo
vtE.GetAngleXY( X_AX, dAng) ;
PtrOwner<ICurve> pBiArc2( GetBiArc( ptE, dAng, ptCrv2, 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 ( ! CalcDistanceFromRawSurface( m_nPhase, ptP, vtDirP, dDist, vtNorm))
// return false ;
if( ! GetSignedDistFromStmRaw( m_nPhase, ptP, vtDirP, dDist, vtNorm))
return false ;
if ( abs( dDist) < EPS_SMALL) {
ptP -= vtDirP ;
if ( ! CalcDistanceFromRawSurface( m_nPhase, 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 && GetSignedDistFromStmRaw( m_nPhase, ptP, vtDir, dDistMin, vtNorm)) {
if ( abs( dDistMin) < abs( dDist) && abs( dDistMin) > EPS_SMALL) {
dDistRef = dDistMin ;
dCorr = dDist / dDistMin ;
}
}
// se vicino al bordo del grezzo
if ( abs( dDistRef) < m_TParams.m_dDiam / 2 + 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 ( ! CalcDistanceFromRawSurface( m_nPhase, ptP, vtDirO, dDist, vtNorm))
// return false ;
if ( ! GetSignedDistFromStmRaw( m_nPhase, ptP, vtDirO, dDist, vtNorm))
return false ;
// se vicino al bordo del grezzo
if ( 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::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( CreateCurveComposite()) ;
if ( IsNull( pCompo) || ! pCompo->AddCurve( 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( CreateCurveComposite()) || ! pCrv->AddCurve( 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( CreateCurveComposite()) || ! pCrv->AddCurve( 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)
{
//int Y = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompo->Clone()) ;
//m_pGeomDB->SetMaterial( Y, YELLOW) ;
// 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() ;
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) ;
// 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 ;
}
}
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)
{
// 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)
continue ;
PtrOwner<ICurve> pCrvlonger( OffsCrv.GetLongerCurve()) ;
int W = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvlonger->Clone()) ;
m_pGeomDB->SetMaterial( W, WHITE) ;
while ( ! IsNull( pCrvlonger)) {
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
vpCrvs[i].Set( Release( pCrvlonger)) ;
pCrvlonger.Set( OffsCrv.GetLongerCurve()) ;
}
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) ;
}
}
//int green = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompo->Clone()) ;
//m_pGeomDB->SetMaterial( green, GREEN) ;
// 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) ;
// 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) {
// -----------------------------------------------------------------------------------
PtrOwner<ICurveComposite> pHHHH( CreateCurveComposite()) ;
pHHHH->AddCurve( vpCrvs[i]->Clone()) ;
Point3d ptS ; pCompo->GetEndPoint( ptS) ;
Point3d ptE ; vpCrvs[i+1]->GetStartPoint( ptE) ;
PtrOwner<ICurveComposite> pCrvNew( CreateCurveComposite()) ;
if ( AdjustPathOutsideRawForOpenEdges( pCompo_clone, vCrvIsl, pHHHH, ptS, ptE, dRad, dDiam, pCrvNew, vtTrasl, pStmRaw)) {
vpCrvs[i].Set( Release( pCrvNew)) ;
vpCrvs[i]->GetStartPoint( ptStart) ;
}
//int BRO = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vpCrvs[i]->Clone()) ;
//m_pGeomDB->SetMaterial( BRO, BROWN) ;
// -----------------------------------------------------------------------------------
// 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)) ;
int y = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pJCrv->Clone()) ;
m_pGeomDB->SetMaterial( y, YELLOW) ;
// assegno alle sue sottocurve la proprietà di curva aperta
//for ( int u = 0 ; u < pJCrv->GetCurveCount() ; ++ u)
// pJCrv->SetCurveTempProp( u, 1, 0) ;
// 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) {
// cerco la prima intersezione che entra nella curva aperta
for ( int j = 0 ; j < intCC.GetIntersCount() ; ++ j) {
if ( intCC.GetIntCrvCrvInfo( j, aInfo) && aInfo.IciA[0].nPrevTy == ICCT_OUT) {
bFound = true ;
break ;
}
}
}
if ( bFound) {
pJCrv->TrimEndAtParam( aInfo.IciA[0].dU) ;
vpCrvs[i]->TrimStartAtParam( aInfo.IciB[0].dU) ;
pCompo->AddCurve( ::Release( pJCrv), true, 10 * EPS_SMALL) ;
}
else {
pCompo->AddLine( ptStart) ;
pCompo->SetCurveTempProp( pCompo->GetCurveCount() - 1, 1, 0) ; // segmento come curva aperta
}
}
// 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) ;
pJCrv->RemoveFirstOrLastCurve( false) ;
int a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pJCrv->Clone()) ;
m_pGeomDB->SetMaterial( a, ORANGE) ;
// assegno alle sue sottocurve la proprietà di curva aperta
for ( int u = 0 ; u < pJCrv->GetCurveCount() ; ++ u)
pJCrv->SetCurveTempProp( u, 1, 0) ;
// calcolo l'intersezione nel piano della svuotatura dell'amo con la curva aperta
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() ;
//int A = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pLCrv->Clone()) ;
//m_pGeomDB->SetMaterial( A, AQUA) ;
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)) {
double dUs, dUe ; pCompo->GetDomain( dUs, dUe) ;
pCompo->TrimEndAtParam( dUe - dUL + aInfo.IciB[0].dU) ;
pJCrv->TrimStartAtParam( aInfo.IciA[0].dU) ;
pCompo->AddCurve( ::Release( pJCrv), true, 10 * EPS_SMALL) ;
}
else {
pCompo->AddLine( ptStart) ;
pCompo->SetCurveTempProp( pCompo->GetCurveCount() - 1, 1, 0) ; // segmento come curva aperta
}
}
else {
pCompo->AddLine( ptStart) ;
pCompo->SetCurveTempProp( pCompo->GetCurveCount() - 1, 1, 0) ; // segmento come curva aperta
}
}
}
// aggiungo la curva
pCompo->AddCurve( ::Release( vpCrvs[i]), true, 10 * EPS_SMALL) ;
//int p = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompo->Clone()) ;
//m_pGeomDB->SetMaterial( p, PURPLE) ;
}
// non dovrebbe esserci un gap, ma meglio prevenire problemi
pCompo->Close() ;
//int LI = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompo->Clone()) ;
//m_pGeomDB->SetMaterial( LI, LIME) ;
return true ;
}
//---------------------------------------------------------------------------
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)
{
// 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)) ;
pCompo_Prec->GetParamAtPoint( ptCrvOpenS, dUTrimS) ;
pCompo_Prec->TrimEndAtParam( dUTrimS) ;
//int B = m_pGeomDB->AddGeoObj(GDB_ID_NULL, GDB_ID_ROOT, pCompo_Prec->Clone()) ; //
//m_pGeomDB->SetMaterial( B, BLACK) ; //
PtrOwner<ICurveComposite> pCompo_Succ( CloneCurveComposite( pCompo)) ;
pCompo_Succ->GetParamAtPoint( ptCrvOpenE, dUTrimE) ;
pCompo_Succ->TrimStartAtParam( dUTrimE) ;
//int Bl = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompo_Succ->Clone()) ; //
//m_pGeomDB->SetMaterial( Bl, BLUE) ; //
PtrOwner<ICurveComposite> pCrvOpen( CloneCurveComposite( pCompo)) ;
pCrvOpen->TrimStartEndAtParam( dUTrimS, dUTrimE) ;
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) ;
pCrvOpen_clone->TrimStartEndAtParam( dUS, dUE) ;
// 4) Creo regione squadrata da questa curva
PtrOwner<ISurfFlatRegion> pSfrInc( GetSurfFlatRegionFromFatCurve( Release( pCrvOpen_clone), dRad, true, false)) ;
if ( IsNull( pSfrInc) || ! pSfrInc->IsValid())
return false ;
int black = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrInc->Clone()) ; //
m_pGeomDB->SetMaterial( black, BLACK) ; //
// -------------- 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())
return false ;
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( GetCurveComposite( pCrvCurr->CopyParamRange( ccClass[i].dParS,
ccClass[i].dParE))) ;
if ( IsNull( pCrvCurrPartIn) || ! pCrvCurrPartIn->IsValid())
continue ;
pCrvCurrPartIn->SetExtrusion( vtExtr) ;
// 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, - 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( Release( pCrvCurrPartIn)) ; // aggiunta del tratto interno
int rrr = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvExtBorder->Clone()) ;
m_pGeomDB->SetMaterial( rrr, RED) ;
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)) ;
int green = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrExpan->Clone()) ; //
m_pGeomDB->SetMaterial( green, GREEN) ; //
if ( pSfrExpan->IsValid()) {
if ( AreOppositeVectorApprox( pSfrExpan->GetNormVersor(), vtExtr))
pSfrExpan->Invert() ;
pSfrInc->Add( *pSfrExpan) ;
}
}
}
pOffLongestCrv.Set( OffsCrv.GetLongerCurve()) ;
}
}
}
}
else
return false ;
}
int brown1 = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrInc->Clone()) ; //
m_pGeomDB->SetMaterial( brown1, BROWN) ;
// recupero il Grezzo e sottraggo tutto ciò che sta nella regione
if ( pStmRaw != nullptr) {
bool bIsChanged ;
if ( m_bIntersRaw)
IntersSurfWithRaw( pSfrInc, pStmRaw, vtTrasl + Z_AX * 10 * EPS_SMALL, bIsChanged, 1500 * EPS_SMALL, false, false) ;
}
int brown = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrInc->Clone()) ; //
m_pGeomDB->SetMaterial( brown, BROWN) ;
// RECUPERO DELLA CURVA DI BORDO ESTERNA DA AGGIUNGERE ALLA SVUOTATURA
PtrOwner<ICurveComposite> pCrvNewBorder( GetCurveComposite( pSfrInc->GetLoop( 0, 0))) ;
if ( IsNull( pCrvNewBorder))
return false ;
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 ;
}
pCrvNewBorder->TrimEndAtParam( dUEND) ;
pNewCrv->Clear() ;
pNewCrv->AddCurve( Release( pCrvNewBorder)) ;
for ( int u = 0 ; u < pNewCrv->GetCurveCount() ; ++ u)
pNewCrv->SetCurveTempProp( u, 1, 0) ;
int P = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pNewCrv->Clone()) ; //
m_pGeomDB->SetMaterial( P, PURPLE) ;
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( GetCurveComposite( 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::CalcDistanceFromRawSurface( int nPhase, const Point3d& ptP, const Vector3d& vtDir, double& dDist, Vector3d& vtNorm)
{
//if ( ! GetElevation( nPhase, ptP, vtDir, dDist, vtNorm))
// return false ;
// se punto esterno al grezzo
//if ( abs( dDist) < EPS_SMALL) {
// double dDist1, dDist2 ;
// if ( ! GetElevation( nPhase, ptP, -vtDir, dDist1))
// return false ;
// if ( ! GetElevation( nPhase, ptP - vtDir * ( dDist1), vtDir, dDist2, vtNorm))
// return false ;
// if ( abs( dDist2) > EPS_SMALL && abs( dDist1) > EPS_SMALL)
// dDist = dDist2 - dDist1 ;
//}
//if ( ! GetElevation( nPhase, ptP, vtDir, dDist, vtNorm)
// || ! GetSignedDistFromStmRaw( nPhase, ptP, vtDir, dDist, vtNorm))
// return false ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::AdaptSfrWithRaw( ISurfFlatRegion* pSrf, Vector3d vtTrasl, ICRVCOMPOPOVECTOR& vCrvOEFlags,
bool& bChanged, double dAreaToll)
{
// controllo dei paramtri
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) ;
// ricavo il grezzo attuale della lavorazione
PtrOwner<ISurfTriMesh> pStmRaw( CreateSurfTriMesh()) ;
if ( ! GetStmRawPart( nProp0 , pStmRaw, GLOB_FRM))
return false ;
// se il grezzo è stato trovato, allora controllo intersezioni e proiezioni per lati aperti
if ( pStmRaw->IsValid() || pStmRaw->GetTriangleCount() > 0) {
// 1) INTERSEZIONE CON GREZZO
if ( m_bIntersRaw) {
if ( ! IntersSurfWithRaw( pSrf, pStmRaw, vtTrasl, bChanged, 500 * EPS_SMALL, true, m_dDiam_Prec < EPS_SMALL))
return false ;
if ( pSrf->GetChunkCount() == 0 || ! pSrf->IsValid())
return true ;
//int b = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrf->Clone()) ;
//m_pGeomDB->SetMaterial( b, BROWN) ;
}
// 2) PROIEZIONE CON GREZZO
if ( m_bProjectRaw) {
// recupero la Trimesh di partenza
if ( ! ProjectRaw( pSrf, vtTrasl, pStmRaw, nProp0))
return false ;
if ( pSrf->GetChunkCount() == 0 || ! pSrf->IsValid())
return true ;
int o = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrf->Clone()) ;
m_pGeomDB->SetMaterial( o, ORANGE) ;
}
}
// salvo una copia della superficie attuale
PtrOwner<ISurfFlatRegion> pSrf_noOpenEdge( CloneSurfFlatRegion( pSrf)) ;
if ( IsNull( pSrf_noOpenEdge))
return false ;
// 3) ESTENSIONE PER I LATI APERTI
if ( ! ModifySurfByOpenEdge( pSrf, vCrvOEFlags, vtTrasl, pStmRaw))
return false ;
int p = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrf->Clone()) ;
m_pGeomDB->SetMaterial( p, PURPLE) ;
// 4) SE SUPERIFICIE PRECEDENTEMENTE GIA' LAVORATA...
if ( m_dDiam_Prec > 0)
return GetNewSrfByAnotherPocketing( pSrf, pSrf_noOpenEdge, vtTrasl) ;
return pSrf->IsValid() && pSrf->GetChunkCount() != 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 ;
// 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( GetCurveComposite( pSrf->GetLoop( c, 0))) ;
if ( IsNull( pCrvEL))
return false ;
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( GetCurveComposite( 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( GetCurveComposite( 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( GetCurveComposite( pSfrHelp->GetLoop( 0, 0))) ;
for ( int l = 1 ; l < pSfrHelp->GetLoopCount( 0) ; ++ l) {
PtrOwner<ICurveComposite> pCrvClosedIsland( GetCurveComposite( 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 ;
int nCrvOpen = 0 ;
PtrOwner<ICurveComposite> pCrvIsl( GetCurveComposite( vCrvIsl[i]->Clone())) ;
for ( int u = 0 ; u < pCrvIsl->GetCurveCount() ; ++ u) {
if ( pCrvIsl->GetCurveTempProp( u, nProp0, 0) && nProp0 == 1) {
bSomeOpen = true ;
++ nCrvOpen ;
}
}
if ( bSomeOpen) { // se trovo dei lati aperti
// 5.1) se l'isola è tutta aperta e trascurabile la talgo
if ( nCrvOpen == pCrvIsl->GetCurveCount()) {
// 5.1.1) Offsetto l'isola e controllo se sparisce
OffsetCurve OffsCrv ;
if ( ! OffsCrv.Make( pCrvIsl, m_dDiam_Prec > 0 ? m_dDiam_Prec + m_dOffsetR_Prec : m_TParams.m_dDiam,
ICurve::OFF_FILLET)) {
m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ;
return false ;
}
// nel caso l'Offset sparisca, allora passo all'isola successiva
if ( OffsCrv.GetCurveCount() == 0)
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()) ;
}
// 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_) ;
}
pSrf->Clear() ;
pSrf->CopyFrom( pSrfFinal) ;
return pSrf->IsValid() && pSrf->GetChunkCount() > 0 ;
}
//----------------------------------------------------------------------------
bool
Pocketing::IntersSurfWithRaw( ISurfFlatRegion* pSfrPock, const ISurfTriMesh* pStmRaw, const Vector3d& vtTrasl,
bool& bIsChanged, double dAreaToll, bool bInVsOut, bool bRemoveSmallRawParts)
{
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) ||
//! m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStm->Clone()) || ! m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmRaw->Clone()) ||
! pStm->CutWithOtherSurf( *pStmRaw, bInVsOut, true) ||
pStm->GetTriangleCount() == 0) {
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) ||
pStm->GetTriangleCount() == 0) // nel caso non riesca ancora, lascio la superificie da svuotare inviariata...
return true ;
}
int A = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStm->Clone()) ;
m_pGeomDB->SetMaterial( A, AQUA) ;
// calcolo la nuova area e la confronto con la precedente ( capisco se la superificie è cambiata o meno)
double dAreaAfter = 0 ;
if ( ! pStm->GetArea( dAreaAfter) || abs( dAreaBefore - dAreaAfter) < dAreaToll)
return true ; // se la superificie non è cambiata, allora lascio tutto inviariato...
bIsChanged = true ;
// se le Aree sono cambiate, allora la superificie da svuotare interseca il grezzo
// ------------- creo la FlatRegion come sottrazione delle sue superifici -------------
// imposto i loop per la nuova FlatRegion dai loop della superificie Trimesh ottenuta per sottrazione
// 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) ;
// creo la nuova superificie da svuotare come FlatRegion
SurfFlatRegionByContours SrfChunkDef ;
POLYLINEVECTOR vPl ;
pStm->GetLoops( vPl) ;
for ( int i = 0 ; i < ( int)vPl.size() ; ++ i) {
// recupero la curva composita
PolyLine PL = vPl[i] ;
PtrOwner<ICurveComposite> pCrv( CreateCurveComposite()) ;
pCrv->FromPolyLine( PL) ;
// essendo una curva derivante da un'intersezione di Trimesh ho una composita derivante da una polyLine,
// devo recuperare gli archi
PolyArc PA ;
pCrv->ApproxWithArcsEx( 500 * EPS_SMALL, ANG_TOL_STD_DEG, LIN_FEA_STD, PA) ;
pCrv->Clear() ;
pCrv->FromPolyArc( PA) ;
pCrv->SetExtrusion( vtExtr) ;
pCrv->SetThickness( dThick) ;
//int V = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrv->Clone()) ;
//m_pGeomDB->SetMaterial( V, GREEN) ;
// la converto in una semplice cruva per proiettarla su piano della svuotatura
// dato che le curve sono prese da una trimesh, le riproietto sul piano traslato 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 ;
PtrOwner<ICurve> pCrv_proj( ProjectCurveOnPlane( *pCrv_c, plPock)) ;
//int L = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrv_proj->Clone()) ;
//m_pGeomDB->SetMaterial( L, LIME) ;
SrfChunkDef.AddCurve( Release( pCrv_proj)) ; // aggiungo le curve proiettate
}
PtrOwner<ISurfFlatRegion> pSrfByCurves( SrfChunkDef.GetSurf()) ;
if ( IsNull( pSrfByCurves) || pSrfByCurves->GetChunkCount() == 0) // controllo validità della FlatRegion
return false ;
// ------------- aggiunta delle piccole parti del grezzo -------------
// controllo se ho rimosso piccole regioni di grezzo...
// queste regioni possono creare problemi nella definizione di lati aperti
if ( bRemoveSmallRawParts) {
PtrOwner<ISurfFlatRegion> pSrf_RawPartsRemoved( CloneSurfFlatRegion( pSrfByCurves)) ;
PtrOwner<ISurfFlatRegion> pSrf_Pock_orig( CloneSurfFlatRegion( pSfrPock)) ;
if ( IsNull( pSrf_RawPartsRemoved) || ! pSrf_RawPartsRemoved->IsValid() ||
IsNull( pSrf_Pock_orig) || ! pSrf_Pock_orig->IsValid())
return false ;
pSrf_Pock_orig->Translate( vtTrasl) ;
if ( pSrf_Pock_orig->Subtract( *pSrf_RawPartsRemoved)) {
for ( int cc_ = 0 ; cc_ < pSrf_Pock_orig->GetChunkCount() ; ++ cc_) {
// clono dil Chunk cc_ esimo
PtrOwner<ISurfFlatRegion> pSrfCcc_( pSrf_Pock_orig->CloneChunk( cc_)) ;
if ( IsNull( pSrfCcc_) || ! pSrfCcc_->IsValid())
return false ;
if ( ! pSrfCcc_->Offset( m_dDiam_Prec > 0 ?
- 0.5 * m_dDiam_Prec - m_dOffsetR_Prec : - 0.5 * m_TParams.m_dDiam + GetOffsR(),
ICurve::OFF_FILLET) || pSrfCcc_->GetChunkCount() == 0) {
// se Offset interno sparisce, allora aggiungo il chunk cc_ esimo alla superificie da svuotare
PtrOwner<ISurfFlatRegion> pSrf_Chunck_cc_( pSrf_Pock_orig->CloneChunk( cc_)) ;
if ( IsNull( pSrf_Chunck_cc_) || ! pSrf_Chunck_cc_->IsValid())
return false ;
pSrfByCurves->Add( *Release( pSrf_Chunck_cc_)) ;
}
}
}
}
// riporto la superificie tagliata alla quota originale
pSrfByCurves->Translate( - vtTrasl) ;
// ricalcolo i lati aperti
if ( ! SetOpenOrCloseEdge( pSrfByCurves, pSfrPock))
return false ;
// modifico la superficie da svuotare
pSfrPock->Clear() ;
pSfrPock->CopyFrom( pSrfByCurves) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Pocketing::SetOpenOrCloseEdge( ISurfFlatRegion* pSrfTP, const ISurfFlatRegion* pSrfOrig)
{
// controllo parametri
if ( pSrfTP == nullptr || pSrfTP->GetChunkCount() == 0 || pSrfOrig == nullptr || pSrfOrig->GetChunkCount() == 0)
return false ;
// recupero le proprietà
PtrOwner<ICurve> pCrvEL( pSrfOrig->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 = pSrfOrig->GetChunkCount() ;
ICRVCOMPOPOVECTOR vCrvAll ;
for ( int c = 0 ; c < ( int)pSrfOrig->GetChunkCount() ; ++ c)
vCrvAll.emplace_back( GetCurveComposite( pSrfOrig->GetLoop( c, 0))) ;
for ( int c = 0 ; c < ( int)pSrfOrig->GetChunkCount() ; ++ c)
for ( int l = 1 ; l < ( int)pSrfOrig->GetLoopCount( c) ; ++ l)
vCrvAll.emplace_back( GetCurveComposite( pSrfOrig->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) {
PtrOwner<ICurveComposite> pCrv( GetCurveComposite( pSrfTP->GetLoop( c, l))) ;
if ( IsNull( pCrv))
return false ;
pCrv->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ;
for ( int i = 0 ; i < pCrv->GetCurveCount() ; ++ i) {
pCrv->SetCurveTempProp( i, -1, 0) ; // setto proprietà da definire di default
for ( int j = 0 ; j < ( int)vCrvAll.size() ; ++ j) {
int nStat = 0 ;
if ( ! SetTmpPropByOverlap( pCrv, i, vCrvAll[j], nStat))
return false ;
if ( nStat == 1) // se overlap Trovato, non controllo overlap su altri loops
break ;
}
}
// 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
for ( int i = 0 ; i < pCrv->GetCurveCount(); ++ i) { // nei casi di curve nuove ma senza overlap con isole ...
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) ;
// 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 ;
// dall'indice della geometria da svuotare, recupero l'Id del gruppo Processing in cui mi trovo
int nProcessingId = m_pGeomDB->GetParentId( nId) ;
if ( nProcessingId != GDB_ID_NULL) {
int nPartId = m_pGeomDB->GetParentId( nProcessingId) ;
if ( nPartId != GDB_ID_NULL) {
int nIdIter = m_pGeomDB->GetFirstNameInGroup( nPartId, BOX_NAME) ;
if ( nIdIter != GDB_ID_NULL) {
int nIdBox = m_pGeomDB->GetFirstInGroup( nIdIter) ;
if ( nIdBox != GDB_ID_NULL) {
const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( nIdBox) ;
Frame3d frRawPart ;
m_pGeomDB->GetGlobFrame( nIdIter, frRawPart) ;
if ( pGObj == nullptr)
return false ;
if ( pGObj->GetType() == SRF_TRIMESH) {
PtrOwner<ISurfTriMesh> pSrfRawPart( CloneSurfTriMesh( pGObj)) ;
if ( IsNull( pSrfRawPart))
return false ;
pSrfRawPart->LocToLoc( frRawPart, frPocket) ;
pSrfTMRaw->CopyFrom( pSrfRawPart) ;
}
}
}
}
}
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, BOOLVECTOR& vbForcedOutStart)
{
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)
{
// controllo parametri
if ( pSfrFacet == nullptr || pSfrFacet->GetChunkCount() == 0 || nFacet < 0)
return false ;
pSfrProj->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
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 ;
PtrOwner<ISurfFlatRegion> pSfrTemp( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrTemp))
return false ;
pSfrTemp->AddExtLoop( Release( pCrvProj)) ;
if ( pSfrTemp->IsValid()) {
if ( AreOppositeVectorApprox( pSfrTemp->GetNormVersor(), vtN))
pSfrTemp->Invert() ;
if ( pSfrProj->GetChunkCount() == 0)
pSfrProj->CopyFrom( pSfrTemp) ;
else
pSfrProj->Add( *pSfrTemp) ;
}
}
}
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::GetProjStmBoxOnSfr( const ISurfFlatRegion* pSfr, const ISurfTriMesh* pStmRaw, 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 ;
// recupero il piano di proiezione ( piano che contiene la flatRegion )
PtrOwner<ICurveComposite> pCrv( GetCurveComposite( pSfrPock->GetLoop( 0, 0))) ;
if ( IsNull( pCrv))
return false ;
Plane3d plProj ;
Point3d ptCen ;
if ( ! pCrv->GetCentroid( ptCen)) // punto
if ( ! pCrv->GetStartPoint( ptCen))
return false ;
Vector3d vtNorm = pSfrPock->GetNormVersor() ; // normale
if ( vtNorm.IsSmall())
return false ;
plProj.Set( ptCen, -vtNorm) ; // così taglio tutto cià che sta nel semipiano negativo
if ( ! plProj.IsValid())
return false ;
// recupero il box globale del grezzo
//BBox3d b3Raw ;
//if ( ! pStmRaw->GetBBox( GLOB_FRM, b3Raw) || b3Raw.IsEmpty())
// return false ;
// creo la trimesh del box globale del grezzo e la taglio con il piano
PtrOwner<ISurfTriMesh> pSrfRaw_clone( CloneSurfTriMesh( pStmRaw)) ;
if ( IsNull( pSrfRaw_clone))
return false ;
//PtrOwner<ISurfTriMesh> pStmRawClone( GetSurfTriMeshBox( b3Raw.GetDimX(), b3Raw.GetDimY(), b3Raw.GetDimZ())) ;
//if ( IsNull( pStmRawBox) || ! pStmRawBox->IsValid())
// return false ;
//pStmRawBox->Translate( b3Raw.GetMin() - ORIG) ; // è creata con ptMin nell'origine ( alla funzione passo le dimensioni)
if ( ! pSrfRaw_clone->Cut( plProj, true))
return false ;
if ( ! pSrfRaw_clone->IsValid() || pSrfRaw_clone->GetTriangleCount() == 0) {
pSfrRawBoxProj->Clear() ;
return true ;
}
// recupero solo la parte di TriMesh contente la superificie da svuotare
PtrOwner<ISurfTriMesh> pStr_real( CreateSurfTriMesh()) ;
for ( int p = 0 ; p < pSrfRaw_clone->GetPartCount() ; ++ p) {
PtrOwner<ISurfTriMesh> pStm_raw_part( pSrfRaw_clone->ClonePart( p)) ;
POLYLINEVECTOR vPl ;
pStm_raw_part->GetLoops( vPl) ;
for ( int l = 0 ; l < ( int)vPl.size() ; ++ l) {
PtrOwner<ICurveComposite> pCompo( CreateCurveComposite()) ;
pCompo->FromPolyLine( vPl[l]) ;
PtrOwner<ISurfFlatRegion> pSfr_H( CreateSurfFlatRegion()) ;
pSfr_H->AddExtLoop( Release( pCompo)) ;
if ( ! AreSameVectorApprox( pSfr_H->GetNormVersor(), pSfrPock->GetNormVersor()))
pSfr_H->Invert() ;
for ( int c = 0 ; c < pSfrPock->GetChunkCount() ; ++ c) {
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 ;
}
}
}
}
// creo una Regione piana a partire da tutte le curve
PtrOwner<ISurfFlatRegion> pSfrProj( CreateSurfFlatRegion()) ;
if( IsNull( pSfrProj))
return false ;
// proietto ora le curve, delle facce della superificie ottenuta, sul piano della svuotatura
for ( int f = 0 ; f < pStr_real->GetFacetCount() ; ++ f) {
POLYLINEVECTOR vPL ;
pStr_real->GetFacetLoops( f, vPL) ;
PtrOwner<ICurveComposite> pCrvBorder( CreateCurveComposite()) ;
if ( IsNull( pCrvBorder) || ! pCrvBorder->FromPolyLine( vPL[0])) // le facce del box sono semplici
return false ;
PtrOwner<ICurve> pCrvProjFacef( ProjectCurveOnPlane( *pCrvBorder, plProj)) ;
if ( IsNull( pCrvProjFacef) || ! pCrvProjFacef->IsValid())
return false ;
PtrOwner<ISurfFlatRegion> pSfrTmp( CreateSurfFlatRegion()) ;
pSfrTmp->AddExtLoop( pCrvProjFacef->Clone()) ;
if ( pSfrTmp->IsValid()) {
if ( AreOppositeVectorApprox( pSfrTmp->GetNormVersor(), - vtNorm))
pSfrTmp->Invert() ;
if ( pSfrProj->GetChunkCount() == 0)
pSfrProj->CopyFrom( pSfrTmp) ;
else
pSfrProj->Add( *pSfrTmp) ;
}
}
pSfrRawBoxProj->Clear() ;
pSfrRawBoxProj->CopyFrom( pSfrProj) ;
return pSfrRawBoxProj->Invert() && pSfrRawBoxProj->IsValid() && pSfrRawBoxProj->GetChunkCount() > 0 ;
}
//----------------------------------------------------------------------------
bool
Pocketing::ProjectRaw( ISurfFlatRegion* pSrf, const Vector3d& vtTrasl,
const ISurfTriMesh* pStmRaw, int nId)
{
// controllo dei paramtri
if ( pSrf == nullptr || ! pSrf->IsValid() || pSrf->GetChunkCount() == 0 ||
pStmRaw == nullptr || ! pStmRaw->IsValid() || pStmRaw->GetTriangleCount() == 0)
return false ;
// controllo se ho dei lati aperti, altrimenti non serve proiettare
bool bAllClosed = true ;
int nProp = -1 ;
for ( int c = 0 ; c < pSrf->GetChunkCount() && bAllClosed ; ++ c) {
for ( int l = 0 ; l < pSrf->GetLoopCount( c) && bAllClosed ; ++ l) {
PtrOwner<ICurveComposite> pCrvFC( GetCurveComposite( pSrf->GetLoop( c, l))) ;
if ( IsNull( pCrvFC))
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 ;
}
}
if ( bAllClosed)
return true ;
// traslo la superificie allo step corrente
pSrf->Translate( vtTrasl) ;
// ricavo il box del grezzo nel semipiano positivo definito dalla superificie di pocketing
PtrOwner<ISurfFlatRegion> pSrfOnPlPlus( CreateSurfFlatRegion()) ;
if ( IsNull( pSrfOnPlPlus) || ! GetProjStmBoxOnSfr( pSrf, pStmRaw, pSrfOnPlPlus))
return false ;
if ( IsNull( pSrfOnPlPlus) || ! pSrfOnPlPlus->IsValid()) {
pSrf->Clear() ;
return true ;
}
// recupero estrusione e spessore
PtrOwner<ICurve> pCrvEL( pSrf->GetLoop( 0, 0)) ;
if( IsNull( pCrvEL))
return false ;
Vector3d vtExtr ; pCrvEL->GetExtrusion( vtExtr) ;
double dthick ; pCrvEL->GetThickness( dthick) ;
// creo un frame Locale
Frame3d frLoc ;
Point3d ptOri ;
if ( ! pSrf->GetCentroid( ptOri))
if ( ! pCrvEL->GetStartPoint( ptOri))
return false ;
Vector3d vtZ = pSrf->GetNormVersor() ;
if ( vtZ.IsSmall())
return false ;
frLoc.Set( ptOri, vtZ) ;
// porto le superifici nel nuovo frame
pSrf->ToLoc( frLoc) ;
pSrfOnPlPlus->ToLoc( frLoc) ;
int G = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrfOnPlPlus->Clone()) ;
m_pGeomDB->SetMaterial( G, GREEN) ;
// creo la superificie finale da restituire
SurfFlatRegionByContours pSrfAfterProj ;
// modifico la curva esterna, estendola presso i lati aperti
for ( int c = 0 ; c < pSrf->GetChunkCount() ; ++ c) {
// curva esterna della regione da svuotare
PtrOwner<ICurveComposite> pCrvExtSfr( GetCurveComposite( pSrf->GetLoop( c, 0))) ;
if ( IsNull( pCrvExtSfr) || ! pCrvExtSfr->IsValid() || pCrvExtSfr->GetCurveCount() == 0)
return false ;
// creo un vettore con eventuali isole
ICRVCOMPOPOVECTOR vCrvIsl ;
for ( int l = 1 ; l < pSrf->GetLoopCount( c) ; ++ l)
vCrvIsl.emplace_back( GetCurveComposite( pSrf->GetLoop( c, l))) ;
// curva esterna della proeizione del box del grezzo sulla superficie da svuotare
PtrOwner<ICurveComposite> pCrvExtProj( GetCurveComposite( pSrfOnPlPlus->GetLoop( 0, 0))) ;
if ( IsNull( pCrvExtProj) || ! pCrvExtProj->IsValid() || pCrvExtProj->GetCurveCount() == 0)
return false ;
// derivando da una trimesh, semplifico le curve ( specialmente per circonferenze)
pCrvExtProj->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ;
pCrvExtSfr->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ;
int b = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvExtProj->Clone()) ;
m_pGeomDB->SetMaterial( b, BLACK) ;
int l = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvExtSfr->Clone()) ;
m_pGeomDB->SetMaterial( l, LIME) ;
// parametri
Vector3d vtS ; Vector3d vtE ;
Point3d ptS ; Point3d ptE ;
int nCont = 0 ; // contatore lati aperti consecutivi
PtrOwner<ICurveLine> pCrvLS( CreateCurveLine()) ; // linea Start
PtrOwner<ICurveLine> pCrvLE( CreateCurveLine()) ; // linea End
// 0 -> retta iniziale e finale ben definite
// 1 -> retta iniziale degenere ad un punto
// 2 -> retta finale degenere ad un punto
// 3 -> entrambe le rette degeneri ad un punto
int nStat = 0 ;
// cambio il punto iniziale della curva su un lato chiuso
bool bCEFound = false ;
int nTmpProp = 0 ;
for ( int u = 0 ; u < pCrvExtSfr->GetCurveCount() && !bCEFound ; ++ u) {
if ( pCrvExtSfr->GetCurveTempProp( u, nTmpProp ) && nTmpProp == 0) {
bCEFound = true ;
pCrvExtSfr->ChangeStartPoint( u) ;
}
}
// se la curva ha tutti lati aperti, allora la imposto uguale alla proiezione del grezzo ed esco
if ( ! bCEFound) {
pCrvExtSfr->Clear() ;
pCrvExtProj->ToGlob( frLoc) ;
pCrvExtSfr->AddCurve( Release( pCrvExtProj)) ;
if ( ! pCrvExtSfr->IsValid() || pCrvExtSfr->GetCurveCount() == 0 || ! pCrvExtSfr->IsClosed())
return false ;
for ( int i = 0 ; i < pCrvExtSfr->GetCurveCount() ; ++ i)
pCrvExtSfr->SetCurveTempProp( i, 1) ;
pCrvExtSfr->SetExtrusion( vtExtr) ;
pCrvExtSfr->SetThickness( dthick) ;
pCrvExtSfr->ToLoc( frLoc) ;
pSrfAfterProj.AddCurve( Release( pCrvExtSfr)) ;
//PtrOwner<ISurfFlatRegion> pSrf_h( CreateSurfFlatRegion()) ;
//for ( int cc = 0 ; cc < pSrf->GetChunkCount() ; ++ cc) {
// if ( cc != c)
// pSrf_h->Add( *pSrf->CloneChunk( cc)) ;
// else
// pSrf_h->AddExtLoop( Release( pCrvExtSfr)) ;
//}
// la proiezione con il grezzo potrebbe essere troppo grande
//pSrf->Clear() ;
//pSrfF->CopyFrom( pSrf_h) ;
//pSrf->Translate( - vtTrasl) ;
//return true ;
}
else {
//int O = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvExtProj->Clone()) ;
//m_pGeomDB->SetMaterial( O, ORANGE) ;
//int R = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvExtSfr->Clone()) ;
//m_pGeomDB->SetMaterial( R, RED) ;
// paramtri dU iniziali e finali del tratto di curva compreso tra le due rette
double dUS = EPS_SMALL ;
double dUE = EPS_SMALL ;
// scorro tutte le curve del contorno, cercando di raccordare linearmente i tratti aperti
// con il bordo della proiezione ( in modo da estendere la superficie da svuotare
bool bIsLastOpen = false ;
for ( int c = 0 ; c < pCrvExtSfr->GetCurveCount() || bIsLastOpen ; ++c) {
// recupero la curva c-esima
PtrOwner<ICurve> pCrv( pCrvExtSfr->GetCurve( bIsLastOpen ? 0 : c)->Clone()) ;
if ( IsNull( pCrv))
return false ;
// controllo se fa overlap con il bordo della proiezione e/o con il bordo di un isola aperta
int nStat1 = 0 ;
if ( ! CheckSimpleOverlap( pCrv, pCrvExtProj, nStat1, 5 * EPS_SMALL))
return false ;
// se lato aperto e non sulla curva esterna di proiezione...
if ( pCrv->GetTempProp() == 1 && nStat1 == 0) {
++ nCont ;
if ( nCont == 1) { // ... e primo lato aperto trovato
// creo la retta iniziale di raccordo
pCrvLS->Set( ptS, ptS + vtS * 10000) ;
int CC = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvLS->Clone()) ;
m_pGeomDB->SetMaterial( CC, AQUA) ;
// imposto il parametro inziale sulla curva
pCrvExtSfr->GetParamAtPoint( ptS, dUS) ;
// la spezzo alla prima intersezione con il grezzo
CRVCVECTOR ccClass ;
if ( pSrfOnPlPlus->GetCurveClassification( *pCrvLS, EPS_SMALL, ccClass) &&
( ccClass[0].nClass == CRVC_IN || ccClass[0].nClass == CRVC_ON_P || ccClass[0].nClass == CRVC_ON_M)) {
pCrvLS.Set( GetCurveLine( pCrvLS->CopyParamRange( 0, ccClass[0].dParE))) ;
pCrvLS->SetTempProp( ccClass[0].nClass == CRVC_IN ? 0 : 1) ;
}
else if (( int) ccClass.size() == 0) // retta iniziale degenere ad un punto
nStat = 1 ;
else { // esco ...
pSrf->ToGlob( frLoc) ;
pSrf->Translate( -vtTrasl) ;
return true ;
}
// nel caso in cui la retta tocca la curva della svuotatura n volte...
IntersCurveCurve intCCOpt( *pCrvLS, *pCrvExtSfr) ;
if ( intCCOpt.GetCurveClassification( 0, EPS_SMALL, ccClass) && ( int)ccClass.size() > 1) {
// salto questa proiezione, proviene da isole aperte
pSrf->ToGlob( frLoc) ;
pSrf->Translate( -vtTrasl) ;
return true ;
}
// se ultima curva ...
if ( c == pCrvExtSfr->GetCurveCount() - 1)
bIsLastOpen = true ;
}
}
else {
// se è un chiuso dopo n lati aperti non sulla proiezione...
if ( nCont > 0) {
pCrv->GetStartDir( vtE) ; vtE = -vtE ;
pCrv->GetStartPoint( ptE) ;
// setto la retta finale di raccordo
pCrvLE->Set( ptE, ptE + vtE * 10000) ;
int BB = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvLE->Clone()) ;
m_pGeomDB->SetMaterial( BB, BLUE) ;
// imposto il parametro finale sulla curva
pCrvExtSfr->GetParamAtPoint( ptE, dUE) ;
// controllo se il tratto di curva esterno alla superificie da svuotare
PtrOwner<ICurveComposite> pCrvToCheck( GetCurveComposite( pCrvExtSfr->CopyParamRange( dUS, dUE))) ;
if ( ! IsNull( pCrvToCheck) && pCrvToCheck->IsValid()) {
CRVCVECTOR ccClass_c ;
if ( pSrf->GetCurveClassification( *pCrvToCheck, EPS_SMALL, ccClass_c)) {
bool bIsPartOut = false ;
for ( int _c = 0 ; _c < ( int)ccClass_c.size() && ! bIsPartOut ; ++ _c) {
if ( ccClass_c[_c].nClass == CRVC_OUT)
bIsPartOut = true ;
}
// se la curva trovata non è esterna alla superificie ( caso in cui il grezzo sia interno alla
// curva di svuotatura, allora non allargo la sua proiezione al suo box)
if ( ! bIsPartOut) {
nCont = 0 ;
continue ;
}
}
}
// la spezzo alla prima intersezione con il grezzo
CRVCVECTOR ccClass ;
if ( pSrfOnPlPlus->GetCurveClassification( *pCrvLE, EPS_SMALL, ccClass) &&
( ccClass[0].nClass == CRVC_IN || ccClass[0].nClass == CRVC_ON_P || ccClass[0].nClass == CRVC_ON_M)) {
pCrvLE.Set( GetCurveLine( pCrvLE->CopyParamRange( 0, ccClass[0].dParE))) ;
pCrvLE->SetTempProp( ccClass[0].nClass == CRVC_IN ? 0 : 1) ;
}
else if (( int) ccClass.size() == 0) // retta finale degenere ad un punto
nStat = nStat == 1 ? 3 : 2 ;
else { // esco...
pSrf->ToGlob( frLoc) ;
pSrf->Translate( -vtTrasl) ;
return true ; // migliorare
}
// nel caso in cui la retta tocca la curva della svuotatura n volte...
IntersCurveCurve intCCOpt( *pCrvLE, *pCrvExtSfr) ;
if ( intCCOpt.GetCurveClassification( 0, EPS_SMALL, ccClass) && ( int)ccClass.size() > 1) {
// salto questa proiezione, proviene da isole aperte
pSrf->ToGlob( frLoc) ;
pSrf->Translate( -vtTrasl) ;
return true ;
}
int nCrv = pCrvExtSfr->GetCurveCount() ; // memorizzo il numero di curve attuali
PNTVECTOR vPtTan{ ptS, ptE} ;
if ( ! AjustCurveForProjRawOnFace( pCrvLS, pCrvLE, pCrvExtProj, pCrvExtSfr, nStat, vPtTan, pSrfOnPlPlus))
return false ;
c += pCrvExtSfr->GetCurveCount() - nCrv - 1 ; // aumento numero delle curve
nStat = 0 ; // ritorno al caso base per nStat
}
nCont = 0 ;
pCrv->GetEndDir( vtS) ;
pCrv->GetEndPoint( ptS) ;
if ( bIsLastOpen)
bIsLastOpen = false ;
}
}
// aggiungo la nuova curva esterna ricavata e le isole
pCrvExtSfr->SetExtrusion( vtExtr) ;
pCrvExtSfr->SetThickness( dthick) ;
pSrfAfterProj.AddCurve( Release( pCrvExtSfr)) ;
for ( int i = 0 ; i < ( int)vCrvIsl.size() ; ++ i) {
vCrvIsl[i]->SetExtrusion( vtExtr) ;
vCrvIsl[i]->SetThickness( dthick) ;
pSrfAfterProj.AddCurve( Release( vCrvIsl[i])) ;
}
}
}
// Superificie finale
PtrOwner<ISurfFlatRegion> pSrfF( CreateSurfFlatRegion()) ;
pSrfF.Set( pSrfAfterProj.GetSurf()) ;
// ritorno la nuova superificie
pSrf->Clear() ;
// se la superificie da svuotare viene da una Trimesh, taglio quest'ultima con la Trimesh Originale
if ( m_pGeomDB->GetGeoType( nId) == SRF_TRIMESH) {
ICRVCOMPOPOVECTOR vCrvAll ;
for ( int c = 0 ; c < ( int)pSrfF->GetChunkCount() ; ++ c)
vCrvAll.emplace_back( GetCurveComposite( pSrfF->GetLoop( c, 0))) ;
for ( int c = 0 ; c < ( int)pSrfF->GetChunkCount() ; ++ c)
for ( int l = 1 ; l < ( int)pSrfF->GetLoopCount( c) ; ++ l)
vCrvAll.emplace_back( GetCurveComposite( pSrfF->GetLoop( c, l))) ;
PtrOwner<ISurfTriMesh> pStm_orig( CloneSurfTriMesh( m_pGeomDB->GetGeoObj( nId))) ;
Frame3d frLoc1 ; m_pGeomDB->GetGlobFrame( nId, frLoc1) ;
pStm_orig->LocToLoc( frLoc1, frLoc) ;
PtrOwner<ISurfTriMesh> pSrfF_tm( CloneSurfTriMesh( pSrfF->GetAuxSurf())) ;
SurfFlatRegionByContours pSrf_HH ;
if ( pSrfF_tm->CutWithOtherSurf( *pStm_orig, false, true)) {
// estraggo tutti i loops
POLYLINEVECTOR vPl ;
pSrfF_tm->GetLoops( vPl) ;
for ( int ll = 0 ; ll < ( int)vPl.size() ; ++ ll) {
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
pCrvCompo->FromPolyLine( vPl[ll]) ;
for ( int u = 0 ; u < pCrvCompo->GetCurveCount() ; ++ u) {
for ( int j = 0 ; j < ( int)vCrvAll.size() ; ++ j) {
int nStat = -1 ;
pCrvCompo->SetCurveTempProp( u, 0, 0) ;
if ( SetTmpPropByOverlap( pCrvCompo, u, vCrvAll[j], nStat) && nStat == 1)
break ;
}
}
pSrf_HH.AddCurve( Release( pCrvCompo)) ;
}
pSrfF.Set( pSrf_HH.GetSurf()) ;
}
}
pSrf->CopyFrom( pSrfF) ;
pSrf->ToGlob( frLoc) ;
pSrf->Translate( -vtTrasl) ;
//int r = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrf->Clone()) ;
//m_pGeomDB->SetMaterial( r, RED) ;
return true ;
}
//----------------------------------------------------------------------------
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
if ( ! pCompo->IsPointOn( ptJ1A, EPS_SMALL) ||
! pCompo->IsPointOn( ptJ2A, EPS_SMALL) ||
! pCrvBorder->IsPointOn( ptJ1B, EPS_SMALL) ||
! pCrvBorder->IsPointOn( ptJ2B, EPS_SMALL))
return false ;
// 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 ; vCrvNoInters.reserve(( int)vOtherCrv.size()) ;
for ( int i = 0 ; i < ( int)vCrvNoInters.size() ; ++ i)
vCrvNoInters.emplace_back( CloneCurveComposite( vOtherCrv[i])) ;
// ricavo l'estrusione della curva composita
Vector3d vtExtr ;
if ( ! pCompo->GetExtrusion( vtExtr))
vtExtr = Z_AX ;
// ricavo il centroide o il punto centrale 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 * 1.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)) {
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...
//Vector3d vtPerpIn ;
PtrOwner<ICurveComposite> pCompoClone( CloneCurveComposite( pCompo)) ;
if ( IsNull( pCompoClone))
return false ;
double dU ;
pCompoClone->GetParamAtPoint( ptTest, dU) ;
pCompoClone->ChangeStartPoint( dU) ;
vtPerpIn.Normalize() ;
//pCompoClone->GetStartDir( vtPerpIn) ;
vtPerpIn.Rotate( Z_AX, 0, 1) ; // cos( pi/2) = 0, sin( pi/2) = 1
vtPerpIn *= (( 0.5 * m_TParams.m_dDiam + GetOffsR() + 5 * 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( *pCompo, *pCrvToolShape) ;
//int v = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompo->Clone()) ;
//m_pGeomDB->SetMaterial( v, GREEN) ;
//int p = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvToolShape->Clone()) ;
//m_pGeomDB->SetMaterial( p, PURPLE) ;
if ( intCC.GetCurveClassification( 0, EPS_SMALL, ccClass)) {
//if (( int)ccClass.size() == 3 && ccClass[1].nClass == CRVC_IN) {
// se ho solo due intersezioni, controllo di non intersecare isole
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, double dOffs)
{
// ============================= 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 entrares
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( GetCurveComposite( 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, 0, 0) ;
}
// 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( CloneCurveComposite( vCrvLoops[i])) ;
}
// 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, con 50 funziona la C, ma non la passata con il tool a 75 !
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) ;
// 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)) ;
pCrvOriRange->TrimStartEndAtParam( floor( dUS), ceil( dUE)) ;
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::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 ;
}
// <- secondo test
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) ;
pCrv_back->TrimEndAtParam( duS) ;
pCrv_forward->TrimStartAtParam( duE) ;
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 suvrapposizioni 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)) ;
pCrv_before->TrimEndAtParam( aInfo.IciA[0].dU) ;
PtrOwner<ICurveComposite> pCrv_after( CloneCurveComposite( pCrv)) ;
pCrv_after->TrimStartAtParam( aInfo.IciA[1].dU) ;
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)) ;
pCrvCompo->TrimStartAtParam( u) ;
pCrvCompo->TrimEndAtLen( dLen + m_TParams.m_dDiam) ;
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 ;
}