e8964930b3
- in SawFinishing aggiunta gestione per sezioni multiple evitando di lavorare tra di esse.
4390 lines
168 KiB
C++
4390 lines
168 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2015-2019
|
|
//----------------------------------------------------------------------------
|
|
// File : SawFinishing.cpp Data : 23.04.19 Versione : 2.1d3
|
|
// Contenuto : Implementazione gestione finitura superficie con lama.
|
|
//
|
|
// Note : Questa lavorazione è sempre espressa nel riferimento globale.
|
|
//
|
|
// Modifiche : 05.04.16 DS Creazione modulo.
|
|
// 23.04.19 DS Aggiunte cornici curve.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
#include "stdafx.h"
|
|
#include "MachMgr.h"
|
|
#include "DllMain.h"
|
|
#include "SawFinishing.h"
|
|
#include "OperationConst.h"
|
|
#include "OperUserNotesConst.h"
|
|
#include "GeoConst.h"
|
|
#include "/EgtDev/Include/EXeCmdLogOff.h"
|
|
#include "/EgtDev/Include/EXeConst.h"
|
|
#include "/EgtDev/Include/EGkCurveLine.h"
|
|
#include "/EgtDev/Include/EGkCurveArc.h"
|
|
#include "/EgtDev/Include/EGkCurveComposite.h"
|
|
#include "/EgtDev/Include/EGkCurveAux.h"
|
|
#include "/EgtDev/Include/EGkSurfLocal.h"
|
|
#include "/EgtDev/Include/EGkSurfTriMesh.h"
|
|
#include "/EgtDev/Include/EGkOffsetCurve.h"
|
|
#include "/EgtDev/Include/EGkOffsetCurveOnX.h"
|
|
#include "/EgtDev/Include/EGkSfrCreate.h"
|
|
#include "/EgtDev/Include/EGkIntervals.h"
|
|
#include "/EgtDev/Include/EGkPolygon3d.h"
|
|
#include "/EgtDev/Include/EGkPolygonElevation.h"
|
|
#include "/EgtDev/Include/EGkIntersLineSurfTm.h"
|
|
#include "/EgtDev/Include/EGkUserObjFactory.h"
|
|
#include "/EgtDev/Include/EGnStringKeyVal.h"
|
|
#include "/EgtDev/Include/EgtPointerOwner.h"
|
|
|
|
#define DEBUG_SAW_FIN 0
|
|
#if DEBUG_SAW_FIN
|
|
#include "EgtDev/Include/EGkGeoPoint3d.h"
|
|
#include "EgtDev/Include/EGkGeoVector3d.h"
|
|
#include "EgtDev/Include/EGkGeoFrame3d.h"
|
|
#endif
|
|
// per far dimenticare macro di WinUser.h
|
|
#undef GetClassName
|
|
|
|
using namespace std ;
|
|
|
|
//------------------------------ Errors --------------------------------------
|
|
// 2701 = "Error in SawFinishing : UpdateToolData failed"
|
|
// 2702 = "Error in SawFinishing : AdjustGeometry failed"
|
|
// 2703 = "Error in SawFinishing : Empty RawBox"
|
|
// 2704 = "Error in SawFinishing : Depth not computable"
|
|
// 2705 = "Error in SawFinishing : CalculateToolAndCorrVersors"
|
|
// 2706 = "Error in SawFinishing : ApproxWithLines"
|
|
// 2707 = "Error in SawFinishing : Guide Line not along X or Y"
|
|
// 2708 = "Error in SawFinishing : GetElevation"
|
|
// 2709 = "Error in SawFinishing : CalculateAlongToolPath failed"
|
|
// 2710 = "Error in SawFinishing : CalculateAcrossToolPath failed"
|
|
// 2711 = "Error in SawFinishing : axes values not calculable"
|
|
// 2712 = "Error in SawFinishing : outstroke xx"
|
|
// 2713 = "Error in SawFinishing : link movements not calculable"
|
|
// 2714 = "Error in SawFinishing : link outstroke xx"
|
|
// 2715 = "Error in SawFinishing : post apply not calculable"
|
|
// 2716 = "Error in SawFinishing : special apply not calculable"
|
|
// 2717 = "Error in SawFinishing : CalculateSectionToolPath failed"
|
|
// 2718 = "Error in SawFinishing : CalculateStraightAlong5AToolPath failed"
|
|
// 2719 = "Error in SawFinishing : Splitting Section failed"
|
|
// 2751 = "Warning in SawFinishing : Skipped entity (xx)"
|
|
// 2752 = "Warning in SawFinishing : No machinable path"
|
|
// 2753 = "Warning in SawFinishing : Tool name changed (xx)"
|
|
// 2754 = "Warning in SawFinishing : Tool data changed (xx)"
|
|
// 2755 = "Warning in SawFinishing : Link not compatible with extension"
|
|
|
|
//----------------------------------------------------------------------------
|
|
const string MCH_SECTION = "Sect" ;
|
|
const string MCH_GUIDE = "Guide" ;
|
|
enum nCrvClass {
|
|
CCL_SMALL = 0,
|
|
CCL_VERT = 1,
|
|
CCL_FLAT = 2,
|
|
CCL_FALL = 3,
|
|
CCL_RISE = 4
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
USEROBJ_REGISTER( GetOperationClass( OPER_SAWFINISHING), SawFinishing) ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
const string&
|
|
SawFinishing::GetClassName( void) const
|
|
{
|
|
return USEROBJ_GETNAME( SawFinishing) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
SawFinishing*
|
|
SawFinishing::Clone( void) const
|
|
{
|
|
// alloco oggetto
|
|
SawFinishing* pSaw = new(nothrow) SawFinishing ;
|
|
// eseguo copia dei dati
|
|
if ( pSaw != nullptr) {
|
|
try {
|
|
pSaw->m_vId = m_vId ;
|
|
pSaw->m_bStraight = m_bStraight ;
|
|
pSaw->m_pMchMgr = m_pMchMgr ;
|
|
pSaw->m_nPhase = m_nPhase ;
|
|
pSaw->m_Params = m_Params ;
|
|
pSaw->m_TParams = m_TParams ;
|
|
pSaw->m_nStatus = m_nStatus ;
|
|
pSaw->m_nCuts = m_nCuts ;
|
|
}
|
|
catch( ...) {
|
|
delete pSaw ;
|
|
return nullptr ;
|
|
}
|
|
}
|
|
// ritorno l'oggetto
|
|
return pSaw ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::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 ;
|
|
sOut += KEY_STRAIGHT + EQUAL + ToString( m_bStraight) + 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_nCuts) + szNewLine ;
|
|
sOut += KEY_STAT + EQUAL + ToString( m_nStatus) + szNewLine ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::Save( int nBaseId, STRVECTOR& vString) const
|
|
{
|
|
try {
|
|
int nSize = 1 + m_Params.GetSize() + m_TParams.GetSize() + 4 ;
|
|
vString.insert( vString.begin(), nSize, "") ;
|
|
int k = - 1 ;
|
|
if ( ! SetVal( KEY_IDS, m_vId, vString[++k]))
|
|
return false ;
|
|
for ( int i = 0 ; i < m_Params.GetSize() ; ++ i)
|
|
vString[++k] = m_Params.ToString( i) ;
|
|
for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i)
|
|
vString[++k] = m_TParams.ToString( i) ;
|
|
if ( ! SetVal( KEY_PHASE, m_nPhase, vString[++k]))
|
|
return false ;
|
|
if ( ! SetVal( KEY_NUM, m_nCuts, vString[++k]))
|
|
return false ;
|
|
if ( ! SetVal( KEY_STAT, m_nStatus, vString[++k]))
|
|
return false ;
|
|
if ( ! SetVal( KEY_STRAIGHT, m_bStraight, vString[++k]))
|
|
return false ;
|
|
}
|
|
catch( ...) {
|
|
return false ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::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_nCuts))
|
|
return false ;
|
|
}
|
|
else if ( sKey == KEY_STAT) {
|
|
if ( ! FromString( sVal, m_nStatus))
|
|
return false ;
|
|
}
|
|
else if ( sKey == KEY_STRAIGHT) {
|
|
if ( ! FromString( sVal, m_bStraight))
|
|
return false ;
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------
|
|
SawFinishing::SawFinishing( void)
|
|
{
|
|
m_Params.m_sName = "*" ;
|
|
m_Params.m_sToolName = "*" ;
|
|
m_TParams.m_sName = "*" ;
|
|
m_TParams.m_sHead = "*" ;
|
|
m_nStatus = MCH_ST_TO_VERIFY ;
|
|
m_nCuts = 0 ;
|
|
m_bStraight = true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::Prepare( const string& sSawName)
|
|
{
|
|
// verifico il gestore lavorazioni
|
|
if ( m_pMchMgr == nullptr)
|
|
return false ;
|
|
// recupero il gestore DB utensili della macchina corrente
|
|
ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ;
|
|
if ( pTMgr == nullptr)
|
|
return false ;
|
|
// recupero il gestore DB lavorazioni della macchina corrente
|
|
MachiningsMgr* pMMgr = m_pMchMgr->GetCurrMachiningsMgr() ;
|
|
if ( pMMgr == nullptr)
|
|
return false ;
|
|
// ricerca della lavorazione di libreria con il nome indicato
|
|
const SawFinishingData* pDdata = GetSawFinishingData( pMMgr->GetMachining( sSawName)) ;
|
|
if ( pDdata == nullptr)
|
|
return false ;
|
|
m_Params = *pDdata ;
|
|
// ricerca dell'utensile usato dalla lavorazione
|
|
const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ;
|
|
if ( pTdata == nullptr)
|
|
return false ;
|
|
m_TParams = *pTdata ;
|
|
m_Params.m_sToolName = m_TParams.m_sName ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::SetParam( int nType, bool bVal)
|
|
{
|
|
switch ( nType) {
|
|
case MPA_INVERT :
|
|
if ( bVal != m_Params.m_bInvert)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_bInvert = bVal ;
|
|
return true ;
|
|
}
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::SetParam( int nType, int nVal)
|
|
{
|
|
switch ( nType) {
|
|
case MPA_HEADSIDE :
|
|
if ( ! m_Params.VerifyHeadSide( nVal))
|
|
return false ;
|
|
if ( nVal != m_Params.m_nHeadSide)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_nHeadSide = nVal ;
|
|
return true ;
|
|
case MPA_STEPTYPE :
|
|
if ( ! m_Params.VerifyStepType( nVal))
|
|
return false ;
|
|
if ( nVal != m_Params.m_nStepType)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_nStepType = 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 ;
|
|
case MPA_LEADLINKTYPE :
|
|
if ( ! m_Params.VerifyLeadLinkType( nVal))
|
|
return false ;
|
|
if ( nVal != m_Params.m_nLeadLinkType)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_nLeadLinkType = nVal ;
|
|
return true ;
|
|
case MPA_SCC :
|
|
if ( ! m_Params.VerifySolCh( nVal))
|
|
return false ;
|
|
if ( nVal != m_Params.m_nSolCh)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_nSolCh = nVal ;
|
|
return true ;
|
|
}
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::SetParam( int nType, double dVal)
|
|
{
|
|
switch ( nType) {
|
|
case MPA_SPEED :
|
|
if ( ! m_TParams.VerifySpeed( dVal))
|
|
return false ;
|
|
if ( AreSameAngValue( dVal, m_TParams.m_dSpeed))
|
|
dVal = 0 ;
|
|
m_Params.m_dSpeed = dVal ;
|
|
return true ;
|
|
case MPA_FEED :
|
|
if ( AreSameLenValue( dVal, m_TParams.m_dFeed))
|
|
dVal = 0 ;
|
|
if ( ! AreSameLenValue( dVal, m_Params.m_dFeed))
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dFeed = dVal ;
|
|
return true ;
|
|
case MPA_STARTFEED :
|
|
if ( AreSameLenValue( dVal, m_TParams.m_dStartFeed))
|
|
dVal = 0 ;
|
|
if ( ! AreSameLenValue( dVal, m_Params.m_dStartFeed))
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dStartFeed = dVal ;
|
|
return true ;
|
|
case MPA_ENDFEED :
|
|
if ( AreSameLenValue( dVal, m_TParams.m_dEndFeed))
|
|
dVal = 0 ;
|
|
if ( ! AreSameLenValue( dVal, m_Params.m_dEndFeed))
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dEndFeed = dVal ;
|
|
return true ;
|
|
case MPA_TIPFEED :
|
|
if ( AreSameLenValue( dVal, m_TParams.m_dTipFeed))
|
|
dVal = 0 ;
|
|
if ( ! AreSameLenValue( dVal, m_Params.m_dTipFeed))
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dTipFeed = dVal ;
|
|
return true ;
|
|
case MPA_VERTFEED :
|
|
if ( AreSameLenValue( dVal, m_TParams.m_dFeed))
|
|
dVal = 0 ;
|
|
if ( ! AreSameLenValue( dVal, m_Params.m_dVertFeed))
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dVertFeed = dVal ;
|
|
return true ;
|
|
case MPA_OFFSR :
|
|
if ( AreSameLenValue( dVal, m_TParams.m_dOffsR))
|
|
dVal = UNKNOWN_PAR ;
|
|
if ( ! AreSameLenValue( dVal, m_Params.m_dOffsR))
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dOffsR = dVal ;
|
|
return true ;
|
|
case MPA_DEPTH: {
|
|
string sVal = ToString( dVal) ;
|
|
if ( sVal != m_Params.m_sDepth)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_sDepth = sVal ;
|
|
} return true ;
|
|
case MPA_STARTPOS :
|
|
if ( ! AreSameLenValue( dVal, m_Params.m_dStartPos))
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dStartPos = dVal ;
|
|
return true ;
|
|
case MPA_SIDESTEP :
|
|
if ( ! AreSameLenValue( dVal, m_Params.m_dSideStep))
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dSideStep = dVal ;
|
|
return true ;
|
|
case MPA_STEP :
|
|
if ( ! AreSameLenValue( dVal, m_Params.m_dStep))
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dStep = dVal ;
|
|
return true ;
|
|
case MPA_APPROX :
|
|
if ( ! AreSameLenValue( dVal, m_Params.m_dApprox))
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dApprox = dVal ;
|
|
return true ;
|
|
case MPA_STARTADDLEN :
|
|
if ( ! AreSameLenValue( dVal, m_Params.m_dStartAddLen))
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dStartAddLen = dVal ;
|
|
return true ;
|
|
case MPA_ENDADDLEN :
|
|
if ( ! AreSameLenValue( dVal, m_Params.m_dEndAddLen))
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dEndAddLen = dVal ;
|
|
return true ;
|
|
}
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::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
|
|
SawFinishing::SetGeometry( const SELVECTOR& vIds)
|
|
{
|
|
// verifico validità gestore DB geometrico
|
|
if ( m_pGeomDB == nullptr)
|
|
return false ;
|
|
// copia temporanea e reset della geometria corrente
|
|
SELVECTOR vOldId = m_vId ;
|
|
m_vId.clear() ;
|
|
// verifico che gli identificativi rappresentino delle entità ammissibili
|
|
for ( const auto& Id : vIds) {
|
|
// test sull'entità
|
|
int nSubs ;
|
|
if ( ! VerifyGeometry( Id, nSubs)) {
|
|
string sInfo = "Warning in SawFinishing : Skipped entity " + ToString( Id) ;
|
|
m_pMchMgr->SetWarning( 2751, sInfo) ;
|
|
continue ;
|
|
}
|
|
// posso aggiungere alla lista
|
|
m_vId.emplace_back( Id) ;
|
|
}
|
|
// aggiorno lo stato
|
|
if ( m_vId != vOldId)
|
|
m_nStatus |= MCH_ST_GEO_MODIF ;
|
|
// restituisco presenza geometria da lavorare
|
|
return ( ! m_vId.empty()) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::Preview( bool bRecalc)
|
|
{
|
|
// non esiste preview, si fa apply
|
|
return Apply( bRecalc, false) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::Apply( bool bRecalc, bool bPostApply)
|
|
{
|
|
// reset numero tagli nella lavorazione
|
|
int nCurrCuts = m_nCuts ;
|
|
m_nCuts = 0 ;
|
|
|
|
// verifico validità gestore DB geometrico e Id del gruppo
|
|
if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId))
|
|
return false ;
|
|
|
|
// aggiorno dati geometrici dell'utensile
|
|
if ( ! UpdateToolData()) {
|
|
m_pMchMgr->SetLastError( 2701, "Error in SawFinishing : UpdateToolData failed") ;
|
|
return false ;
|
|
}
|
|
|
|
// se modificata geometria, necessario ricalcolo
|
|
if ( ( m_nStatus & MCH_ST_GEO_MODIF) != 0)
|
|
bRecalc = true ;
|
|
|
|
// verifico se necessario continuare nell'aggiornamento
|
|
if ( ! bRecalc && ( m_nStatus == MCH_ST_OK || m_nStatus == MCH_ST_NO_POSTAPPL)) {
|
|
// confermo i percorsi di lavorazione
|
|
m_nCuts = nCurrCuts ;
|
|
string sLog = string( "SawFinishing apply skipped : status ") + ( m_nStatus == MCH_ST_OK ? "already ok" : "no postapply") ;
|
|
LOG_DBG_INFO( GetEMkLogger(), sLog.c_str()) ;
|
|
// eseguo aggiornamento assi macchina e collegamento con operazione precedente
|
|
if ( ! Update( bPostApply))
|
|
return false ;
|
|
m_nStatus = ( bPostApply ? MCH_ST_OK : MCH_ST_NO_POSTAPPL) ;
|
|
LOG_DBG_INFO( GetEMkLogger(), "Update done") ;
|
|
// esco con successo
|
|
return true ;
|
|
}
|
|
m_nStatus = MCH_ST_TO_VERIFY ;
|
|
|
|
// recupero gruppo per geometria ausiliaria
|
|
int nAuxId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_AUX) ;
|
|
// 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) ;
|
|
bRecalc = true ;
|
|
}
|
|
// altrimenti, se chiesto ricalcolo, lo svuoto
|
|
else if ( bRecalc) {
|
|
m_pGeomDB->EmptyGroup( nAuxId) ;
|
|
}
|
|
|
|
// se necessario, preparo geometria e la inserisco sotto la geometria ausiliaria
|
|
if ( bRecalc && ! AdjustGeometry( nAuxId)) {
|
|
m_pMchMgr->SetLastError( 2702, "Error in SawFinishing : AdjustGeometry 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) ;
|
|
|
|
// calcolo le passate
|
|
if ( m_Params.m_nSubType == SAWFIN_SUB_ALONG) {
|
|
if ( m_bStraight) {
|
|
if ( ! CalculateStraightAlongToolPath( nAuxId, nClId)) {
|
|
m_pMchMgr->SetLastError( 2709, "Error in SawFinishing : CalculateAlongToolPath failed") ;
|
|
return false ;
|
|
}
|
|
}
|
|
else {
|
|
if ( ! CalculateCurvedAlongToolPath( nAuxId, nClId)) {
|
|
m_pMchMgr->SetLastError( 2709, "Error in SawFinishing : CalculateAlongToolPath failed") ;
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
else if ( m_Params.m_nSubType == SAWFIN_SUB_ACROSS) {
|
|
if ( m_bStraight) {
|
|
if ( ! CalculateStraightAcrossToolPath( nAuxId, nClId)) {
|
|
m_pMchMgr->SetLastError( 2710, "Error in SawFinishing : CalculateAcrossToolPath failed") ;
|
|
return false ;
|
|
}
|
|
}
|
|
else {
|
|
if ( ! CalculateCurvedAcrossToolPath( nAuxId, nClId)) {
|
|
m_pMchMgr->SetLastError( 2710, "Error in SawFinishing : CalculateAcrossToolPath failed") ;
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
else if ( m_Params.m_nSubType == SAWFIN_SUB_SECTION) {
|
|
if ( m_bStraight) {
|
|
if ( ! CalculateStraightSectionToolPath( nAuxId, nClId)) {
|
|
m_pMchMgr->SetLastError( 2717, "Error in SawFinishing : CalculateSectionToolPath failed") ;
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
else if ( m_Params.m_nSubType == SAWFIN_SUB_ALONG_5A) {
|
|
if ( m_bStraight) {
|
|
if ( ! CalculateStraightAlong5AToolPath( nAuxId, nClId)) {
|
|
m_pMchMgr->SetLastError( 2718, "Error in SawFinishing : CalculateStraightAlong5AToolPath failed") ;
|
|
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(), "SawFinishing apply done") ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::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_nCuts == 0) {
|
|
m_pMchMgr->SetWarning( 2752, "Warning in SawFinishing : No machinable path") ;
|
|
return true ;
|
|
}
|
|
|
|
// elimino le entità CLIMB, RISE e HOME della lavorazione, potrebbero falsare i calcoli degli assi (in ogni casi vengono riaggiunte dopo)
|
|
RemoveClimbRiseHome() ;
|
|
|
|
// imposto eventuale asse bloccato da lavorazione
|
|
SetBlockedRotAxis( m_Params.m_sBlockedAxis) ;
|
|
|
|
// calcolo gli assi macchina
|
|
string sHint = ExtractHint( m_Params.m_sUserNotes) ;
|
|
if ( ! m_Params.m_sInitAngs.empty())
|
|
sHint = m_Params.m_sInitAngs ;
|
|
if ( ! CalculateAxesValues( sHint)) {
|
|
string sInfo = m_pMchMgr->GetOutstrokeInfo() ;
|
|
if ( sInfo.empty())
|
|
m_pMchMgr->SetLastError( 2711, "Error in SawFinishing : axes values not calculable") ;
|
|
else
|
|
m_pMchMgr->SetLastError( 2712, "Error in SawFinishing : outstroke ") ;
|
|
return false ;
|
|
}
|
|
|
|
// assegno estremi degli assi dei vari percorsi di lavorazione e della lavorazione nel suo complesso
|
|
CalcAndSetAxesBBox() ;
|
|
|
|
// esecuzione eventuali personalizzazioni speciali
|
|
string sSpecErr ;
|
|
if ( bPostApply && ! SpecialApply( sSpecErr)) {
|
|
if ( ! IsEmptyOrSpaces( sSpecErr))
|
|
m_pMchMgr->SetLastError( 2716, sSpecErr) ;
|
|
else
|
|
m_pMchMgr->SetLastError( 2716, "Error in SawFinishing : special apply not calculable") ;
|
|
return false ;
|
|
}
|
|
|
|
// gestione movimenti all'inizio di ogni singolo percorso di lavorazione e alla fine della lavorazione
|
|
if ( ! AdjustStartEndMovements()) {
|
|
string sInfo = m_pMchMgr->GetOutstrokeInfo() ;
|
|
if ( sInfo.empty())
|
|
m_pMchMgr->SetLastError( 2713, "Error in SawFinishing : link movements not calculable") ;
|
|
else
|
|
m_pMchMgr->SetLastError( 2714, "Error in SawFinishing : link outstroke ") ;
|
|
return false ;
|
|
}
|
|
|
|
// esecuzione eventuali personalizzazioni finali
|
|
string sPostErr ;
|
|
if ( bPostApply && ! PostApply( sPostErr)) {
|
|
if ( ! IsEmptyOrSpaces( sPostErr))
|
|
m_pMchMgr->SetLastError( 2715, sPostErr) ;
|
|
else
|
|
m_pMchMgr->SetLastError( 2715, "Error in SawFinishing : post apply not calculable") ;
|
|
return false ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::GetParam( int nType, bool& bVal) const
|
|
{
|
|
switch ( nType) {
|
|
case MPA_INVERT :
|
|
bVal = m_Params.m_bInvert ;
|
|
return true ;
|
|
}
|
|
bVal = false ;
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::GetParam( int nType, int& nVal) const
|
|
{
|
|
switch ( nType) {
|
|
case MPA_TYPE :
|
|
nVal = MT_SAWFINISHING ;
|
|
return true ;
|
|
case MPA_HEADSIDE :
|
|
nVal = m_Params.m_nHeadSide ;
|
|
return true ;
|
|
case MPA_STEPTYPE :
|
|
nVal = m_Params.m_nStepType ;
|
|
return true ;
|
|
case MPA_SUBTYPE :
|
|
nVal = m_Params.m_nSubType ;
|
|
return true ;
|
|
case MPA_LEADLINKTYPE :
|
|
nVal = m_Params.m_nLeadLinkType ;
|
|
return true ;
|
|
case MPA_SCC :
|
|
nVal = m_Params.m_nSolCh ;
|
|
return true ;
|
|
}
|
|
nVal = 0 ;
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::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_VERTFEED :
|
|
dVal = GetVertFeed() ;
|
|
return true ;
|
|
case MPA_OFFSR :
|
|
dVal =GetOffsR() ;
|
|
return true ;
|
|
case MPA_STARTPOS :
|
|
dVal = m_Params.m_dStartPos ;
|
|
return true ;
|
|
case MPA_SIDESTEP :
|
|
dVal = m_Params.m_dSideStep ;
|
|
return true ;
|
|
case MPA_STEP :
|
|
dVal = m_Params.m_dStep ;
|
|
return true ;
|
|
case MPA_APPROX :
|
|
dVal = m_Params.m_dApprox ;
|
|
return true ;
|
|
case MPA_STARTADDLEN :
|
|
dVal = m_Params.m_dStartAddLen ;
|
|
return true ;
|
|
case MPA_ENDADDLEN :
|
|
dVal = m_Params.m_dEndAddLen ;
|
|
return true ;
|
|
}
|
|
dVal = 0 ;
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::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&
|
|
SawFinishing::GetToolData( void) const
|
|
{
|
|
return m_TParams ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::UpdateToolData( void)
|
|
{
|
|
// recupero il gestore DB utensili della macchina corrente
|
|
ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ;
|
|
if ( pTMgr == nullptr)
|
|
return false ;
|
|
// recupero l'utensile nel DB utensili (se fallisce con UUID provo con il nome)
|
|
const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ;
|
|
if ( pTdata == nullptr) {
|
|
pTdata = pTMgr->GetTool( m_Params.m_sToolName) ;
|
|
if ( pTdata == nullptr)
|
|
return false ;
|
|
m_Params.m_ToolUuid = m_TParams.m_Uuid ;
|
|
}
|
|
// salvo posizione TC, testa e uscita originali
|
|
string sOrigTcPos = m_TParams.m_sTcPos ;
|
|
string sOrigHead = m_TParams.m_sHead ;
|
|
int nOrigExit = m_TParams.m_nExit ;
|
|
// verifico se sono diversi (ad esclusione di nome, posizione TC, testa e uscita)
|
|
bool bChanged = ( ! SameTool( m_TParams, *pTdata, false)) ;
|
|
// aggiorno comunque i parametri
|
|
m_TParams = *pTdata ;
|
|
// se definito attrezzaggio, aggiorno i parametri che ne possono derivare
|
|
string sTcPos ; string sHead ; int nExit ;
|
|
if ( m_pMchMgr->GetCurrSetupMgr().GetToolData( m_TParams.m_sName, sTcPos, sHead, nExit)) {
|
|
if ( sOrigTcPos != sTcPos ||
|
|
sOrigHead != sHead ||
|
|
nOrigExit != nExit)
|
|
bChanged = true ;
|
|
m_TParams.m_sTcPos = sTcPos ;
|
|
m_TParams.m_sHead = sHead ;
|
|
m_TParams.m_nExit = nExit ;
|
|
}
|
|
else {
|
|
if ( sOrigTcPos != pTdata->m_sTcPos ||
|
|
sOrigHead != pTdata->m_sHead ||
|
|
nOrigExit != pTdata->m_nExit)
|
|
bChanged = true ;
|
|
}
|
|
// eventuali segnalazioni
|
|
if ( ! EqualNoCase( m_Params.m_sToolName, m_TParams.m_sName)) {
|
|
string sInfo = "Warning in SawFinishing : tool name changed (" +
|
|
m_Params.m_sToolName + "->" + m_TParams.m_sName + ")" ;
|
|
m_pMchMgr->SetWarning( 2753, sInfo) ;
|
|
m_Params.m_sToolName = m_TParams.m_sName ;
|
|
}
|
|
if ( bChanged) {
|
|
string sInfo = "Warning in SawFinishing : tool data changed (" +
|
|
m_Params.m_sToolName + ")" ;
|
|
m_pMchMgr->SetWarning( 2754, sInfo) ;
|
|
}
|
|
// se modificato, aggiusto lo stato
|
|
if ( bChanged)
|
|
m_nStatus = MCH_ST_TO_VERIFY ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::GetGeometry( SELVECTOR& vIds) const
|
|
{
|
|
// restituisco l'elenco delle entità
|
|
vIds = m_vId ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::AdjustEndPointForAxesCalc( const CamData* pCamData, Point3d& ptP) const
|
|
{
|
|
// compenso il raggio dell'utensile
|
|
ptP += pCamData->GetCorrDir() * ( m_TParams.m_dDiam / 2) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::VerifyGeometry( SelData Id, int& nSubs)
|
|
{
|
|
// ammessi : curve o superfici
|
|
|
|
// per ora accetto solo curve
|
|
const ICurve* pCurve = nullptr ;
|
|
const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ;
|
|
// se direttamente la curva
|
|
if ( Id.nSub == SEL_SUB_ALL) {
|
|
pCurve = ::GetCurve( pGObj) ;
|
|
if ( pCurve != nullptr) {
|
|
if ( pCurve->GetType() == CRV_COMPO)
|
|
nSubs = ::GetCurveComposite( pCurve)->GetCurveCount() ;
|
|
else
|
|
nSubs = 0 ;
|
|
}
|
|
}
|
|
// altrimenti sottocurva di composita
|
|
else {
|
|
const ICurveComposite* pCompo = GetCurveComposite( pGObj) ;
|
|
if ( pCompo != nullptr)
|
|
pCurve = pCompo->GetCurve( Id.nSub) ;
|
|
nSubs = 0 ;
|
|
}
|
|
return ( pCurve != nullptr) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurve*
|
|
SawFinishing::GetCurve( SelData Id)
|
|
{
|
|
// ammessi : curve o facce di polymesh
|
|
// nel caso di facce si deve recuperare la linea di base
|
|
|
|
// per ora accetto solo curve
|
|
PtrOwner<ICurve> pCurve ;
|
|
// se direttamente curva
|
|
if ( Id.nSub == SEL_SUB_ALL) {
|
|
// recupero e duplico la curva
|
|
const ICurve* pOriCurve = ::GetCurve( m_pGeomDB->GetGeoObj( Id.nId)) ;
|
|
if ( pOriCurve != nullptr)
|
|
pCurve.Set( pOriCurve->Clone()) ;
|
|
}
|
|
// altrimenti sottocurva di composita
|
|
else {
|
|
// recupero la composita
|
|
const ICurveComposite* pCompo = GetCurveComposite( m_pGeomDB->GetGeoObj( Id.nId)) ;
|
|
if ( pCompo != nullptr) {
|
|
// duplico la curva semplice
|
|
const ICurve* pOriCurve = ::GetCurve( pCompo->GetCurve( Id.nSub)) ;
|
|
if ( pOriCurve != nullptr) {
|
|
pCurve.Set( pOriCurve->Clone()) ;
|
|
// recupero estrusione e spessore
|
|
Vector3d vtExtr ;
|
|
if ( pCompo->GetExtrusion( vtExtr))
|
|
pCurve->SetExtrusion( vtExtr) ;
|
|
double dThick ;
|
|
if ( pCompo->GetThickness( dThick))
|
|
pCurve->SetThickness( dThick) ;
|
|
}
|
|
}
|
|
}
|
|
if ( IsNull( pCurve))
|
|
return nullptr ;
|
|
// ne recupero il riferimento globale
|
|
Frame3d frGlob ;
|
|
if ( ! m_pGeomDB->GetGlobFrame( Id.nId, frGlob))
|
|
return nullptr ;
|
|
// la porto in globale
|
|
pCurve->ToGlob( frGlob) ;
|
|
// la restituisco
|
|
return Release( pCurve) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::AdjustGeometry( int nAuxId)
|
|
{
|
|
// sgrossatura di cornici diritte : due o più curve (sezioni e guida rettilinea)
|
|
// sgrossatura di cornici curve : due curve (sezione e guida curva)
|
|
size_t nCrvCount = m_vId.size() ;
|
|
if ( nCrvCount >= 2) {
|
|
// le sezioni devono essere chiuse, piane e giacere in uno stesso piano verticale
|
|
ICURVEPOVECTOR vpSects ;
|
|
vpSects.reserve( nCrvCount - 1) ;
|
|
Vector3d vtN ;
|
|
for ( size_t i = 0 ; i < nCrvCount - 1 ; ++ i) {
|
|
vpSects.emplace_back( GetCurve( m_vId[i])) ;
|
|
if ( IsNull( vpSects.back()))
|
|
return false ;
|
|
if ( ! vpSects.back()->IsClosed())
|
|
return false ;
|
|
Plane3d plPlane ;
|
|
if ( ! vpSects.back()->IsFlat( plPlane, false, 10 * EPS_SMALL) || abs( plPlane.GetVersN().z) > EPS_SMALL)
|
|
return false ;
|
|
if ( i == 0)
|
|
vtN = plPlane.GetVersN() ;
|
|
else {
|
|
if ( ! AreSameOrOppositeVectorApprox( plPlane.GetVersN(), vtN))
|
|
return false ;
|
|
}
|
|
}
|
|
// l'ultima curva è la guida
|
|
PtrOwner<ICurve> pGuide( GetCurve( m_vId[nCrvCount-1])) ;
|
|
if ( IsNull( pGuide))
|
|
return false ;
|
|
// se linea -> cornici diritte (lama verticale)
|
|
if ( pGuide->GetType() == CRV_LINE)
|
|
m_bStraight = true ;
|
|
// altrimenti curva -> cornici curve (lama orizzontale)
|
|
else {
|
|
m_bStraight = false ;
|
|
// ammessa una sola sezione
|
|
if ( nCrvCount > 2)
|
|
return false ;
|
|
// la guida deve giacere nel piano XY
|
|
Plane3d plPlane ;
|
|
if ( ! pGuide->IsFlat( plPlane, false, 10 * EPS_SMALL) || ! AreSameOrOppositeVectorApprox( plPlane.GetVersN(), Z_AX))
|
|
return false ;
|
|
// verifiche sulla curva (che trasformo in composita)
|
|
PtrOwner<ICurveComposite> pCompo ;
|
|
if ( ! pCompo.Set( ConvertCurveToComposite( Release( pGuide))))
|
|
return false ;
|
|
// converto in archi e rette
|
|
pCompo->ArcsBezierCurvesToArcsPerpExtr( LIN_TOL_MID, ANG_TOL_STD_DEG) ;
|
|
// verifiche sull'ampiezza dell'angolo al centro degli eventuali archi
|
|
VerifyArcs( pCompo) ;
|
|
// reinserisco nella curva originale
|
|
pGuide.Set( pCompo) ;
|
|
}
|
|
// deve iniziare in comune con la prima sezione ed essere ivi perpendicolare
|
|
Vector3d vtGdDir ;
|
|
if ( ! pGuide->GetStartDir( vtGdDir) || ! AreSameOrOppositeVectorApprox( vtN, vtGdDir))
|
|
return false ;
|
|
Point3d ptStStart, ptGdStart ;
|
|
if ( ! vpSects[0]->GetStartPoint( ptStStart) ||
|
|
! pGuide->GetStartPoint( ptGdStart) ||
|
|
abs( ( ptGdStart - ptStStart) * vtGdDir) > 10 * EPS_SMALL)
|
|
return false ;
|
|
// creo sottogruppo di ausiliario per le sezioni con riferimento avente
|
|
// l'origine nel punto di inizio della guida e la Z opposta alla direzione della guida
|
|
Frame3d frSect ;
|
|
if ( ! frSect.Set( ptGdStart, - vtGdDir))
|
|
return false ;
|
|
int nGrpSectId = m_pGeomDB->AddGroup( GDB_ID_NULL, nAuxId, frSect) ;
|
|
if ( nGrpSectId == GDB_ID_NULL)
|
|
return false ;
|
|
m_pGeomDB->SetName( nGrpSectId, MCH_SECTION) ;
|
|
// inserisco le sezioni e ne sistemo il senso di rotazione come CCW
|
|
for ( auto& pSect : vpSects) {
|
|
pSect->ToLoc( frSect) ;
|
|
double dArea ;
|
|
pSect->GetAreaXY( dArea) ;
|
|
if ( dArea < 0)
|
|
pSect->Invert() ;
|
|
if ( m_pGeomDB->AddGeoObj( GDB_ID_NULL, nGrpSectId, ::Release( pSect)) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// creo sottogruppo per la guida
|
|
// inserisco la guida nel gruppo ausiliario
|
|
int nGrpGuideId = m_pGeomDB->AddGroup( GDB_ID_NULL, nAuxId, Frame3d()) ;
|
|
if ( nGrpGuideId == GDB_ID_NULL)
|
|
return false ;
|
|
m_pGeomDB->SetName( nGrpGuideId, MCH_GUIDE) ;
|
|
if ( m_pGeomDB->AddGeoObj( GDB_ID_NULL, nGrpGuideId, ::Release( pGuide)) == GDB_ID_NULL)
|
|
return false ;
|
|
return true ;
|
|
}
|
|
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalculateStraightAlongToolPath( int nAuxId, int nClId)
|
|
{
|
|
// Recupero ed elaboro le sezioni per portarle ad essere la curva del centro in basso della lama
|
|
int nSectGrpId = m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_SECTION) ;
|
|
ICRVCOMPOPOVECTOR vpSections ;
|
|
if ( ! CalculateSection( nSectGrpId, vpSections))
|
|
return false ;
|
|
// recupero il riferimento globale delle sezioni
|
|
Frame3d frSect ;
|
|
m_pGeomDB->GetGroupGlobFrame( nSectGrpId, frSect) ;
|
|
// recupero il box globale delle sezioni
|
|
BBox3d b3Sect ;
|
|
m_pGeomDB->GetGlobalBBox( nSectGrpId, b3Sect) ;
|
|
|
|
// Recupero da UserNotes il flag di estensione al bordo del grezzo
|
|
bool bExtend ;
|
|
if ( ! GetValInNotes( m_Params.m_sUserNotes, UN_EXTEND, bExtend))
|
|
bExtend = true ;
|
|
// se estensione non presente e Link di tipo Extended, lo forzo come Center
|
|
if ( ! bExtend && m_Params.m_nLeadLinkType == SAWFIN_LL_OUT) {
|
|
m_pMchMgr->SetWarning( 2655, "Warning in SawRoughing : Link not compatible with extension") ;
|
|
m_Params.m_nLeadLinkType = SAWFIN_LL_CENT ;
|
|
}
|
|
|
|
// Recupero ed elaboro la linea guida
|
|
Point3d ptGdStart, ptGdEnd ;
|
|
Vector3d vtGdDir ;
|
|
int nGuideId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_GUIDE)) ;
|
|
if ( ! CalculateGuideLine( nGuideId, ptGdStart, ptGdEnd, vtGdDir, nSectGrpId, false))
|
|
return false ;
|
|
if ( m_Params.m_bInvert) {
|
|
swap( ptGdStart, ptGdEnd) ;
|
|
vtGdDir.Invert() ;
|
|
}
|
|
// recupero il box globale della linea guida
|
|
BBox3d b3Guide ;
|
|
m_pGeomDB->GetGlobalBBox( nGuideId, b3Guide) ;
|
|
|
|
// recupero il box del grezzo in globale
|
|
BBox3d b3Test ;
|
|
b3Test.Add( b3Sect) ;
|
|
b3Test.Add( b3Guide) ;
|
|
BBox3d b3Raw ;
|
|
if ( ! GetRawGlobBox( m_nPhase, b3Test, 10 * EPS_SMALL, b3Raw) || b3Raw.IsEmpty()) {
|
|
m_pMchMgr->SetLastError( 2703, "Error in SawFinishing : Empty RawBox") ;
|
|
return false ;
|
|
}
|
|
|
|
// valuto l'espressione dell'affondamento
|
|
ExeLuaSetGlobNumVar( "TH", 0) ;
|
|
ExeLuaSetGlobNumVar( "RB", b3Raw.GetMax().z - b3Raw.GetMin().z) ;
|
|
double dDepth ;
|
|
if ( ! ExeLuaEvalNumExpr( m_Params.m_sDepth, &dDepth)) {
|
|
m_pMchMgr->SetLastError( 2704, "Error in SawFinishing : Depth not computable") ;
|
|
return false ;
|
|
}
|
|
|
|
// creo gruppo per geometria di lavorazione
|
|
int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ;
|
|
if ( nPxId == GDB_ID_NULL)
|
|
return false ;
|
|
m_pGeomDB->SetName( nPxId, MCH_PATH + "1_1") ;
|
|
m_pGeomDB->SetMaterial( nPxId, GREEN) ;
|
|
|
|
// Determino versori fresa e correzione
|
|
Vector3d vtTool, vtCorr ;
|
|
if ( ! CalculateToolAndCorrVersors( vtGdDir, m_Params.m_nHeadSide, vtTool, vtCorr)) {
|
|
m_pMchMgr->SetLastError( 2705, "Error in SawFinishing : CalculateToolAndCorrVersors") ;
|
|
return false ;
|
|
}
|
|
|
|
// Imposto dati comuni
|
|
SetPathId( nPxId) ;
|
|
SetToolDir( vtTool) ;
|
|
SetCorrAuxDir( vtCorr) ;
|
|
|
|
// assegno il vettore estrazione al gruppo del percorso
|
|
m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ;
|
|
|
|
// recupero la TriMesh del grezzo in globale
|
|
PtrOwner<ISurfTriMesh> pStmRaw( CreateSurfTriMesh()) ;
|
|
if ( IsNull( pStmRaw))
|
|
return false ;
|
|
pStmRaw->AdjustTopology() ;
|
|
int nRawId = m_pMchMgr->GetFirstRawPart() ;
|
|
while ( nRawId != GDB_ID_NULL) {
|
|
// verifico che il grezzo compaia nella fase
|
|
if ( m_pMchMgr->VerifyRawPartPhase( nRawId, m_nPhase)) {
|
|
// recupero l'oggetto dal database con tale Id
|
|
int nRawSolidId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_SOLID) ;
|
|
const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( nRawSolidId) ;
|
|
if ( pGObj != nullptr) {
|
|
// recupero il frame in cui si trova
|
|
Frame3d frRaw ;
|
|
m_pGeomDB->GetGlobFrame( nRawSolidId, frRaw) ;
|
|
// controllo che sia una Trimesh
|
|
if ( pGObj->GetType() == SRF_TRIMESH) {
|
|
SurfLocal StmRawPart( GetSurfTriMesh( pGObj), frRaw, GLOB_FRM) ;
|
|
// lo aggiungo alla Trimesh complessiva
|
|
pStmRaw->Add( *GetSurfTriMesh( StmRawPart)) ;
|
|
}
|
|
}
|
|
}
|
|
// passo al grezzo successivo
|
|
nRawId = m_pMchMgr->GetNextRawPart( nRawId) ;
|
|
}
|
|
|
|
// per ogni sezione
|
|
for ( int nSect = 0 ; nSect < ssize( vpSections) ; ++ nSect) {
|
|
|
|
// recupero la sezione corrente
|
|
ICurve* pCrv = vpSections[nSect] ;
|
|
if ( pCrv == nullptr || ! pCrv->IsValid())
|
|
continue ;
|
|
|
|
// Classifico i tratti a seconda della pendenza (salita, discesa, verticale, orizzontale)
|
|
INTVECTOR vnClass ;
|
|
ClassifySection( pCrv, vnClass) ;
|
|
|
|
// Inizializzo contatore tagli
|
|
m_nCuts = 0 ;
|
|
|
|
// Passate sui lati verticali
|
|
int nUmin = -1, nUmax = -1 ;
|
|
for ( size_t i = 0 ; i < vnClass.size() ; ++ i) {
|
|
// se lato verticale
|
|
if ( vnClass[i] == CCL_VERT) {
|
|
if ( nUmin < 0)
|
|
nUmin = int( i) ;
|
|
nUmax = int( i + 1) ;
|
|
}
|
|
// se lato non verticale e non piccolo o ultimo
|
|
if ( ( vnClass[i] != CCL_VERT && vnClass[i] != CCL_SMALL) || i == vnClass.size() - 1) {
|
|
if ( nUmin >= 0) {
|
|
// eseguo la passata
|
|
if ( ! CalcAlongVerticalCuts( pCrv, nUmin, nUmax, frSect, bExtend, ptGdStart, ptGdEnd, vtGdDir, dDepth, b3Raw.GetMax().z,
|
|
vtTool, vtCorr, pStmRaw))
|
|
return false ;
|
|
nUmin = - 1 ;
|
|
}
|
|
}
|
|
}
|
|
// Altre passate
|
|
int nStatus = CCL_VERT ;
|
|
nUmin = -1 ;
|
|
nUmax = -1 ;
|
|
bool bSkipMin = false, bSkipMax = false ;
|
|
for ( size_t i = 0 ; i < vnClass.size() ; ++ i) {
|
|
// se stato nullo (verticale)
|
|
if ( nStatus == CCL_VERT) {
|
|
if ( vnClass[i] == CCL_VERT || vnClass[i] == CCL_SMALL)
|
|
continue ;
|
|
else {
|
|
nStatus = vnClass[i] ;
|
|
nUmin = int( i) ;
|
|
nUmax = int( i + 1) ;
|
|
bSkipMin = true ;
|
|
}
|
|
}
|
|
// altrimenti
|
|
else {
|
|
// se classe piatto e trovo salita o discesa, converto a questo
|
|
if ( nStatus == CCL_FLAT && ( vnClass[i] == CCL_RISE || vnClass[i] == CCL_FALL))
|
|
nStatus = vnClass[i] ;
|
|
// se si conserva la classe, aggiorno fine
|
|
if ( vnClass[i] == nStatus || vnClass[i] == CCL_FLAT || vnClass[i] == CCL_SMALL)
|
|
nUmax = int( i + 1) ;
|
|
// altrimenti calcolo il tratto precedente
|
|
else {
|
|
// calcolo il tratto
|
|
bSkipMax = ( vnClass[i] == CCL_VERT) ;
|
|
bool bInvert = ( nStatus == CCL_RISE) ;
|
|
if ( ! CalcAlongStdCuts( pCrv, nUmin, nUmax,
|
|
bSkipMin, bSkipMax, bInvert, frSect, bExtend, ptGdStart, ptGdEnd, vtGdDir, dDepth, b3Raw.GetMax().z,
|
|
vtTool, vtCorr, pStmRaw))
|
|
return false ;
|
|
// aggiorno stato
|
|
if ( vnClass[i] == CCL_VERT)
|
|
nStatus = CCL_VERT ;
|
|
else {
|
|
nStatus = vnClass[i] ;
|
|
nUmin = int( i) ;
|
|
nUmax = int( i + 1) ;
|
|
}
|
|
bSkipMin = true ;
|
|
}
|
|
}
|
|
}
|
|
// se c'è qualcosa in sospeso
|
|
if ( nStatus != CCL_VERT) {
|
|
bSkipMax = false ;
|
|
bool bInvert = ( nStatus == CCL_RISE) ;
|
|
if ( ! CalcAlongStdCuts( pCrv, nUmin, nUmax, bSkipMin, bSkipMax, bInvert, frSect, bExtend, ptGdStart, ptGdEnd, vtGdDir, dDepth,
|
|
b3Raw.GetMax().z, vtTool, vtCorr, pStmRaw))
|
|
return false ;
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalculateStraightAcrossToolPath( int nAuxId, int nClId)
|
|
{
|
|
// Recupero ed elaboro le sezioni per portarle ad essere la curva del centro in basso della lama
|
|
int nSectGrpId = m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_SECTION) ;
|
|
ICRVCOMPOPOVECTOR vpSections ;
|
|
if ( ! CalculateSection( nSectGrpId, vpSections))
|
|
return false ;
|
|
// recupero il riferimento globale delle sezioni
|
|
Frame3d frSect ;
|
|
m_pGeomDB->GetGroupGlobFrame( nSectGrpId, frSect) ;
|
|
// recupero il box globale delle sezioni
|
|
BBox3d b3Sect ;
|
|
m_pGeomDB->GetGlobalBBox( nSectGrpId, b3Sect) ;
|
|
|
|
// Recupero da UserNotes il flag di estensione al bordo del grezzo
|
|
bool bExtend ;
|
|
if ( ! GetValInNotes( m_Params.m_sUserNotes, UN_EXTEND, bExtend))
|
|
bExtend = true ;
|
|
// se estensione non presente e Link di tipo Extended, lo forzo come Center
|
|
if ( ! bExtend && m_Params.m_nLeadLinkType == SAWFIN_LL_OUT) {
|
|
m_pMchMgr->SetWarning( 2655, "Warning in SawRoughing : Link not compatible with extension") ;
|
|
m_Params.m_nLeadLinkType = SAWFIN_LL_CENT ;
|
|
}
|
|
|
|
// Recupero ed elaboro la linea guida
|
|
Point3d ptGdStart, ptGdEnd ;
|
|
Vector3d vtGdDir ;
|
|
int nGuideId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_GUIDE)) ;
|
|
if ( ! CalculateGuideLine( nGuideId, ptGdStart, ptGdEnd, vtGdDir, nSectGrpId, bExtend))
|
|
return false ;
|
|
Vector3d vtDeltaSect = vtGdDir * ( vtGdDir * ( ptGdStart - frSect.Orig())) ;
|
|
if ( m_Params.m_bInvert) {
|
|
swap( ptGdStart, ptGdEnd) ;
|
|
vtGdDir.Invert() ;
|
|
}
|
|
// recupero il box globale della linea guida
|
|
BBox3d b3Guide ;
|
|
m_pGeomDB->GetGlobalBBox( nGuideId, b3Guide) ;
|
|
|
|
// recupero il box del grezzo in globale
|
|
BBox3d b3Test ;
|
|
b3Test.Add( b3Sect) ;
|
|
b3Test.Add( b3Guide) ;
|
|
BBox3d b3Raw ;
|
|
if ( ! GetRawGlobBox( m_nPhase, b3Test, 10 * EPS_SMALL, b3Raw) || b3Raw.IsEmpty()) {
|
|
m_pMchMgr->SetLastError( 2703, "Error in SawFinishing : Empty RawBox") ;
|
|
return false ;
|
|
}
|
|
|
|
// valuto l'espressione dell'affondamento
|
|
ExeLuaSetGlobNumVar( "TH", 0) ;
|
|
ExeLuaSetGlobNumVar( "RB", b3Raw.GetMax().z - b3Raw.GetMin().z) ;
|
|
double dDepth ;
|
|
if ( ! ExeLuaEvalNumExpr( m_Params.m_sDepth, &dDepth)) {
|
|
m_pMchMgr->SetLastError( 2704, "Error in SawFinishing : Depth not computable") ;
|
|
return false ;
|
|
}
|
|
|
|
// creo gruppo per geometria di lavorazione
|
|
int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ;
|
|
if ( nPxId == GDB_ID_NULL)
|
|
return false ;
|
|
m_pGeomDB->SetName( nPxId, MCH_PATH + "1_1") ;
|
|
m_pGeomDB->SetMaterial( nPxId, GREEN) ;
|
|
|
|
// Determino versori fresa e correzione
|
|
Vector3d vtTool, vtCorr ;
|
|
if ( ! CalculateToolAndCorrVersors( vtGdDir, m_Params.m_nHeadSide, vtTool, vtCorr)) {
|
|
m_pMchMgr->SetLastError( 2705, "Error in SawFinishing : CalculateToolAndCorrVersors") ;
|
|
return false ;
|
|
}
|
|
|
|
// per ogni sezione
|
|
for ( int nSect = 0 ; nSect < ssize( vpSections) ; ++ nSect) {
|
|
|
|
// recupero la sezione corrente
|
|
ICurve* pCrv = vpSections[nSect] ;
|
|
if ( pCrv == nullptr || ! pCrv->IsValid())
|
|
continue ;
|
|
|
|
// Approssimo la curva con una spezzata
|
|
PolyLine PL ;
|
|
if ( ! pCrv->ApproxWithLines( LIN_TOL_MID, ANG_TOL_STD_DEG, ICurve::APL_RIGHT, PL)) {
|
|
m_pMchMgr->SetLastError( 2706, "Error in SawFinishing : ApproxWithLines") ;
|
|
return false ;
|
|
}
|
|
// Se standard, allungo inizio e fine della sezione dello spessore lama
|
|
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_STD) {
|
|
// inizio
|
|
PL.Invert() ;
|
|
double dU ;
|
|
Point3d ptP ;
|
|
PL.GetLastUPoint( &dU, &ptP) ;
|
|
PL.AddUPoint( dU, ptP + Vector3d( m_TParams.m_dThick, 0, 0)) ;
|
|
PL.Invert() ;
|
|
// fine
|
|
PL.GetLastUPoint( &dU, &ptP) ;
|
|
PL.AddUPoint( dU, ptP - Vector3d( m_TParams.m_dThick, 0, 0)) ;
|
|
}
|
|
// La porto in globale
|
|
PL.ToGlob( frSect) ;
|
|
PL.Translate( vtDeltaSect) ;
|
|
if ( m_Params.m_bInvert)
|
|
PL.Translate( ptGdStart - ptGdEnd) ;
|
|
|
|
// Calcolo eventuale anticipo dell'inizio
|
|
double dAddStart = 0 ;
|
|
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_OUT) {
|
|
BBox3d b3PL ;
|
|
PL.GetLocalBBox( b3PL) ;
|
|
double dMaxElev = min( dDepth, b3Raw.GetMax().z - b3PL.GetMin().z) ;
|
|
if ( dMaxElev > 0.0 && dMaxElev < 0.5 * m_TParams.m_dDiam)
|
|
dAddStart = sqrt( dMaxElev * m_TParams.m_dDiam - dMaxElev * dMaxElev) ;
|
|
else
|
|
dAddStart = 0.5 * m_TParams.m_dDiam ;
|
|
}
|
|
|
|
// Imposto dati comuni
|
|
SetPathId( nPxId) ;
|
|
SetToolDir( vtTool) ;
|
|
SetCorrAuxDir( vtCorr) ;
|
|
|
|
// assegno il vettore estrazione al gruppo del percorso
|
|
m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ;
|
|
|
|
// Inizializzo contatore tagli
|
|
m_nCuts = 0 ;
|
|
|
|
// Calcolo le passate
|
|
double dStep = max( m_Params.m_dSideStep, 10 * EPS_SMALL) ;
|
|
double dL = Dist( ptGdStart, ptGdEnd) + dAddStart ;
|
|
int nStep = static_cast<int>( ceil( dL / dStep)) ;
|
|
dStep = dL / nStep ;
|
|
Point3d ptP ;
|
|
for ( int i = 0 ; i <= nStep ; ++ i) {
|
|
// vettore di spostamento
|
|
Vector3d vtMove = vtGdDir * ( - dAddStart + i * dStep) ;
|
|
// lavoro la sezione
|
|
if ( m_Params.m_nStepType != SAWFIN_ST_ZIGZAG) {
|
|
if ( ! CalcAcrossOneWayCut( PL, vtMove, vtTool, vtCorr, b3Raw.GetMax().z, dDepth))
|
|
return false ;
|
|
}
|
|
else {
|
|
bool bFirst = ( i == 0) ;
|
|
if ( ! CalcAcrossZigZagCut( PL, vtMove, vtTool, vtCorr, b3Raw.GetMax().z, dDepth, bFirst))
|
|
return false ;
|
|
}
|
|
}
|
|
// se ZigZag aggiungo risalita
|
|
if ( m_Params.m_nStepType == SAWFIN_ST_ZIGZAG) {
|
|
// recupero distanza di sicurezza
|
|
double dSafeZ = GetSafeZ() ;
|
|
// lunghezza di approccio/retrazione
|
|
double dAppr = m_Params.m_dStartPos ;
|
|
// aggiungo retrazione
|
|
Point3d ptEnd ;
|
|
if ( ! GetCurrPos( ptEnd))
|
|
return false ;
|
|
double dElev = b3Raw.GetMax().z - ptEnd.z ;
|
|
if ( ! AddRetract( ptEnd, vtCorr, dSafeZ, dElev, dAppr))
|
|
return false ;
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalculateCurvedAlongToolPath( int nAuxId, int nClId)
|
|
{
|
|
// Ruoto di 90 deg la curva sezione nel suo piano
|
|
int nSectGrpId = m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_SECTION) ;
|
|
int nCrvId = ExeGetFirstInGroup( nSectGrpId) ;
|
|
m_pGeomDB->Rotate( nCrvId, ORIG, Z_AX, 90.0) ;
|
|
// Recupero ed elaboro la sezione per portarla ad essere la curva del lato verso la cornice della lama
|
|
ICRVCOMPOPOVECTOR vpSections ;
|
|
if ( ! CalculateSection( nSectGrpId, vpSections))
|
|
return false ;
|
|
// Contro rotazione della curva
|
|
m_pGeomDB->Rotate( nCrvId, ORIG, Z_AX, -90.0) ;
|
|
// recupero il riferimento globale della sezione
|
|
Frame3d frSect ;
|
|
m_pGeomDB->GetGroupGlobFrame( nSectGrpId, frSect) ;
|
|
// recupero il box globale della sezione
|
|
BBox3d b3Sect ;
|
|
m_pGeomDB->GetGlobalBBox( nSectGrpId, b3Sect) ;
|
|
|
|
// Recupero ed elaboro la linea guida
|
|
int nGuideId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_GUIDE)) ;
|
|
// recupero la linea guida
|
|
ICurve* pGuide = ::GetCurve( m_pGeomDB->GetGeoObj( nGuideId)) ;
|
|
if ( pGuide == nullptr)
|
|
return false ;
|
|
// recupero il suo riferimento
|
|
Frame3d frGdL ;
|
|
m_pGeomDB->GetGlobFrame( nGuideId, frGdL) ;
|
|
// porto la curva in globale (dovrebbe già avere riferimento globale)
|
|
pGuide->ToGlob( frGdL) ;
|
|
// recupero il box globale della linea guida
|
|
BBox3d b3Guide ;
|
|
m_pGeomDB->GetGlobalBBox( nGuideId, b3Guide) ;
|
|
|
|
// recupero il box del grezzo in globale
|
|
BBox3d b3Test ;
|
|
b3Test.Add( b3Sect) ;
|
|
b3Test.Add( b3Guide) ;
|
|
BBox3d b3Raw ;
|
|
if ( ! GetRawGlobBox( m_nPhase, b3Test, 10 * EPS_SMALL, b3Raw) || b3Raw.IsEmpty()) {
|
|
m_pMchMgr->SetLastError( 2703, "Error in SawFinishing : Empty RawBox") ;
|
|
return false ;
|
|
}
|
|
|
|
// valuto l'espressione dell'affondamento
|
|
ExeLuaSetGlobNumVar( "TH", 0) ;
|
|
ExeLuaSetGlobNumVar( "RB", b3Raw.GetMax().z - b3Raw.GetMin().z) ;
|
|
double dDepth ;
|
|
if ( ! ExeLuaEvalNumExpr( m_Params.m_sDepth, &dDepth)) {
|
|
m_pMchMgr->SetLastError( 2704, "Error in SawFinishing : Depth not computable") ;
|
|
return false ;
|
|
}
|
|
|
|
// creo gruppo per geometria di lavorazione
|
|
int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ;
|
|
if ( nPxId == GDB_ID_NULL)
|
|
return false ;
|
|
m_pGeomDB->SetName( nPxId, MCH_PATH + "1_1") ;
|
|
m_pGeomDB->SetMaterial( nPxId, GREEN) ;
|
|
|
|
// Imposto versore fresa come Z+
|
|
Vector3d vtTool = Z_AX ;
|
|
|
|
// Imposto dati comuni
|
|
SetPathId( nPxId) ;
|
|
SetToolDir( vtTool) ;
|
|
|
|
// assegno il vettore estrazione al gruppo del percorso
|
|
m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ;
|
|
|
|
// per ogni sezione
|
|
for ( int nSect = 0 ; nSect < ssize( vpSections) ; ++ nSect) {
|
|
|
|
// recupero la sezione corrente
|
|
ICurve* pCrv = vpSections[nSect] ;
|
|
if ( pCrv == nullptr || ! pCrv->IsValid())
|
|
continue ;
|
|
|
|
// Classifico i tratti a seconda della pendenza (salita, discesa, verticale, orizzontale)
|
|
INTVECTOR vnClass ;
|
|
ClassifySection( pCrv, vnClass) ;
|
|
|
|
// Ripristino orientamento sezione con controrotazione
|
|
pCrv->Rotate( ORIG, Z_AX, -90.0) ;
|
|
|
|
// Inizializzo contatore tagli
|
|
m_nCuts = 0 ;
|
|
|
|
// Passate sui lati verticali
|
|
int nUmin = -1, nUmax = -1 ;
|
|
for ( size_t i = 0 ; i < vnClass.size() ; ++ i) {
|
|
// se lato verticale
|
|
if ( vnClass[i] == CCL_VERT) {
|
|
if ( nUmin < 0)
|
|
nUmin = int( i) ;
|
|
nUmax = int( i + 1) ;
|
|
}
|
|
// se lato non verticale e non piccolo o ultimo
|
|
if ( ( vnClass[i] != CCL_VERT && vnClass[i] != CCL_SMALL) || i == vnClass.size() - 1) {
|
|
if ( nUmin >= 0) {
|
|
// eseguo la passata
|
|
if ( ! CalcCurvedAlongVerticalCuts( pCrv, nUmin, nUmax, frSect,
|
|
pGuide, dDepth, b3Raw.GetMax().z, vtTool))
|
|
return false ;
|
|
nUmin = - 1 ;
|
|
}
|
|
}
|
|
}
|
|
// Altre passate
|
|
int nStatus = CCL_VERT ;
|
|
nUmin = -1 ;
|
|
nUmax = -1 ;
|
|
bool bSkipMin = false, bSkipMax = false ;
|
|
for ( size_t i = 0 ; i < vnClass.size() ; ++ i) {
|
|
// se stato nullo (verticale)
|
|
if ( nStatus == CCL_VERT) {
|
|
if ( vnClass[i] == CCL_VERT || vnClass[i] == CCL_SMALL)
|
|
continue ;
|
|
else {
|
|
nStatus = vnClass[i] ;
|
|
nUmin = int( i) ;
|
|
nUmax = int( i + 1) ;
|
|
bSkipMin = true ;
|
|
}
|
|
}
|
|
// altrimenti
|
|
else {
|
|
// se classe piatto e trovo salita o discesa, converto a questo
|
|
if ( nStatus == CCL_FLAT && ( vnClass[i] == CCL_RISE || vnClass[i] == CCL_FALL))
|
|
nStatus = vnClass[i] ;
|
|
// se si conserva la classe, aggiorno fine
|
|
if ( vnClass[i] == nStatus || vnClass[i] == CCL_FLAT || vnClass[i] == CCL_SMALL)
|
|
nUmax = int( i + 1) ;
|
|
// altrimenti calcolo il tratto precedente
|
|
else {
|
|
// calcolo il tratto
|
|
bSkipMax = ( vnClass[i] == CCL_VERT) ;
|
|
bool bInvert = ( nStatus == CCL_RISE) ;
|
|
if ( ! CalcCurvedAlongStdCuts( pCrv, nUmin, nUmax,
|
|
bSkipMin, bSkipMax, bInvert, frSect,
|
|
pGuide, dDepth, b3Raw.GetMax().z, vtTool))
|
|
return false ;
|
|
// aggiorno stato
|
|
if ( vnClass[i] == CCL_VERT)
|
|
nStatus = CCL_VERT ;
|
|
else {
|
|
nStatus = vnClass[i] ;
|
|
nUmin = int( i) ;
|
|
nUmax = int( i + 1) ;
|
|
}
|
|
bSkipMin = true ;
|
|
}
|
|
}
|
|
}
|
|
// se c'è qualcosa in sospeso
|
|
if ( nStatus != CCL_VERT) {
|
|
bSkipMax = false ;
|
|
bool bInvert = ( nStatus == CCL_RISE) ;
|
|
if ( ! CalcCurvedAlongStdCuts( pCrv, nUmin, nUmax,
|
|
bSkipMin, bSkipMax, bInvert, frSect,
|
|
pGuide, dDepth, b3Raw.GetMax().z, vtTool))
|
|
return false ;
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalculateCurvedAcrossToolPath( int nAuxId, int nClId)
|
|
{
|
|
// Ruoto di 90 deg la curva sezione nel suo piano
|
|
int nSectGrpId = m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_SECTION) ;
|
|
int nCrvId = ExeGetFirstInGroup( nSectGrpId) ;
|
|
m_pGeomDB->Rotate( nCrvId, ORIG, Z_AX, 90.0) ;
|
|
// Recupero ed elaboro le sezioni per portarle ad essere la curva del centro in basso della lama
|
|
ICRVCOMPOPOVECTOR vpSections ;
|
|
if ( ! CalculateSection( nSectGrpId, vpSections))
|
|
return false ;
|
|
// Contro rotazione della curva
|
|
m_pGeomDB->Rotate( nCrvId, ORIG, Z_AX, -90.0) ;
|
|
// recupero il riferimento globale della sezione
|
|
Frame3d frSect ;
|
|
m_pGeomDB->GetGroupGlobFrame( nSectGrpId, frSect) ;
|
|
// recupero il box globale della sezione
|
|
BBox3d b3Sect ;
|
|
m_pGeomDB->GetGlobalBBox( nSectGrpId, b3Sect) ;
|
|
|
|
// Recupero ed elaboro la linea guida
|
|
int nGuideId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_GUIDE)) ;
|
|
// recupero la linea guida
|
|
ICurve* pGuide = ::GetCurve( m_pGeomDB->GetGeoObj( nGuideId)) ;
|
|
if ( pGuide == nullptr)
|
|
return false ;
|
|
// recupero il suo riferimento
|
|
Frame3d frGdL ;
|
|
m_pGeomDB->GetGlobFrame( nGuideId, frGdL) ;
|
|
// porto la curva in globale (dovrebbe già avere riferimento globale)
|
|
pGuide->ToGlob( frGdL) ;
|
|
// recupero il box globale della linea guida
|
|
BBox3d b3Guide ;
|
|
m_pGeomDB->GetGlobalBBox( nGuideId, b3Guide) ;
|
|
|
|
// recupero il box del grezzo in globale
|
|
BBox3d b3Test ;
|
|
b3Test.Add( b3Sect) ;
|
|
b3Test.Add( b3Guide) ;
|
|
BBox3d b3Raw ;
|
|
if ( ! GetRawGlobBox( m_nPhase, b3Test, 10 * EPS_SMALL, b3Raw) || b3Raw.IsEmpty()) {
|
|
m_pMchMgr->SetLastError( 2703, "Error in SawFinishing : Empty RawBox") ;
|
|
return false ;
|
|
}
|
|
|
|
// valuto l'espressione dell'affondamento
|
|
ExeLuaSetGlobNumVar( "TH", 0) ;
|
|
ExeLuaSetGlobNumVar( "RB", b3Raw.GetMax().z - b3Raw.GetMin().z) ;
|
|
double dDepth ;
|
|
if ( ! ExeLuaEvalNumExpr( m_Params.m_sDepth, &dDepth)) {
|
|
m_pMchMgr->SetLastError( 2704, "Error in SawFinishing : Depth not computable") ;
|
|
return false ;
|
|
}
|
|
|
|
// creo gruppo per geometria di lavorazione
|
|
int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ;
|
|
if ( nPxId == GDB_ID_NULL)
|
|
return false ;
|
|
m_pGeomDB->SetName( nPxId, MCH_PATH + "1_1") ;
|
|
m_pGeomDB->SetMaterial( nPxId, GREEN) ;
|
|
|
|
// per ogni sezione
|
|
for ( int nSect = 0 ; nSect < ssize( vpSections) ; ++ nSect) {
|
|
|
|
// recupero la sezione corrente
|
|
ICurve* pCrv = vpSections[nSect] ;
|
|
if ( pCrv == nullptr || ! pCrv->IsValid())
|
|
continue ;
|
|
|
|
// Ripristino orientamento sezione con controrotazione
|
|
pCrv->Rotate( ORIG, Z_AX, -90.0) ;
|
|
|
|
// Approssimo la curva con una spezzata
|
|
PolyLine PL ;
|
|
if ( ! pCrv->ApproxWithLines( LIN_TOL_MID, ANG_TOL_STD_DEG, ICurve::APL_RIGHT, PL)) {
|
|
m_pMchMgr->SetLastError( 2706, "Error in SawFinishing : ApproxWithLines") ;
|
|
return false ;
|
|
}
|
|
// Se standard, allungo inizio e fine della sezione dello spessore lama
|
|
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_STD) {
|
|
// inizio
|
|
PL.Invert() ;
|
|
double dU ;
|
|
Point3d ptP ;
|
|
PL.GetLastUPoint( &dU, &ptP) ;
|
|
PL.AddUPoint( dU, ptP + Vector3d( m_TParams.m_dThick, 0, 0)) ;
|
|
PL.Invert() ;
|
|
// fine
|
|
PL.GetLastUPoint( &dU, &ptP) ;
|
|
PL.AddUPoint( dU, ptP - Vector3d( m_TParams.m_dThick, 0, 0)) ;
|
|
}
|
|
// La porto in globale
|
|
PL.ToGlob( frSect) ;
|
|
|
|
// Calcolo eventuale anticipo dell'inizio
|
|
double dAddStart = 0 ;
|
|
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_OUT) {
|
|
BBox3d b3PL ;
|
|
PL.GetLocalBBox( b3PL) ;
|
|
double dMaxElev = min( dDepth, b3Raw.GetMax().z - b3PL.GetMin().z) ;
|
|
if ( dMaxElev > 0.0 && dMaxElev < 0.5 * m_TParams.m_dDiam)
|
|
dAddStart = sqrt( dMaxElev * m_TParams.m_dDiam - dMaxElev * dMaxElev) ;
|
|
else
|
|
dAddStart = 0.5 * m_TParams.m_dDiam ;
|
|
}
|
|
|
|
// Imposto versore fresa come Z+
|
|
Vector3d vtTool = Z_AX ;
|
|
|
|
// Imposto dati comuni
|
|
SetPathId( nPxId) ;
|
|
SetToolDir( vtTool) ;
|
|
|
|
// assegno il vettore estrazione al gruppo del percorso
|
|
m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ;
|
|
|
|
// Inizializzo contatore tagli
|
|
m_nCuts = 0 ;
|
|
|
|
// Punto iniziale guida
|
|
Point3d ptPI ; Vector3d vtDirI ;
|
|
pGuide->GetPointTang( 0, ICurve::FROM_PLUS, ptPI, vtDirI) ;
|
|
// Calcolo le passate
|
|
double dLenTot ; pGuide->GetLength( dLenTot) ;
|
|
double dStep = max( m_Params.m_dSideStep, 10 * EPS_SMALL) ;
|
|
int nStep = static_cast<int>( ceil( dLenTot / dStep)) ;
|
|
dStep = dLenTot / nStep ;
|
|
double dLen = 0 ;
|
|
while ( dLen < dLenTot + 10 * EPS_SMALL) {
|
|
double dU ;
|
|
Point3d ptP ;
|
|
Vector3d vtDir ;
|
|
pGuide->GetParamAtLength( dLen, dU) ;
|
|
pGuide->GetPointTang( dU, ICurve::FROM_MINUS, ptP, vtDir) ;
|
|
// vettore di spostamento
|
|
Vector3d vtMove = ptP - ptPI ;
|
|
// angolo di rotazione
|
|
double dAngRotDeg ; vtDirI.GetAngleXY( vtDir, dAngRotDeg) ;
|
|
// vettore di correzione
|
|
Vector3d vtCorr = vtDirI ;
|
|
vtCorr.Rotate( Z_AX, dAngRotDeg - 90) ;
|
|
// flag di inizio
|
|
bool bFirst = ( dLen < EPS_SMALL) ;
|
|
// se non è inizio
|
|
bool bCorner = false ;
|
|
Vector3d vtPrev ;
|
|
if ( ! bFirst) {
|
|
// verifico se grande rotazione (oltre 15 deg)
|
|
Point3d ptPrev ;
|
|
if ( ! GetCurrPos( ptPrev) || ! GetCurrCorr( vtPrev))
|
|
return false ;
|
|
if ( vtPrev * vtCorr < cos( 15 * DEGTORAD)) {
|
|
// calcolo dell'elevazione
|
|
double dEndElev = 0 ;
|
|
GetElevation( m_nPhase, ptPrev, vtPrev, dEndElev) ;
|
|
// aggiungo retrazione
|
|
double dSafeZ = GetSafeZ() ;
|
|
double dAppr = m_Params.m_dStartPos ;
|
|
if ( ! AddRetract( ptPrev, vtPrev, dSafeZ, dEndElev, dAppr))
|
|
return false ;
|
|
bCorner = true ;
|
|
}
|
|
}
|
|
// imposto direzione attuale dopo i controlli
|
|
SetCorrAuxDir( vtCorr) ;
|
|
// lavoro la sezione
|
|
if ( m_Params.m_nStepType != SAWFIN_ST_ZIGZAG) {
|
|
//if ( ! CalcAcrossOneWayCut( PL, vtMove, vtTool, vtCorr, b3Raw.GetMax().z, dDepth))
|
|
// return false ;
|
|
}
|
|
else {
|
|
if ( ! CalcCurvedAcrossZigZagCut( PL, vtMove, ptP, dAngRotDeg, vtTool, vtCorr, vtPrev, dDepth, bFirst, bCorner))
|
|
return false ;
|
|
}
|
|
// passo al successivo
|
|
dLen += dStep ;
|
|
}
|
|
// se ZigZag aggiungo risalita
|
|
if ( m_Params.m_nStepType == SAWFIN_ST_ZIGZAG) {
|
|
// recupero distanza di sicurezza
|
|
double dSafeZ = GetSafeZ() ;
|
|
// lunghezza di approccio/retrazione
|
|
double dAppr = m_Params.m_dStartPos ;
|
|
// recupero punto e versore correzione finali
|
|
Point3d ptEnd ; Vector3d vtEnd ;
|
|
if ( ! GetCurrPos( ptEnd) || ! GetCurrCorr( vtEnd))
|
|
return false ;
|
|
// calcolo dell'elevazione
|
|
double dEndElev = 0 ;
|
|
GetElevation( m_nPhase, ptEnd, vtEnd, dEndElev) ;
|
|
// aggiungo retrazione
|
|
if ( ! AddRetract( ptEnd, vtEnd, dSafeZ, dEndElev, dAppr))
|
|
return false ;
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalculateStraightSectionToolPath( int nAuxId, int nClId)
|
|
{
|
|
// recupero il riferimento globale delle sezioni
|
|
int nSectGrpId = m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_SECTION) ;
|
|
Frame3d frSect ; m_pGeomDB->GetGroupGlobFrame( nSectGrpId, frSect) ;
|
|
// recupero il box globale delle sezioni
|
|
BBox3d b3Sect ; m_pGeomDB->GetGlobalBBox( nSectGrpId, b3Sect) ;
|
|
|
|
// Recupero ed elaboro le sezioni per portarle ad essere la curva del centro in basso della lama
|
|
ICurve* pSect ;
|
|
if ( ! CalculateOffsetSection( nSectGrpId, frSect, pSect))
|
|
return false ;
|
|
PtrOwner<ICurve> pCrv( pSect) ;
|
|
if ( IsNull( pCrv) || ! pCrv->IsValid())
|
|
return false ;
|
|
|
|
// Recupero da UserNotes il flag di estensione al bordo del grezzo
|
|
bool bExtend ;
|
|
if ( ! GetValInNotes( m_Params.m_sUserNotes, UN_EXTEND, bExtend))
|
|
bExtend = true ;
|
|
// se estensione non presente e Link di tipo Extended, lo forzo come Center
|
|
if ( ! bExtend && m_Params.m_nLeadLinkType == SAWFIN_LL_OUT) {
|
|
m_pMchMgr->SetWarning( 2655, "Warning in SawRoughing : Link not compatible with extension") ;
|
|
m_Params.m_nLeadLinkType = SAWFIN_LL_CENT ;
|
|
}
|
|
|
|
// Recupero ed elaboro la linea guida
|
|
Point3d ptGdStart, ptGdEnd ;
|
|
Vector3d vtGdDir ;
|
|
int nGuideId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_GUIDE)) ;
|
|
if ( ! CalculateGuideLine( nGuideId, ptGdStart, ptGdEnd, vtGdDir, nSectGrpId, bExtend))
|
|
return false ;
|
|
if ( m_Params.m_bInvert) {
|
|
swap( ptGdStart, ptGdEnd) ;
|
|
vtGdDir.Invert() ;
|
|
}
|
|
|
|
// recupero il box globale della linea guida
|
|
BBox3d b3Guide ; m_pGeomDB->GetGlobalBBox( nGuideId, b3Guide) ;
|
|
|
|
// recupero il box del grezzo in globale
|
|
BBox3d b3Test ;
|
|
b3Test.Add( b3Sect) ;
|
|
b3Test.Add( b3Guide) ;
|
|
BBox3d b3Raw ;
|
|
if ( ! GetRawGlobBox( m_nPhase, b3Test, 10. * EPS_SMALL, b3Raw) || b3Raw.IsEmpty()) {
|
|
m_pMchMgr->SetLastError( 2703, "Error in SawFinishing : Empty RawBox") ;
|
|
return false ;
|
|
}
|
|
|
|
// valuto l'espressione dell'affondamento
|
|
ExeLuaSetGlobNumVar( "TH", 0.) ;
|
|
ExeLuaSetGlobNumVar( "RB", b3Raw.GetMax().z - b3Raw.GetMin().z) ;
|
|
double dDepth ;
|
|
if ( ! ExeLuaEvalNumExpr( m_Params.m_sDepth, &dDepth)) {
|
|
m_pMchMgr->SetLastError( 2704, "Error in SawFinishing : Depth not computable") ;
|
|
return false ;
|
|
}
|
|
|
|
// creo gruppo per geometria di lavorazione
|
|
int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ;
|
|
if ( nPxId == GDB_ID_NULL)
|
|
return false ;
|
|
m_pGeomDB->SetName( nPxId, MCH_PATH + "1_1") ;
|
|
m_pGeomDB->SetMaterial( nPxId, GREEN) ;
|
|
|
|
// Determino versori fresa e correzione
|
|
Point3d ptSecStart ; pSect->GetStartPoint( ptSecStart) ;
|
|
Point3d ptSecEnd ; pSect->GetEndPoint( ptSecEnd) ;
|
|
Vector3d vtTool, vtCorr ;
|
|
if ( ! CalculateToolAndCorrVersors( GetToGlob( ptSecEnd - ptSecStart, frSect), m_Params.m_nHeadSide, vtTool, vtCorr)) {
|
|
m_pMchMgr->SetLastError( 2705, "Error in SawFinishing : CalculateToolAndCorrVersors") ;
|
|
return false ;
|
|
}
|
|
|
|
// Approssimo la curva di sezione ad una spezzata
|
|
PolyLine PL ;
|
|
if ( ! pCrv->ApproxWithLines( LIN_TOL_MID, ANG_TOL_STD_DEG, ICurve::APL_RIGHT, PL)) {
|
|
m_pMchMgr->SetLastError( 2706, "Error in SawFinishing : ApproxWithLines") ;
|
|
return false ;
|
|
}
|
|
// Se link standard, allungo inizio e fine della sezione dello spessore lama
|
|
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_STD) {
|
|
// inizio
|
|
PL.Invert() ;
|
|
double dU ;
|
|
Point3d ptP ;
|
|
PL.GetLastUPoint( &dU, &ptP) ;
|
|
PL.AddUPoint( dU, ptP + Vector3d( m_TParams.m_dThick, 0., 0.)) ;
|
|
PL.Invert() ;
|
|
// fine
|
|
PL.GetLastUPoint( &dU, &ptP) ;
|
|
PL.AddUPoint( dU, ptP - Vector3d( m_TParams.m_dThick, 0., 0.)) ;
|
|
}
|
|
// La porto in globale
|
|
PL.ToGlob( frSect) ;
|
|
// traslo la sezione lungo la direzione della guida per farla coicidere con il suo punto iniziale
|
|
PL.Translate( ( ( ptGdStart - GetToGlob( ptSecStart, frSect)) * vtGdDir) * vtGdDir) ;
|
|
|
|
// Imposto dati comuni
|
|
SetPathId( nPxId) ;
|
|
SetToolDir( vtTool) ;
|
|
SetCorrAuxDir( vtCorr) ;
|
|
|
|
// assegno il vettore estrazione al gruppo del percorso
|
|
m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ;
|
|
|
|
// recupero la TriMesh del grezzo in globale
|
|
PtrOwner<ISurfTriMesh> pStmRaw( CreateSurfTriMesh()) ;
|
|
if ( IsNull( pStmRaw))
|
|
return false ;
|
|
pStmRaw->AdjustTopology() ;
|
|
int nRawId = m_pMchMgr->GetFirstRawPart() ;
|
|
while ( nRawId != GDB_ID_NULL) {
|
|
// verifico che il grezzo compaia nella fase
|
|
if ( m_pMchMgr->VerifyRawPartPhase( nRawId, m_nPhase)) {
|
|
// recupero l'oggetto dal database con tale Id
|
|
int nRawSolidId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_SOLID) ;
|
|
const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( nRawSolidId) ;
|
|
if ( pGObj != nullptr) {
|
|
// recupero il frame in cui si trova
|
|
Frame3d frRaw ;
|
|
m_pGeomDB->GetGlobFrame( nRawSolidId, frRaw) ;
|
|
// controllo che sia una Trimesh
|
|
if ( pGObj->GetType() == SRF_TRIMESH) {
|
|
SurfLocal StmRawPart( GetSurfTriMesh( pGObj), frRaw, GLOB_FRM) ;
|
|
// lo aggiungo alla Trimesh complessiva
|
|
pStmRaw->Add( *GetSurfTriMesh( StmRawPart)) ;
|
|
}
|
|
}
|
|
}
|
|
// passo al grezzo successivo
|
|
nRawId = m_pMchMgr->GetNextRawPart( nRawId) ;
|
|
}
|
|
|
|
// Inizializzo contatore tagli
|
|
m_nCuts = 0 ;
|
|
|
|
// Calcolo le passate
|
|
double dStep = max( m_Params.m_dSideStep, 10. * EPS_SMALL) ;
|
|
double dL = Dist( ptGdStart, ptGdEnd) ;
|
|
int nStep = static_cast<int>( ceil( dL/dStep)) ;
|
|
dStep = dL / nStep ;
|
|
Point3d ptP ;
|
|
for ( int i = 0 ; i <= nStep ; ++ i) {
|
|
// vettore di spostamento
|
|
Vector3d vtMove = vtGdDir * ( i * dStep) ;
|
|
// se link Extended, allora estendo il percorso fino alla dimensione del grezzo
|
|
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_OUT) {
|
|
PL.Translate( vtMove) ;
|
|
if ( ! ExtendPathToRaw( PL, pStmRaw, m_TParams.m_dThick))
|
|
return false ;
|
|
PL.Translate( - vtMove) ;
|
|
}
|
|
// lavoro la sezione
|
|
if ( m_Params.m_nStepType != SAWFIN_ST_ZIGZAG) {
|
|
if ( ! CalcAcrossOneWayCut( PL, vtMove, vtTool, vtCorr, b3Raw.GetMax().z, dDepth))
|
|
return false ;
|
|
}
|
|
else {
|
|
bool bFirst = ( i == 0) ;
|
|
if ( ! CalcAcrossZigZagCut( PL, vtMove, vtTool, vtCorr, b3Raw.GetMax().z, dDepth, bFirst))
|
|
return false ;
|
|
}
|
|
}
|
|
// se ZigZag aggiungo risalita
|
|
if ( m_Params.m_nStepType == SAWFIN_ST_ZIGZAG) {
|
|
// recupero distanza di sicurezza
|
|
double dSafeZ = GetSafeZ() ;
|
|
// lunghezza di approccio/retrazione
|
|
double dAppr = m_Params.m_dStartPos ;
|
|
// aggiungo retrazione
|
|
Point3d ptEnd ;
|
|
if ( ! GetCurrPos( ptEnd))
|
|
return false ;
|
|
double dElev = b3Raw.GetMax().z - ptEnd.z ;
|
|
if ( ! AddRetract( ptEnd, vtCorr, dSafeZ, dElev, dAppr))
|
|
return false ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalculateStraightAlong5AToolPath( int nAuxId, int nClId)
|
|
{
|
|
// Recupero ed elaboro le sezioni per portarle ad essere la curva del centro in basso della lama
|
|
int nSectGrpId = m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_SECTION) ;
|
|
SECTIONVECTOR vSections ;
|
|
if ( ! Split5ASection( nSectGrpId, vSections)) {
|
|
m_pMchMgr->SetLastError( 2719, "Error in SawFinishing : Splitting Section failed") ;
|
|
return false ;
|
|
}
|
|
// recupero il riferimento globale delle sezioni
|
|
Frame3d frSect ;
|
|
m_pGeomDB->GetGroupGlobFrame( nSectGrpId, frSect) ;
|
|
// recupero il box globale delle sezioni
|
|
BBox3d b3Sect ;
|
|
m_pGeomDB->GetGlobalBBox( nSectGrpId, b3Sect) ;
|
|
|
|
// Recupero da UserNotes il flag di estensione al bordo del grezzo
|
|
bool bExtend ;
|
|
if ( ! GetValInNotes( m_Params.m_sUserNotes, UN_EXTEND, bExtend))
|
|
bExtend = true ;
|
|
// se estensione non presente e Link di tipo Extended, lo forzo come Center
|
|
if ( ! bExtend && m_Params.m_nLeadLinkType == SAWFIN_LL_OUT) {
|
|
m_pMchMgr->SetWarning( 2655, "Warning in SawRoughing : Link not compatible with extension") ;
|
|
m_Params.m_nLeadLinkType = SAWFIN_LL_CENT ;
|
|
}
|
|
// se link di tipo Standard, questa viene convertita in Center, per la lavorazione corrente si effettuano le rotazioni della lama
|
|
// sempre al di fuori del grezzo
|
|
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_STD) {
|
|
m_pMchMgr->SetWarning( 2655, "Warning in SawRoughing : Link not compatible with extension") ;
|
|
m_Params.m_nLeadLinkType = SAWFIN_LL_CENT ;
|
|
}
|
|
|
|
// Recupero ed elaboro la linea guida
|
|
Point3d ptGdStart, ptGdEnd ;
|
|
Vector3d vtGdDir ;
|
|
int nGuideId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_GUIDE)) ;
|
|
if ( ! CalculateGuideLine( nGuideId, ptGdStart, ptGdEnd, vtGdDir, nSectGrpId, false))
|
|
return false ;
|
|
if ( m_Params.m_bInvert) {
|
|
swap( ptGdStart, ptGdEnd) ;
|
|
vtGdDir.Invert() ;
|
|
}
|
|
// recupero il box globale della linea guida
|
|
BBox3d b3Guide ;
|
|
m_pGeomDB->GetGlobalBBox( nGuideId, b3Guide) ;
|
|
// recupero il box del grezzo in globale
|
|
BBox3d b3Test ;
|
|
b3Test.Add( b3Sect) ;
|
|
b3Test.Add( b3Guide) ;
|
|
BBox3d b3Raw ;
|
|
if ( ! GetRawGlobBox( m_nPhase, b3Test, 10 * EPS_SMALL, b3Raw) || b3Raw.IsEmpty()) {
|
|
m_pMchMgr->SetLastError( 2703, "Error in SawFinishing : Empty RawBox") ;
|
|
return false ;
|
|
}
|
|
|
|
// valuto l'espressione dell'affondamento
|
|
ExeLuaSetGlobNumVar( "TH", 0) ;
|
|
ExeLuaSetGlobNumVar( "RB", b3Raw.GetMax().z - b3Raw.GetMin().z) ;
|
|
double dDepth ;
|
|
if ( ! ExeLuaEvalNumExpr( m_Params.m_sDepth, &dDepth)) {
|
|
m_pMchMgr->SetLastError( 2704, "Error in SawFinishing : Depth not computable") ;
|
|
return false ;
|
|
}
|
|
|
|
// creo gruppo per geometria di lavorazione
|
|
int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ;
|
|
if ( nPxId == GDB_ID_NULL)
|
|
return false ;
|
|
m_pGeomDB->SetName( nPxId, MCH_PATH + "1_1") ;
|
|
m_pGeomDB->SetMaterial( nPxId, GREEN) ;
|
|
|
|
// Imposto dati comuni
|
|
SetPathId( nPxId) ;
|
|
|
|
// recupero la TriMesh del grezzo in globale
|
|
PtrOwner<ISurfTriMesh> pStmRaw( CreateSurfTriMesh()) ;
|
|
if ( IsNull( pStmRaw))
|
|
return false ;
|
|
pStmRaw->AdjustTopology() ;
|
|
int nRawId = m_pMchMgr->GetFirstRawPart() ;
|
|
while ( nRawId != GDB_ID_NULL) {
|
|
// verifico che il grezzo compaia nella fase
|
|
if ( m_pMchMgr->VerifyRawPartPhase( nRawId, m_nPhase)) {
|
|
// recupero l'oggetto dal database con tale Id
|
|
int nRawSolidId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_SOLID) ;
|
|
const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( nRawSolidId) ;
|
|
if ( pGObj != nullptr) {
|
|
// recupero il frame in cui si trova
|
|
Frame3d frRaw ;
|
|
m_pGeomDB->GetGlobFrame( nRawSolidId, frRaw) ;
|
|
// controllo che sia una Trimesh
|
|
if ( pGObj->GetType() == SRF_TRIMESH) {
|
|
SurfLocal StmRawPart( GetSurfTriMesh( pGObj), frRaw, GLOB_FRM) ;
|
|
// lo aggiungo alla Trimesh complessiva
|
|
pStmRaw->Add( *GetSurfTriMesh( StmRawPart)) ;
|
|
}
|
|
}
|
|
}
|
|
// passo al grezzo successivo
|
|
nRawId = m_pMchMgr->GetNextRawPart( nRawId) ;
|
|
}
|
|
|
|
// elaboro le Section/SubSections
|
|
if ( ! CalcAlong5ACuts( vSections, frSect, bExtend, ptGdStart, ptGdEnd, vtGdDir, dDepth, b3Raw, pStmRaw))
|
|
return false ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::ExtendPathToRaw( PolyLine& PL, const ISurfTriMesh* pStmRaw, double dExtraOut) const
|
|
{
|
|
// se grezzo non valido, non estendo nulla
|
|
if ( pStmRaw == nullptr || ! pStmRaw->IsValid() || pStmRaw->GetTriangleCount() == 0)
|
|
return true ;
|
|
|
|
// recupero gli estremi della PolyLine e il versore di estensione
|
|
Point3d ptS ; PL.GetFirstPoint( ptS) ;
|
|
Point3d ptE ; PL.GetLastPoint( ptE) ;
|
|
Vector3d vtExt = ( ptE - ptS) ;
|
|
vtExt.z = 0. ;
|
|
if ( ! vtExt.Normalize())
|
|
return false ;
|
|
|
|
const double LINE_LEN = 1e5 ;
|
|
const double COS_SMALL = sin( EPS_ANG_SMALL * DEGTORAD) ;
|
|
|
|
// verifico se posso estendere l'inizio
|
|
ILSIVECTOR vInfo ;
|
|
if ( ! IntersLineSurfTm( ptS, - vtExt, LINE_LEN, *pStmRaw, vInfo))
|
|
return false ;
|
|
if ( ! vInfo.empty()) {
|
|
for ( int i = 0 ; i < ssize( vInfo) ; ++ i) {
|
|
// se c'è intersezione ed esco dalla superficie
|
|
if ( vInfo[i].nILTT != ILTT_NO && vInfo[i].dCosDN > COS_SMALL) {
|
|
// aggiungo il punto di intersezione con il grezzo
|
|
PL.AddUPoint( 0., vInfo[i].ptI, false) ;
|
|
// aggiungo un punto per estensione aggiuntiva
|
|
if ( dExtraOut > EPS_SMALL)
|
|
PL.AddUPoint( 0., vInfo[i].ptI - vtExt * dExtraOut, false) ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// allo stesso modo, verifico se posso estendere la fine
|
|
vInfo.clear() ;
|
|
if ( ! IntersLineSurfTm( ptE, vtExt, LINE_LEN, *pStmRaw, vInfo))
|
|
return false ;
|
|
if ( ! vInfo.empty()) {
|
|
for ( int i = 0 ; i < ssize( vInfo) ; ++ i) {
|
|
// se c'è intersezione ed esco dalla superficie
|
|
if ( vInfo[i].nILTT != ILTT_NO && vInfo[i].dCosDN > COS_SMALL) {
|
|
// aggiungo il punto di intersezione con il grezzo
|
|
PL.AddUPoint( 0., vInfo[i].ptI, true) ;
|
|
// aggiungo un punto per estensione aggiuntiva
|
|
if ( dExtraOut > EPS_SMALL)
|
|
PL.AddUPoint( 0., vInfo[i].ptI + vtExt * dExtraOut, true) ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::TrimVerticalSectionBounds( ICurveComposite* pSect, double dAngDeg) const
|
|
{
|
|
// verifico che la curva sia valida
|
|
if ( pSect == nullptr || ! pSect->IsValid())
|
|
return false ;
|
|
|
|
// -->! NB. La sezione è già orientata per X decrescente e nel piano XY
|
|
// splitto gli archi con angolo maggiore della tolleranza
|
|
VerifyArcs( pSect, dAngDeg) ;
|
|
|
|
// elimino tutti i tratti all'inizio della sezione
|
|
const double COS_ANG_TOL = cos( ( dAngDeg) * DEGTORAD) ;
|
|
for ( int i = 0 ; i < pSect->GetCurveCount() ; ++ i) {
|
|
const ICurve* pCrv = pSect->GetCurve( i) ;
|
|
if ( pCrv != nullptr && pCrv->IsValid()) {
|
|
// se Linea
|
|
if ( pCrv->GetType() == CRV_LINE) {
|
|
Vector3d vtDir ; pCrv->GetStartDir( vtDir) ;
|
|
Vector3d vtPerp = vtDir ; vtPerp.Rotate( Z_AX, - ANG_RIGHT) ;
|
|
if ( abs( vtPerp * Y_AX) > COS_ANG_TOL) {
|
|
// se prima linea in tolleranza, elimino tutte le curve precedenti
|
|
if ( i > 0)
|
|
pSect->TrimStartAtParam( 1. * i) ;
|
|
break ;
|
|
}
|
|
}
|
|
// se Arco
|
|
else if ( pCrv->GetType() == CRV_ARC) {
|
|
const ICurveArc* pArc = GetCurveArc( pCrv) ;
|
|
if ( pArc == nullptr)
|
|
return false ;
|
|
Point3d ptCenter = pArc->GetCenter() ;
|
|
Point3d ptStart ; pArc->GetStartPoint( ptStart) ;
|
|
Point3d ptEnd ; pArc->GetEndPoint( ptEnd) ;
|
|
Vector3d vtDirS = ( ptStart - ptCenter) ; vtDirS.Normalize() ;
|
|
Vector3d vtDirE = ( ptEnd - ptCenter) ; vtDirE.Normalize() ;
|
|
bool bOkStart = ( abs( vtDirS * Y_AX) > COS_ANG_TOL) ;
|
|
bool bOkEnd = ( abs( vtDirE * Y_AX) > COS_ANG_TOL) ;
|
|
// se inizio valido, allora non ho bisogno di modificare l'arco corrente (elimino eventuali curve precedenti)
|
|
if ( bOkStart) {
|
|
if ( i > 0)
|
|
pSect->TrimStartAtParam( 1. * i) ;
|
|
break ;
|
|
}
|
|
// se nè inizio nè fine validi, passo il controllo alla curva successiva
|
|
if ( ! bOkEnd)
|
|
continue ;
|
|
// se inizio non valido, ma fine in tolleranza, determino il nuovo punto iniziale della curva e trimmo tutto in precedenza
|
|
else {
|
|
// Trim iniziale
|
|
Point3d ptNewStart = ptCenter + pArc->GetRadius() * Y_AX ;
|
|
ptNewStart.Rotate( ptCenter, Z_AX, - dAngDeg) ;
|
|
double dUTrim = 0. ;
|
|
pSect->GetParamAtPoint( ptNewStart, dUTrim, 10. * EPS_SMALL) ;
|
|
pSect->TrimStartAtParam( dUTrim) ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ripeto lo stesso ragionemento per il tratto finale
|
|
if ( ! pSect->IsValid())
|
|
return false ;
|
|
for ( int i = pSect->GetCurveCount() - 1 ; i >= 0 ; -- i) {
|
|
const ICurve* pCrv = pSect->GetCurve( i) ;
|
|
if ( pCrv != nullptr && pCrv->IsValid()) {
|
|
// se Linea
|
|
if ( pCrv->GetType() == CRV_LINE) {
|
|
Vector3d vtDir ; pCrv->GetStartDir( vtDir) ;
|
|
Vector3d vtPerp = vtDir ; vtPerp.Rotate( Z_AX, - ANG_RIGHT) ;
|
|
if ( abs( vtPerp * Y_AX) > COS_ANG_TOL) {
|
|
// se linea in tolleranza, elimino tutte le successive
|
|
if ( i < pSect->GetCurveCount() - 1)
|
|
pSect->TrimEndAtParam( 1. * ( i + 1)) ;
|
|
break ;
|
|
}
|
|
}
|
|
// se Arco
|
|
else if ( pCrv->GetType() == CRV_ARC) {
|
|
const ICurveArc* pArc = GetCurveArc( pCrv) ;
|
|
if ( pArc == nullptr)
|
|
return false ;
|
|
Point3d ptCenter = pArc->GetCenter() ;
|
|
Point3d ptStart ; pArc->GetStartPoint( ptStart) ;
|
|
Point3d ptEnd ; pArc->GetEndPoint( ptEnd) ;
|
|
Vector3d vtDirS = ( ptStart - ptCenter) ; vtDirS.Normalize() ;
|
|
Vector3d vtDirE = ( ptEnd - ptCenter) ; vtDirE.Normalize() ;
|
|
bool bOkStart = ( abs( vtDirS * Y_AX) > COS_ANG_TOL) ;
|
|
bool bOkEnd = ( abs( vtDirE * Y_AX) > COS_ANG_TOL) ;
|
|
// se fine valido, non ho bisogno di modificare l'arco corrente (elimino eventuali curve precedenti)
|
|
if ( bOkEnd) {
|
|
if ( i < pSect->GetCurveCount() - 1)
|
|
pSect->TrimEndAtParam( 1. * ( i + 1)) ;
|
|
break ;
|
|
}
|
|
// se nè inizio nè fine validi, passo il controllo alla curva successiva
|
|
if ( ! bOkStart)
|
|
continue ;
|
|
// se inizio no valido, ma fine in tolleranza, determino il nuovo punto finale della curva e trimmo tutto in successione
|
|
else {
|
|
// Trim Finale
|
|
Point3d ptNewEnd = ptCenter + pArc->GetRadius() * Y_AX ;
|
|
ptNewEnd.Rotate( ptCenter, Z_AX, dAngDeg) ;
|
|
double dUTrim = pSect->GetCurveCount() - 1 ;
|
|
pSect->GetParamAtPoint( ptNewEnd, dUTrim, 10. * EPS_SMALL) ;
|
|
pSect->TrimEndAtParam( dUTrim) ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( pSect->IsValid()) {
|
|
pSect->MergeCurves( LIN_TOL_MID, ANG_TOL_STD_DEG) ;
|
|
return true ;
|
|
}
|
|
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalculateOffsetSection( int nSectGrpId, const Frame3d& frSec, ICurve*& pSect) const
|
|
{
|
|
// recupero le sezioni
|
|
ICURVEPVECTOR vpSects ;
|
|
int nSectId = m_pGeomDB->GetFirstInGroup( nSectGrpId) ;
|
|
while ( nSectId != GDB_ID_NULL) {
|
|
// recupero il puntatore alla curva
|
|
vpSects.emplace_back( ::GetCurve( m_pGeomDB->GetGeoObj( nSectId))) ;
|
|
if ( vpSects.back() == nullptr)
|
|
return false ;
|
|
// passo alla successiva
|
|
nSectId = m_pGeomDB->GetNext( nSectId) ;
|
|
}
|
|
|
|
// elimino eventuali sottosquadra
|
|
ICURVEPOVECTOR vpNucCrvs ;
|
|
vpNucCrvs.reserve( vpSects.size()) ;
|
|
for ( const auto& pSect : vpSects) {
|
|
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
|
|
if ( IsNull( pCrvCompo) ||
|
|
! pCrvCompo->AddCurve( *pSect) ||
|
|
! pCrvCompo->RemoveUndercutOnY( LIN_TOL_STD, ANG_TOL_STD_DEG))
|
|
return false ;
|
|
|
|
vpNucCrvs.emplace_back( Release( pCrvCompo)) ;
|
|
}
|
|
|
|
// calcolo ordinamento delle curve secondo la X decrescente
|
|
typedef pair<int,double> INDASC ; // coppia indice, ascissa
|
|
typedef vector<INDASC> INDASCVECTOR ; // vettore di coppie indice, ascissa
|
|
INDASCVECTOR vIAsc ;
|
|
vIAsc.reserve( vpNucCrvs.size()) ;
|
|
for ( int i = 0 ; i < ssize( vpNucCrvs) ; ++ i) {
|
|
Point3d ptStart ;
|
|
if ( ! vpNucCrvs[i]->GetStartPoint( ptStart))
|
|
return false ;
|
|
vIAsc.emplace_back( i, ptStart.x) ;
|
|
}
|
|
sort( vIAsc.begin(), vIAsc.end(), []( const INDASC& a, const INDASC& b) { return a.second > b.second ; }) ;
|
|
|
|
// definisco la regione non oltrepassabile dal fondo della lama
|
|
BBox3d b3Raw ;
|
|
if ( ! GetCurrRawsGlobBox( b3Raw) || b3Raw.IsEmpty()) {
|
|
m_pMchMgr->SetLastError( 2703, "Error in SawFinishing : Empty RawBox") ;
|
|
return false ;
|
|
}
|
|
b3Raw.ToLoc( frSec) ;
|
|
Point3d ptMin = b3Raw.GetMin(),
|
|
ptMax = b3Raw.GetMax() ;
|
|
double dMinY = 5. ;
|
|
double dTabDist = 0. ;
|
|
if ( GetValInNotes( m_Params.m_sUserNotes, UN_RB_DIST, dTabDist) && dTabDist > dMinY)
|
|
dMinY = dTabDist ;
|
|
const double LINE_EXT = 1e5 ;
|
|
Point3d ptLineMinYStart = Point3d( ptMin.x - LINE_EXT, ptMin.y + dMinY, 0.) ;
|
|
Point3d ptLineMinYEnd = Point3d( ptMax.x + LINE_EXT, ptMin.y + dMinY, 0.) ;
|
|
PtrOwner<ICurveComposite> pCompoRegLimit( CreateCurveComposite()) ;
|
|
if ( IsNull( pCompoRegLimit))
|
|
return false ;
|
|
pCompoRegLimit->AddPoint( ptLineMinYStart) ;
|
|
pCompoRegLimit->AddLine( ptLineMinYStart - Y_AX * LINE_EXT) ;
|
|
pCompoRegLimit->AddLine( ptLineMinYEnd - Y_AX * LINE_EXT) ;
|
|
pCompoRegLimit->AddLine( ptLineMinYEnd) ;
|
|
pCompoRegLimit->Close() ;
|
|
PtrOwner<ISurfFlatRegion> pSfrLimit( CreateSurfFlatRegion()) ;
|
|
if ( IsNull( pSfrLimit) || ! pSfrLimit->AddExtLoop( ::Release( pCompoRegLimit)))
|
|
return false ;
|
|
|
|
// unisco le diverse curve (ora aperte) in un unico profilo
|
|
PtrOwner<ICurveComposite> pCurve( CreateCurveComposite()) ;
|
|
if ( IsNull( pCurve))
|
|
return false ;
|
|
bool bFirst = true ;
|
|
for ( int i = 0 ; i < ssize( vpNucCrvs) ; ++ i) {
|
|
if ( ! bFirst) {
|
|
Point3d ptStart ;
|
|
if ( ! vpNucCrvs[vIAsc[i].first]->GetStartPoint( ptStart) ||
|
|
! pCurve->AddLine( ptStart))
|
|
return false ;
|
|
}
|
|
if ( ! pCurve->AddCurve( Release( vpNucCrvs[vIAsc[i].first])))
|
|
return false ;
|
|
bFirst = false ;
|
|
}
|
|
|
|
// elimino tutti i tratti all'inizio e alla fine della sezione con tangenza sotto i 60deg
|
|
double dAngDegSplit = 60. ;
|
|
double dAngUN = 0. ;
|
|
if ( GetValInNotes( m_Params.m_sUserNotes, UN_LIMIT_ANG, dAngUN))
|
|
dAngDegSplit = max( 15. - EPS_ANG_SMALL, dAngUN) ;
|
|
if ( ! TrimVerticalSectionBounds( pCurve, dAngDegSplit))
|
|
return false ;
|
|
|
|
// offset radiale delle sezioni per il sovramateriale e il raggio utensile
|
|
OffsetCurve OffsCrv ;
|
|
pCurve->Translate( - Y_AX * m_TParams.m_dDiam / 2.) ;
|
|
OffsCrv.Make( pCurve, m_TParams.m_dDiam / 2. + GetOffsR(), ICurve::OFF_FILLET) ;
|
|
PtrOwner<ICurve> pOvrCrv( OffsCrv.GetLongerCurve()) ;
|
|
|
|
// la curva ricavata deve essere sufficientemente distante dal fondo del grezzo
|
|
CRVCVECTOR ccClass ;
|
|
if ( ! pSfrLimit->GetCurveClassification( *pOvrCrv, EPS_SMALL, ccClass))
|
|
return false ;
|
|
ICURVEPOVECTOR vpCrvOut ; vpCrvOut.reserve( ccClass.size()) ;
|
|
for ( int i = 0 ; i < ssize( ccClass) ; ++ i) {
|
|
if ( ccClass[i].nClass != CRVC_IN)
|
|
vpCrvOut.emplace_back( pOvrCrv->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE)) ;
|
|
}
|
|
erase_if( vpCrvOut, []( const ICurve* pCrv) { return ( pCrv == nullptr || ! pCrv->IsValid()) ; }) ;
|
|
if ( vpCrvOut.empty())
|
|
return false ;
|
|
pCurve->Clear() ;
|
|
bFirst = true ;
|
|
for ( int i = 0 ; i < ssize( vpCrvOut) ; ++ i) {
|
|
if ( ! bFirst) {
|
|
Point3d ptStart ;
|
|
if ( ! vpCrvOut[i]->GetStartPoint( ptStart) || ! pCurve->AddLine( ptStart))
|
|
return false ;
|
|
}
|
|
if ( ! pCurve->AddCurve( Release( vpCrvOut[i])))
|
|
return false ;
|
|
bFirst = false ;
|
|
}
|
|
|
|
// eseguo trim (se richiesto)
|
|
if ( IsNull( pCurve) || ! TrimSection( pCurve))
|
|
return false ;
|
|
|
|
pSect = Release( pCurve) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalculateSection( int nSectGrpId, ICRVCOMPOPOVECTOR& vpSections) const
|
|
{
|
|
vpSections.clear() ;
|
|
|
|
// recupero le sezioni
|
|
ICURVEPVECTOR vpSects ;
|
|
int nSectId = m_pGeomDB->GetFirstInGroup( nSectGrpId) ;
|
|
while ( nSectId != GDB_ID_NULL) {
|
|
// recupero il puntatore alla curva
|
|
vpSects.emplace_back( ::GetCurve( m_pGeomDB->GetGeoObj( nSectId))) ;
|
|
if ( vpSects.back() == nullptr)
|
|
return false ;
|
|
// passo alla successiva
|
|
nSectId = m_pGeomDB->GetNext( nSectId) ;
|
|
}
|
|
|
|
// elimino eventuali sottosquadra ed oriento ogni curva secondo per X decrescente
|
|
ICURVEPOVECTOR vpNucCrvs ; vpNucCrvs.reserve( vpSects.size()) ;
|
|
for ( const auto& pSect : vpSects) {
|
|
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
|
|
if ( IsNull( pCrvCompo) ||
|
|
! pCrvCompo->AddCurve( *pSect) ||
|
|
! pCrvCompo->RemoveUndercutOnY( LIN_TOL_STD, ANG_TOL_STD_DEG) ||
|
|
! vpNucCrvs.emplace_back( ::Release( pCrvCompo)))
|
|
return false ;
|
|
Point3d ptS ; vpNucCrvs.back()->GetStartPoint( ptS) ;
|
|
Point3d ptE ; vpNucCrvs.back()->GetEndPoint( ptE) ;
|
|
if ( ptS.x < ptE.x)
|
|
vpNucCrvs.back()->Invert() ;
|
|
}
|
|
|
|
// dalle sezioni recuperate eseguo l'Offset Radiale complessivo (evito così interferenze con sezioni differenti)
|
|
ICURVEPVECTOR vpMySections ; vpMySections.resize( vpNucCrvs.size()) ;
|
|
for ( int i = 0 ; i < ssize( vpNucCrvs) ; ++ i)
|
|
vpMySections[i] = vpNucCrvs[i] ;
|
|
ICURVEPOVECTOR vMySections ;
|
|
if ( ! CalcOffsetCurves( vpMySections, vMySections, GetOffsR()))
|
|
return false ;
|
|
vpSections.reserve( vMySections.size()) ;
|
|
for ( int i = 0 ; i < ssize( vMySections) ; ++ i) {
|
|
if ( vMySections[i] != nullptr && vMySections[i]->IsValid()) {
|
|
vpSections.resize( vpSections.size() + 1) ;
|
|
if ( ! vpSections.back().Set( CreateCurveComposite()) ||
|
|
! vpSections.back()->AddCurve( vMySections[i]->Clone()))
|
|
return false ;
|
|
// eseguo anche Offset lungo X
|
|
OffsetCurveOnX OffsCrvX ;
|
|
if ( ! OffsCrvX.Make( vpSections.back(), 0.5 * m_TParams.m_dThick))
|
|
return false ;
|
|
PtrOwner<ICurve> pCrv( OffsCrvX.GetLongerCurve()) ;
|
|
if ( IsNull( pCrv) || ! pCrv->IsValid())
|
|
return false ;
|
|
// trim della sezione (se richiesto)
|
|
if ( ! TrimSection( pCrv))
|
|
return false ;
|
|
// memorizzo il risultato
|
|
if ( ! vpSections.back()->Clear() ||
|
|
! vpSections.back()->AddCurve( ::Release( pCrv)))
|
|
return false ;
|
|
}
|
|
}
|
|
|
|
// le curve ricavate vengo ordinate per X descrescente
|
|
// NB. prima le curve sono orientate per X decrescente, quindi ogni curva si muove verso sinistra; ora, se si hanno più sezioni, queste
|
|
// vengono lavorate oridinatamente da destra a sinistra
|
|
typedef pair<int,double> INDASC ; // coppia indice, ascissa
|
|
typedef vector<INDASC> INDASCVECTOR ; // vettore di coppie indice, ascissa
|
|
INDASCVECTOR vIAsc ; vIAsc.reserve( vpSections.size()) ;
|
|
for ( int i = 0 ; i < ssize( vpSections) ; ++ i) {
|
|
Point3d ptStart ;
|
|
if ( ! vpSections[i]->GetStartPoint( ptStart))
|
|
return false ;
|
|
vIAsc.emplace_back( i, ptStart.x) ;
|
|
}
|
|
sort( vIAsc.begin(), vIAsc.end(), []( const INDASC& a, const INDASC& b) { return a.second > b.second ; }) ;
|
|
for ( int nNewPos = 0 ; nNewPos < ssize( vIAsc) ; ++ nNewPos) {
|
|
int nOldPos = vIAsc[nNewPos].first ;
|
|
if ( nOldPos == nNewPos)
|
|
continue ;
|
|
swap( vpSections[nNewPos], vpSections[nOldPos]) ;
|
|
swap( vIAsc[nNewPos].first, vIAsc[nOldPos].first) ;
|
|
}
|
|
|
|
erase_if( vpSections, []( const ICurveComposite* pSection) { return ( pSection != nullptr && ! pSection->IsValid()) ; }) ;
|
|
return ( ! vpSections.empty()) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::TrimSection( ICurve* pCrv) const
|
|
{
|
|
// se parametri di accorciamento iniziale e finale sono nulli, non faccio alcunché
|
|
if ( m_Params.m_dStartAddLen > -EPS_SMALL && m_Params.m_dEndAddLen > -EPS_SMALL)
|
|
return true ;
|
|
|
|
// box della sezione in locale
|
|
BBox3d b3Crv ;
|
|
pCrv->GetBBox( Frame3d(), b3Crv) ;
|
|
|
|
// riduco gli estremi in X
|
|
Point3d ptMin = b3Crv.GetMin() ;
|
|
Point3d ptMax = b3Crv.GetMax() ;
|
|
ptMin.x -= m_Params.m_dStartAddLen ;
|
|
ptMax.x += m_Params.m_dEndAddLen ;
|
|
double dDimX = ptMax.x - ptMin.x ;
|
|
double dDimY = ptMax.y - ptMin.y + 100. * EPS_SMALL ;
|
|
|
|
// regione del box nel piano XY
|
|
PtrOwner<ISurfFlatRegion> pSfr( GetSurfFlatRegionRectangle( dDimX, dDimY)) ;
|
|
if ( IsNull( pSfr))
|
|
return false ;
|
|
pSfr->Translate( Vector3d( ptMin.x, ptMin.y - 50. * EPS_SMALL, ptMin.z)) ;
|
|
|
|
// calcolo la classificazione della curva rispetto alla regione
|
|
CRVCVECTOR ccClass ;
|
|
if ( ! pSfr->GetCurveClassification( *pCrv, EPS_SMALL, ccClass))
|
|
return false ;
|
|
|
|
// determino l'intervallo di curva da conservare
|
|
Intervals inOk ;
|
|
for ( const CrvClass& ccOne : ccClass) {
|
|
if ( ccOne.nClass == CRVC_IN || ccOne.nClass == CRVC_ON_P || ccOne.nClass == CRVC_ON_M)
|
|
inOk.Add( ccOne.dParS, ccOne.dParE) ;
|
|
}
|
|
|
|
// eseguo trim
|
|
double dUmin, dUmax ;
|
|
if ( ! inOk.GetMinMax( dUmin, dUmax))
|
|
return false ;
|
|
return ( pCrv->TrimEndAtParam( dUmax) && pCrv->TrimStartAtParam( dUmin)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::Split5ASection( int nSectGrpId, SECTIONVECTOR& vSections) const
|
|
{
|
|
vSections.clear() ;
|
|
|
|
// recupero le sezioni
|
|
ICURVEPVECTOR vpSects ;
|
|
int nSectId = m_pGeomDB->GetFirstInGroup( nSectGrpId) ;
|
|
while ( nSectId != GDB_ID_NULL) {
|
|
// recupero il puntatore alla curva
|
|
vpSects.emplace_back( ::GetCurve( m_pGeomDB->GetGeoObj( nSectId))) ;
|
|
if ( vpSects.back() == nullptr)
|
|
return false ;
|
|
// passo alla successiva
|
|
nSectId = m_pGeomDB->GetNext( nSectId) ;
|
|
}
|
|
|
|
// elimino eventuali sottosquadra
|
|
ICRVCOMPOPOVECTOR vpNucCrvs ; vpNucCrvs.reserve( vpSects.size()) ;
|
|
for ( const auto& pSect : vpSects) {
|
|
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
|
|
if ( IsNull( pCrvCompo) ||
|
|
! pCrvCompo->AddCurve( *pSect) ||
|
|
! pCrvCompo->RemoveUndercutOnY( LIN_TOL_STD, ANG_TOL_STD_DEG))
|
|
return false ;
|
|
vpNucCrvs.emplace_back( Release( pCrvCompo)) ;
|
|
}
|
|
|
|
// per ogni sezione vengono rimossi i tratti verticali
|
|
ICRVCOMPOPOVECTOR vSimpleSections ;
|
|
for ( int i = 0 ; i < ssize( vpNucCrvs) ; ++ i) {
|
|
// se tratto non valido, non lo considero
|
|
if ( IsNull( vpNucCrvs[i]) || ! vpNucCrvs[i]->IsValid())
|
|
return false ;
|
|
|
|
// oriento la curva corrente per X decrescenti
|
|
Point3d ptStart ; vpNucCrvs[i]->GetStartPoint( ptStart) ;
|
|
Point3d ptEnd ; vpNucCrvs[i]->GetEndPoint( ptEnd) ;
|
|
if ( ptEnd.x > ptStart.x)
|
|
vpNucCrvs[i]->Invert() ;
|
|
|
|
// approssimo per la presenza di archi e classifico i tratti
|
|
PolyLine PL ;
|
|
vpNucCrvs[i]->ApproxWithLines( LIN_TOL_MID, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) ;
|
|
vpNucCrvs[i]->Clear() ;
|
|
vpNucCrvs[i]->FromPolyLine( PL) ;
|
|
INTVECTOR vnClass ;
|
|
if ( ! ClassifySection( vpNucCrvs[i], vnClass))
|
|
return false ;
|
|
|
|
// vettore delle parti di sezione validi senza tratti verticiali (e sottosquadra)
|
|
ICRVCOMPOPOVECTOR vpNucCrvsNoVert ; vpNucCrvsNoVert.reserve( vnClass.size()) ;
|
|
PtrOwner<ICurveComposite> pCompoTmp( nullptr) ;
|
|
for ( int j = 0 ; j < ssize( vnClass) ; ++ j) {
|
|
if ( vnClass[j] == CCL_VERT) {
|
|
if ( ! IsNull( pCompoTmp) && pCompoTmp->IsValid())
|
|
vpNucCrvsNoVert.emplace_back( ::Release( pCompoTmp)) ;
|
|
}
|
|
else {
|
|
if ( IsNull( pCompoTmp))
|
|
pCompoTmp.Set( CreateCurveComposite()) ;
|
|
const ICurve* pCrv = vpNucCrvs[i]->GetCurve( j) ;
|
|
if ( pCrv == nullptr || ! pCrv->IsValid())
|
|
return false ;
|
|
pCompoTmp->AddCurve( pCrv->Clone()) ;
|
|
}
|
|
}
|
|
erase_if( vpNucCrvsNoVert, []( const PtrOwner<ICurveComposite>& pCompo) { return ( pCompo == nullptr || ! pCompo->IsValid()) ; }) ;
|
|
for ( int j = 0 ; j < ssize( vpNucCrvsNoVert) ; ++ j) {
|
|
if ( ! vSimpleSections.emplace_back( ::Release( vpNucCrvsNoVert[j])))
|
|
return false ;
|
|
}
|
|
}
|
|
|
|
// dalle sezioni semplici recuperate eseguo l'Offset Radiale complessivo ( evito così interferenze con sezioni differenti)
|
|
ICURVEPVECTOR vMySimpleSections ; vMySimpleSections.resize( vSimpleSections.size()) ;
|
|
for ( int i = 0 ; i < ssize( vSimpleSections) ; ++ i)
|
|
vMySimpleSections[i] = vSimpleSections[i] ;
|
|
ICURVEPOVECTOR vMySections ;
|
|
if ( ! CalcOffsetCurves( vMySimpleSections, vMySections, GetOffsR()))
|
|
return false ;
|
|
for ( int i = 0 ; i < ssize( vMySections) ; ++ i) {
|
|
if ( vMySections[i] != nullptr && vMySections[i]->IsValid()) {
|
|
vSections.resize( vSections.size() + 1) ;
|
|
if ( ! vSections.back().pSection.Set( CreateCurveComposite()) || ! vSections.back().pSection->AddCurve( vMySections[i]->Clone()))
|
|
return false ;
|
|
}
|
|
}
|
|
erase_if( vSections, []( const SectionInfo& SectionInfo) {
|
|
return ( SectionInfo.pSection == nullptr || ! SectionInfo.pSection->IsValid()) ;
|
|
}) ;
|
|
|
|
// calcolo ordinamento delle curve secondo la X decrescente
|
|
typedef pair<int,double> INDASC ; // coppia indice, ascissa
|
|
typedef vector<INDASC> INDASCVECTOR ; // vettore di coppie indice, ascissa
|
|
INDASCVECTOR vIAsc ;
|
|
vIAsc.reserve( vSections.size()) ;
|
|
for ( int i = 0 ; i < ssize( vSections) ; ++ i) {
|
|
Point3d ptStart ;
|
|
if ( ! vSections[i].pSection->GetStartPoint( ptStart))
|
|
return false ;
|
|
vIAsc.emplace_back( i, ptStart.x) ;
|
|
}
|
|
sort( vIAsc.begin(), vIAsc.end(), []( const INDASC& a, const INDASC& b) { return a.second > b.second ; }) ;
|
|
for ( int nNewPos = 0 ; nNewPos < ssize( vIAsc) ; ++ nNewPos) {
|
|
int nOldPos = vIAsc[nNewPos].first ;
|
|
if ( nOldPos == nNewPos)
|
|
continue ;
|
|
swap( vSections[nNewPos], vSections[nOldPos]) ;
|
|
swap( vIAsc[nNewPos].first, vIAsc[nOldPos].first) ;
|
|
}
|
|
|
|
// !<-- NB:
|
|
// - Una Section semplice non presente tratti verticali e non presenta tratti in sottosquadra
|
|
// - Una Section semplice è orientata per X decrescente
|
|
// - Le sue SubSections sono anch'esse orientate per X decrescente
|
|
|
|
// recupero angolo di Split iniziale e finale per i tratti
|
|
double dAngDegSplit = 60. ;
|
|
double dAngUN = 0. ;
|
|
if ( GetValInNotes( m_Params.m_sUserNotes, UN_LIMIT_ANG, dAngUN))
|
|
dAngDegSplit = max( 15. - EPS_ANG_SMALL, dAngUN) ;
|
|
|
|
// ---------------------------- funzioni ausiliarie semplici -------------------------------------
|
|
auto AddSubSection = [&]( SUBSECTIONVECTOR& vSubSections, PtrOwner<ICurveComposite>& pCompo, int nHeadSide) {
|
|
if ( IsNull( pCompo) || ! pCompo->IsValid())
|
|
return false ;
|
|
vSubSections.resize( vSubSections.size() + 1) ;
|
|
vSubSections.back().pSubSection.Set( ::Release( pCompo)) ;
|
|
vSubSections.back().nHeadSide = nHeadSide ;
|
|
return true ;
|
|
} ;
|
|
auto GetHeadSide = [&]( int nClass) {
|
|
if ( nClass == CCL_FALL)
|
|
return int( SAWFIN_HS_RIGHT) ;
|
|
else if ( nClass == CCL_RISE)
|
|
return int( SAWFIN_HS_LEFT) ;
|
|
else
|
|
return m_Params.m_nHeadSide ;
|
|
} ;
|
|
|
|
// per ogni sezione semplice
|
|
for ( int i = 0 ; i < ssize( vSections) ; ++ i) {
|
|
|
|
// riferimenti
|
|
SectionInfo& CurrSection = vSections[i] ;
|
|
SUBSECTIONVECTOR& vCurrSubSections = CurrSection.vSubSections ;
|
|
|
|
// elimino tutti i tratti all'inizio e alla fine della sezione con tangenza sotto i 60deg
|
|
if ( ! TrimVerticalSectionBounds( CurrSection.pSection, dAngDegSplit))
|
|
return false ;
|
|
// eseguo trim della parte iniziale e finale (se richiesto)
|
|
if ( ! TrimSection( CurrSection.pSection))
|
|
return false ;
|
|
// Classifico i tratti a seconda della pendenza (salita, discesa, verticale, orizzontale)
|
|
INTVECTOR vnClass ;
|
|
if ( ! ClassifySection( CurrSection.pSection, vnClass))
|
|
return false ;
|
|
|
|
// se una sola classificazione presente
|
|
if ( ssize( vnClass) == 1) {
|
|
PtrOwner<ICurveComposite> pSubSection( CloneCurveComposite( CurrSection.pSection)) ;
|
|
return AddSubSection( vCurrSubSections, pSubSection, vnClass[0]) ;
|
|
}
|
|
|
|
// scrorro i tratti correnti
|
|
bool bCanSwapHead = true ;
|
|
for ( int i = 1 ; i < ssize( vnClass) ; ++ i) {
|
|
if ( i == 1) {
|
|
// inserisco il primo elemento
|
|
PtrOwner<ICurveComposite> pCompoSubSect( ConvertCurveToComposite( CurrSection.pSection->CopyParamRange( double( i - 1), double( i)))) ;
|
|
if ( ! AddSubSection( vCurrSubSections, pCompoSubSect, GetHeadSide( vnClass[0])))
|
|
return false ;
|
|
}
|
|
// classificazione corrente
|
|
const int& nCurrClass = vnClass[i] ;
|
|
// classificazione precedente
|
|
const int& nPrevClass = vnClass[i - 1] ;
|
|
// parametri per copia sotto-tratto corrente
|
|
double dUS = double( i) ;
|
|
double dUE = double( i + 1) ;
|
|
PtrOwner<ICurveComposite> pCompoSub( ConvertCurveToComposite( CurrSection.pSection->CopyParamRange( dUS, dUE))) ;
|
|
if ( IsNull( pCompoSub) || ! pCompoSub->IsValid())
|
|
return false ;
|
|
switch ( nCurrClass) {
|
|
// --- classificazione corrente Flat o Small
|
|
case CCL_FLAT :
|
|
case CCL_SMALL :
|
|
{
|
|
// a prescindere dai valori precedenti si aggiunge semplicemente il tratto di sezione
|
|
if ( ! vCurrSubSections.back().pSubSection->AddCurve( ::Release( pCompoSub)))
|
|
return false ;
|
|
bCanSwapHead = ( bCanSwapHead && ( nPrevClass != CCL_RISE && nPrevClass != CCL_FALL)) ;
|
|
break ;
|
|
}
|
|
// --- classificazione corrente Fall (la testa deve essere a destra)
|
|
case CCL_FALL : {
|
|
// se la precedente è flat, veticale o small
|
|
if ( nPrevClass == CCL_FLAT || nPrevClass == CCL_SMALL) {
|
|
if ( vCurrSubSections.back().nHeadSide == SAWFIN_HS_RIGHT) {
|
|
// allungo il percorso precedente
|
|
if ( ! vCurrSubSections.back().pSubSection->AddCurve( ::Release( pCompoSub)))
|
|
return false ;
|
|
// non posso swappare la testa
|
|
bCanSwapHead = false ;
|
|
}
|
|
else if ( bCanSwapHead) {
|
|
// inverto la testa del percorso precedente e mi collego
|
|
vCurrSubSections.back().nHeadSide = SAWFIN_HS_RIGHT ;
|
|
if ( ! vCurrSubSections.back().pSubSection->AddCurve( ::Release( pCompoSub)))
|
|
return false ;
|
|
bCanSwapHead = false ;
|
|
}
|
|
else {
|
|
// nuovo percorso
|
|
PtrOwner<ICurveComposite> pCompoSubSect( ::Release( pCompoSub)) ;
|
|
if ( ! AddSubSection( vCurrSubSections, pCompoSubSect, SAWFIN_HS_RIGHT))
|
|
return false ;
|
|
}
|
|
}
|
|
// se la precedente è fall
|
|
else if ( nPrevClass == CCL_FALL) {
|
|
// allungo il percorso precedente
|
|
if ( ! vCurrSubSections.back().pSubSection->AddCurve( ::Release( pCompoSub)))
|
|
return false ;
|
|
}
|
|
// se la precedente è Rise
|
|
else if ( nPrevClass == CCL_RISE) {
|
|
// definisco un nuovo percorso
|
|
PtrOwner<ICurveComposite> pCompoSubSect( ::Release( pCompoSub)) ;
|
|
if ( ! AddSubSection( vCurrSubSections, pCompoSubSect, SAWFIN_HS_RIGHT))
|
|
return false ;
|
|
}
|
|
break ;
|
|
}
|
|
// --- classificazione corrente Rise (la testa deve essere a sinistra)
|
|
case CCL_RISE : {
|
|
// se la precedente è flat, veticale o small
|
|
if ( nPrevClass == CCL_FLAT || nPrevClass == CCL_SMALL) {
|
|
if ( vCurrSubSections.back().nHeadSide == SAWFIN_HS_LEFT) {
|
|
// allungo il percorso precedente
|
|
if ( ! vCurrSubSections.back().pSubSection->AddCurve( ::Release( pCompoSub)))
|
|
return false ;
|
|
// non posso swappare la testa
|
|
bCanSwapHead = false ;
|
|
}
|
|
else if ( bCanSwapHead) {
|
|
// inverto la testa del percorso precedente e mi collego
|
|
vCurrSubSections.back().nHeadSide = SAWFIN_HS_LEFT ;
|
|
if ( ! vCurrSubSections.back().pSubSection->AddCurve( ::Release( pCompoSub)))
|
|
return false ;
|
|
bCanSwapHead = false ;
|
|
}
|
|
else {
|
|
// nuovo percorso
|
|
PtrOwner<ICurveComposite> pCompoSubSect( ::Release( pCompoSub)) ;
|
|
if ( ! AddSubSection( vCurrSubSections, pCompoSubSect, SAWFIN_HS_LEFT))
|
|
return false ;
|
|
}
|
|
}
|
|
// se la precedente è fall
|
|
else if ( nPrevClass == CCL_FALL) {
|
|
// definisco un nuovo percorso
|
|
PtrOwner<ICurveComposite> pCompoSubSect( ::Release( pCompoSub)) ;
|
|
if ( ! AddSubSection( vCurrSubSections, pCompoSubSect, SAWFIN_HS_LEFT))
|
|
return false ;
|
|
}
|
|
// se la precedente è Rise
|
|
else if ( nPrevClass == CCL_RISE) {
|
|
// allungo il percorso precedente
|
|
if ( ! vCurrSubSections.back().pSubSection->AddCurve( ::Release( pCompoSub)))
|
|
return false ;
|
|
}
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::AdaptGuideLineToRaw( Point3d& ptGdStart, Point3d& ptGdEnd, const Vector3d& vtGdDir, bool bExtend, const ISurfTriMesh* pStmRaw) const
|
|
{
|
|
// se non richiesta estensione, non faccio nulla
|
|
if ( ! bExtend)
|
|
return true ;
|
|
// se grezzo non presente, non faccio nulla
|
|
if ( pStmRaw == nullptr || ! pStmRaw->IsValid() || pStmRaw->GetTriangleCount() == 0)
|
|
return true ;
|
|
|
|
// calcolo l'intersezione tra la linea corrente e la superficie del grezzo per prolungare l'entrata
|
|
const double LINE_LEN = 1e5 ;
|
|
const double COS_SMALL = sin( EPS_ANG_SMALL * DEGTORAD) ;
|
|
ILSIVECTOR vInfo ;
|
|
if ( ! IntersLineSurfTm( ptGdStart, - vtGdDir, LINE_LEN, *pStmRaw, vInfo, true))
|
|
return false ;
|
|
Point3d ptNewStart = ptGdStart ;
|
|
// se esistono intersezioni, cerco la prima uscente dalla superficie
|
|
if ( ! vInfo.empty()) {
|
|
for ( int i = 0 ; i < ssize( vInfo) ; ++ i) {
|
|
// se c'è intersezione ed esco dalla superficie
|
|
if ( vInfo[i].nILTT != ILTT_NO && vInfo[i].dCosDN > COS_SMALL) {
|
|
ptNewStart = vInfo[i].ptI ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
// se non esistono intersezioni e il tipo di prolungamento non richiede il collegamento, devo solo verificare
|
|
// che non ci siano parti nel vuoto
|
|
else {
|
|
vInfo.clear() ;
|
|
if ( ! IntersLineSurfTm( ptGdStart, vtGdDir, LINE_LEN, *pStmRaw, vInfo, true))
|
|
return false ;
|
|
// se esistono intersezioni, cerco la prima entrante dalla superficie
|
|
if ( ! vInfo.empty()) {
|
|
for ( int i = 0 ; i < ssize( vInfo) ; ++ i) {
|
|
// se c'è intersezione ed entro dalla superficie
|
|
if ( vInfo[i].nILTT != ILTT_NO && vInfo[i].dCosDN < - COS_SMALL) {
|
|
ptNewStart = vInfo[i].ptI ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// calcolo l'interszione tra la linea corrente e la superficie del grezzo per prolungare l'uscita
|
|
if ( ! IntersLineSurfTm( ptGdEnd, vtGdDir, LINE_LEN, *pStmRaw, vInfo, true))
|
|
return false ;
|
|
Point3d ptNewEnd = ptGdEnd ;
|
|
// se esistono intersezioni, cerco la prima cerco la prima uscente dalla superficie
|
|
if ( ! vInfo.empty()) {
|
|
for ( int i = 0 ; i < ssize( vInfo) ; ++ i) {
|
|
// se c'è intersezione ed esco dalla superficie
|
|
if ( vInfo[i].nILTT != ILTT_NO) {
|
|
if ( vInfo[i].nILTT != ILTT_NO && vInfo[i].dCosDN > COS_SMALL) {
|
|
ptNewEnd = vInfo[i].ptI ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// se non esistono intersezioni e il tipo di collegamento non richiede allungamento devo solo verificare che
|
|
// non ci siano parti nel vuoto
|
|
else {
|
|
vInfo.clear() ;
|
|
if ( ! IntersLineSurfTm( ptGdEnd, - vtGdDir, LINE_LEN, *pStmRaw, vInfo, true))
|
|
return false ;
|
|
// se esitono intersezioni, cerco la prima entrante dalla superficie
|
|
if ( ! vInfo.empty()) {
|
|
for ( int i = 0 ; i < ssize( vInfo) ; ++ i) {
|
|
// se c'è intersezione ed entro dalla superficie
|
|
if ( vInfo[i].nILTT != ILTT_NO && vInfo[i].dCosDN < - COS_SMALL) {
|
|
ptNewEnd = vInfo[i].ptI ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// assegno i valori trovati
|
|
ptGdStart = ptNewStart ;
|
|
ptGdEnd = ptNewEnd ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalculateSectElevation( const Polygon3d& pgFacet, double& dElev) const
|
|
{
|
|
// verifico che il poligono sia valido
|
|
if ( ! pgFacet.IsValid())
|
|
return true ;
|
|
dElev = 0. ;
|
|
|
|
// inizializzo elevazioni per ogni grezzo
|
|
INTDBLVECTOR vRawElev ;
|
|
// ciclo sui grezzi della fase
|
|
int nRawId = m_pMchMgr->GetFirstRawPart() ;
|
|
while ( nRawId != GDB_ID_NULL) {
|
|
// verifico che il grezzo compaia nella fase
|
|
if ( m_pMchMgr->VerifyRawPartPhase( nRawId, m_nPhase)) {
|
|
// recupero la trimesh del grezzo
|
|
int nStmId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_SOLID) ;
|
|
const ISurfTriMesh* pStm = GetSurfTriMesh( m_pGeomDB->GetGeoObj( nStmId)) ;
|
|
if ( pStm != nullptr) {
|
|
// recupero il riferimento della trimesh
|
|
Frame3d frStm ;
|
|
m_pGeomDB->GetGlobFrame( nStmId, frStm) ;
|
|
// porto il poligono in questo riferimento
|
|
Polygon3d pgFacetL = pgFacet ;
|
|
pgFacetL.ToLoc( frStm) ;
|
|
// calcolo l'elevazione iniziale
|
|
double dCurrElev = 0. ;
|
|
if ( ! PolygonElevationInClosedSurfTm( pgFacetL, *pStm, true, dCurrElev))
|
|
return false ;
|
|
if ( dCurrElev > EPS_SMALL)
|
|
vRawElev.emplace_back( nStmId, dCurrElev) ;
|
|
}
|
|
}
|
|
// passo al grezzo successivo
|
|
nRawId = m_pMchMgr->GetNextRawPart( nRawId) ;
|
|
}
|
|
|
|
// se trovate elevazioni
|
|
if ( ! vRawElev.empty()) {
|
|
// ordino il vettore secondo l'elevazione crescente
|
|
sort( vRawElev.begin(), vRawElev.end(), []( const INTDBL& a, const INTDBL& b) { return a.second < b.second ; }) ;
|
|
// box dell'insieme delle posizioni utensile all'inizioe
|
|
const double MAX_DIST_RAW = 200.0 ;
|
|
BBox3d b3Tool ;
|
|
pgFacet.GetLocalBBox( b3Tool) ;
|
|
Vector3d vtDir = pgFacet.GetVersN() ;
|
|
b3Tool.Add( b3Tool.GetMin() + m_TParams.m_dLen * vtDir) ;
|
|
b3Tool.Add( b3Tool.GetMax() + m_TParams.m_dLen * vtDir) ;
|
|
if ( vtDir.IsX())
|
|
b3Tool.Expand( 0, m_TParams.m_dDiam / 2., m_TParams.m_dDiam / 2.) ;
|
|
else if ( vtDir.IsY())
|
|
b3Tool.Expand( m_TParams.m_dDiam / 2., 0., m_TParams.m_dDiam / 2.) ;
|
|
else if ( vtDir.IsZ())
|
|
b3Tool.Expand( m_TParams.m_dDiam / 2., m_TParams.m_dDiam / 2., 0.) ;
|
|
else {
|
|
double dExpandX = ( m_TParams.m_dDiam / 2.) * sqrt( 1. - vtDir.x * vtDir.x) ;
|
|
double dExpandY = ( m_TParams.m_dDiam / 2.) * sqrt( 1. - vtDir.y * vtDir.y) ;
|
|
double dExpandZ = ( m_TParams.m_dDiam / 2.) * sqrt( 1. - vtDir.z * vtDir.z) ;
|
|
b3Tool.Expand( dExpandX, dExpandY, dExpandZ) ;
|
|
}
|
|
b3Tool.Expand( MAX_DIST_RAW) ;
|
|
// verifico la reale interferenza dell'utensile con i diversi grezzi
|
|
for ( int i = 0 ; i < ssize( vRawElev) ; ++ i) {
|
|
// box del grezzo
|
|
BBox3d b3Raw ;
|
|
m_pGeomDB->GetGlobalBBox( vRawElev[i].first, b3Raw) ;
|
|
// confronto con il box dell'utensile nella posizione precedente
|
|
BBox3d b3CurrTool = b3Tool ;
|
|
b3CurrTool.Translate( dElev * vtDir) ;
|
|
if ( b3Raw.Overlaps( b3CurrTool))
|
|
dElev = vRawElev[i].second ;
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalculateGuideLine( int nGuideId, Point3d& ptGdStart, Point3d& ptGdEnd, Vector3d& vtGdDir,
|
|
int nSectGrpId, bool bExtendToRawBox) const
|
|
{
|
|
// recupero la linea guida
|
|
ICurve* pGuide = ::GetCurve( m_pGeomDB->GetGeoObj( nGuideId)) ;
|
|
if ( pGuide == nullptr)
|
|
return false ;
|
|
// recupero il suo riferimento
|
|
Frame3d frGdL ;
|
|
m_pGeomDB->GetGlobFrame( nGuideId, frGdL) ;
|
|
// porto la curva in globale (dovrebbe già avere riferimento globale)
|
|
pGuide->ToGlob( frGdL) ;
|
|
// recupero gli estremi della linea guida
|
|
pGuide->GetStartPoint( ptGdStart) ;
|
|
pGuide->GetEndPoint( ptGdEnd) ;
|
|
// recupero la direzione della linea guida
|
|
pGuide->GetStartDir( vtGdDir) ;
|
|
|
|
// se richiesta estensione lungo il Box
|
|
if ( bExtendToRawBox) {
|
|
// recupero le sezioni
|
|
ICURVEPVECTOR vpSects ;
|
|
int nSectId = m_pGeomDB->GetFirstInGroup( nSectGrpId) ;
|
|
while ( nSectId != GDB_ID_NULL) {
|
|
vpSects.emplace_back( ::GetCurve( m_pGeomDB->GetGeoObj( nSectId))) ;
|
|
if ( vpSects.back() == nullptr)
|
|
return false ;
|
|
nSectId = m_pGeomDB->GetNext( nSectId) ;
|
|
}
|
|
// per ogni sezione calcolo eventuale elevazione
|
|
double dMaxStartElev = 0., dMaxEndElev = 0. ;
|
|
for ( const ICurve* pCrvSect : vpSects) {
|
|
// applico offset radiale
|
|
OffsetCurve OffsCrv ;
|
|
OffsCrv.Make( pCrvSect, GetOffsR(), ICurve::OFF_FILLET) ;
|
|
PtrOwner<ICurve> pSectOffsR( OffsCrv.GetLongerCurve()) ;
|
|
if ( ! IsNull( pSectOffsR) && pSectOffsR->IsValid()) {
|
|
// porto la sezione in globale
|
|
Frame3d frSect ;
|
|
m_pGeomDB->GetGroupGlobFrame( nSectGrpId, frSect) ;
|
|
pSectOffsR->ToGlob( frSect) ;
|
|
// approssimo la curva con una polilinea che uso per creare il poligono equivalente
|
|
PolyLine PL ;
|
|
if ( ! pSectOffsR->ApproxWithLines( LIN_TOL_RAW, ANG_TOL_MAX_DEG, ICurve::APL_SPECIAL, PL))
|
|
return false ;
|
|
Polygon3d pgFacet ;
|
|
if ( ! pgFacet.FromPolyLine( PL))
|
|
return false ;
|
|
// calcolo l'estensione della guida fino alla proiezione in eccesso del grezzo
|
|
double dCurrStartElev = 0. ;
|
|
if ( ! CalculateSectElevation( pgFacet, dCurrStartElev))
|
|
return false ;
|
|
if ( dCurrStartElev > dMaxStartElev)
|
|
dMaxStartElev = dCurrStartElev ;
|
|
// calcolo l'estensione della guida fino alla proiezione in eccesso del grezzo
|
|
pgFacet.Translate( ptGdEnd - ptGdStart) ;
|
|
pgFacet.Invert() ;
|
|
double dCurrEndElev = 0. ;
|
|
if ( ! CalculateSectElevation( pgFacet, dCurrEndElev))
|
|
return false ;
|
|
if ( dCurrEndElev > dMaxEndElev)
|
|
dMaxEndElev = dCurrEndElev ;
|
|
}
|
|
}
|
|
// estendo la guida nel punto trovato
|
|
if ( dMaxEndElev > EPS_SMALL)
|
|
ptGdEnd += ( vtGdDir * dMaxEndElev) ;
|
|
if ( dMaxStartElev > EPS_SMALL)
|
|
ptGdStart -= ( vtGdDir * dMaxStartElev) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::ClassifySection( ICurve* pCrv, INTVECTOR& vnClass) const
|
|
{
|
|
const ICurveComposite* pCompo = GetCurveComposite( pCrv) ;
|
|
if ( pCompo != nullptr) {
|
|
const ICurve* pSimpCrv = pCompo->GetFirstCurve() ;
|
|
while ( pSimpCrv != nullptr) {
|
|
// analizzo la curva
|
|
Point3d ptStart, ptEnd ;
|
|
pSimpCrv->GetStartPoint( ptStart) ;
|
|
pSimpCrv->GetEndPoint( ptEnd) ;
|
|
if ( AreSamePointXYEpsilon( ptEnd, ptStart, 15 * EPS_SMALL))
|
|
vnClass.push_back( CCL_SMALL) ;
|
|
else if ( abs( ptEnd.x - ptStart.x) < EPS_SMALL)
|
|
vnClass.push_back( CCL_VERT) ;
|
|
else if ( abs( ptEnd.y - ptStart.y) < EPS_SMALL)
|
|
vnClass.push_back( CCL_FLAT) ;
|
|
else if ( ptEnd.y > ptStart.y)
|
|
vnClass.push_back( CCL_RISE) ;
|
|
else
|
|
vnClass.push_back( CCL_FALL) ;
|
|
// passo alla curva successiva
|
|
pSimpCrv = pCompo->GetNextCurve() ;
|
|
}
|
|
}
|
|
else {
|
|
Point3d ptStart, ptEnd ;
|
|
pCrv->GetStartPoint( ptStart) ;
|
|
pCrv->GetEndPoint( ptEnd) ;
|
|
if ( AreSamePointXYEpsilon( ptEnd, ptStart, 10 * EPS_SMALL))
|
|
vnClass.push_back( CCL_SMALL) ;
|
|
else if ( abs( ptEnd.x - ptStart.x) < EPS_SMALL)
|
|
vnClass.push_back( CCL_VERT) ;
|
|
else if ( abs( ptEnd.y - ptStart.y) < EPS_SMALL)
|
|
vnClass.push_back( CCL_FLAT) ;
|
|
else if ( ptEnd.y > ptStart.y)
|
|
vnClass.push_back( CCL_RISE) ;
|
|
else
|
|
vnClass.push_back( CCL_FALL) ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalcAlongVerticalCuts( ICurve* pSect, int nUmin, int nUmax, const Frame3d& frSect, bool bExtend,
|
|
const Point3d& ptGdStart, const Point3d& ptGdEnd, const Vector3d& vtGdDir, double dDepth,
|
|
double dRawMaxZ, const Vector3d& vtTool, const Vector3d& vtCorr, const ISurfTriMesh* pStmRaw)
|
|
{
|
|
// Ingombro del taglio
|
|
BBox3d b3Cut ;
|
|
for ( int i = nUmin ; i <= nUmax ; ++ i) {
|
|
Point3d ptP ;
|
|
if ( pSect->GetPointD1D2( i, ICurve::FROM_MINUS, ptP))
|
|
b3Cut.Add( ptP) ;
|
|
}
|
|
if ( b3Cut.IsEmpty())
|
|
return false ;
|
|
// ascissa
|
|
double dX = ( b3Cut.GetMin().x + b3Cut.GetMax().x) / 2 ;
|
|
// Calcolo dello step tra le passate
|
|
double dL = b3Cut.GetMax().y - b3Cut.GetMin().y ;
|
|
if ( dL < 10 * EPS_SMALL)
|
|
return true ;
|
|
double dStep = max( m_Params.m_dStep, 10 * EPS_SMALL) ;
|
|
int nStep = static_cast<int>( ceil( dL / dStep)) ;
|
|
dStep = dL / nStep ;
|
|
// Ciclo sulle passate
|
|
double dLastElev ;
|
|
Point3d ptStartPrev ;
|
|
for ( int i = 0 ; i <= nStep ; ++ i) {
|
|
// ordinata
|
|
double dY = b3Cut.GetMax().y - i * dStep ;
|
|
// estremi del taglio
|
|
Vector3d vtMove = dX * frSect.VersX() + dY * frSect.VersY() - 0.5 * m_TParams.m_dThick * vtTool ;
|
|
Point3d ptStart = ptGdStart + vtMove ;
|
|
Point3d ptEnd = ptGdEnd + vtMove ;
|
|
// verifico eventuale estensione degli estremi sul grezzo
|
|
if ( bExtend) {
|
|
if ( ! AdaptGuideLineToRaw( ptStart, ptEnd, vtGdDir, bExtend, pStmRaw))
|
|
return false ;
|
|
}
|
|
// determino l'elevazione del taglio
|
|
Vector3d vtThick = vtTool * m_TParams.m_dThick ;
|
|
double dElev, dElev2 ;
|
|
if ( ! GetElevation( m_nPhase, ptStart, ptEnd, vtCorr, dElev) ||
|
|
! GetElevation( m_nPhase, ptStart + vtThick, ptEnd + vtThick, vtCorr, dElev2) ) {
|
|
m_pMchMgr->SetLastError( 2708, "Error in SawFinishinging : GetElevation") ;
|
|
return false ;
|
|
}
|
|
dElev = max( dElev, dElev2) ;
|
|
if ( dElev < EPS_SMALL)
|
|
dElev = max( max( dRawMaxZ - ptStart.z, dRawMaxZ - ptEnd.z), 0.) ;
|
|
// la confronto con il massimo affondamento e con la massima lavorazione della lama
|
|
double dMaxDepth = min( dDepth, m_TParams.m_dMaxMat) ;
|
|
if ( dElev > dMaxDepth) {
|
|
ptStart += Vector3d( 0, 0, dElev - dMaxDepth) ;
|
|
ptEnd += Vector3d( 0, 0, dElev - dMaxDepth) ;
|
|
dElev = dMaxDepth ;
|
|
}
|
|
// se diverso da precedente, eseguo il taglio
|
|
bool bFirst = ( i == 0) ;
|
|
if ( bFirst || ! AreSamePointEpsilon( ptStart, ptStartPrev, 10 * EPS_SMALL)) {
|
|
if ( m_Params.m_nStepType != SAWFIN_ST_ZIGZAG) {
|
|
if ( ! CalcAlongOneWayCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, bExtend, true))
|
|
return false ;
|
|
}
|
|
else {
|
|
if ( ! CalcAlongZigZagCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, bExtend, true, bFirst))
|
|
return false ;
|
|
}
|
|
// salvo dati correnti
|
|
dLastElev = dElev ;
|
|
ptStartPrev = ptStart ;
|
|
}
|
|
}
|
|
// se ZigZag e non centrato aggiungo risalita
|
|
if ( m_Params.m_nStepType == SAWFIN_ST_ZIGZAG && m_Params.m_nLeadLinkType != SAWFIN_LL_CENT) {
|
|
// recupero distanza di sicurezza
|
|
double dSafeZ = GetSafeZ() ;
|
|
// lunghezza di approccio/retrazione
|
|
double dAppr = m_Params.m_dStartPos ;
|
|
// aggiungo retrazione
|
|
Point3d ptNewEnd ;
|
|
if ( ! GetCurrPos( ptNewEnd) || ! AddRetract( ptNewEnd, vtCorr, dSafeZ, dLastElev, dAppr))
|
|
return false ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalcAlongStdCuts( ICurve* pSect, double dUmin, double dUmax,
|
|
bool bSkipMin, bool bSkipMax, bool bInvert, const Frame3d& frSect, bool bExtend,
|
|
const Point3d& ptGdStart, const Point3d& ptGdEnd, const Vector3d& vtGdDir, double dDepth,
|
|
double dRawMaxZ, const Vector3d& vtTool, const Vector3d& vtCorr, const ISurfTriMesh* pStmRaw)
|
|
{
|
|
// Calcolo dello step tra le passate
|
|
double dStep = max( m_Params.m_dSideStep, 10 * EPS_SMALL) ;
|
|
double dLmin, dLmax ;
|
|
if ( ! pSect->GetLengthAtParam( dUmin, dLmin) || ! pSect->GetLengthAtParam( dUmax, dLmax))
|
|
return false ;
|
|
double dL = dLmax - dLmin - m_TParams.m_dThick ;
|
|
if ( dL < 10 * EPS_SMALL)
|
|
return true ;
|
|
int nStep = static_cast<int>( ceil( dL / dStep)) ;
|
|
dStep = dL / nStep ;
|
|
nStep ++ ;
|
|
// Ciclo sulle passate
|
|
double dLastElev ;
|
|
Point3d ptStartPrev ;
|
|
bool bSkipIni = ( bInvert ? bSkipMax : bSkipMin) ;
|
|
bool bSkipFin = ( bInvert ? bSkipMin : bSkipMax) ;
|
|
int nIni = ( bSkipIni ? 1 : 0) ;
|
|
int nFin = ( bSkipFin ? nStep - 1 : nStep) ;
|
|
if ( nFin < nIni)
|
|
return true ;
|
|
for ( int i = nIni ; i <= nFin ; ++ i) {
|
|
// calcolo del parametro
|
|
double dLcurr = ( bInvert ? dLmax - m_TParams.m_dThick - ( i - 1) * dStep : dLmin + m_TParams.m_dThick + ( i - 1) * dStep) ;
|
|
double dU ;
|
|
pSect->GetParamAtLength( dLcurr, dU) ;
|
|
// coordinate nel punto
|
|
Point3d ptP ;
|
|
pSect->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP) ;
|
|
// estremi del taglio
|
|
Vector3d vtMove = ptP.x * frSect.VersX() + ptP.y * frSect.VersY() - 0.5 * m_TParams.m_dThick * vtTool ;
|
|
Point3d ptStart = ptGdStart + vtMove ;
|
|
Point3d ptEnd = ptGdEnd + vtMove ;
|
|
// verifico eventuale estensione degli estremi sul grezzo
|
|
if ( bExtend) {
|
|
if ( ! AdaptGuideLineToRaw( ptStart, ptEnd, vtGdDir, bExtend, pStmRaw))
|
|
return false ;
|
|
}
|
|
// determino l'elevazione del taglio
|
|
Vector3d vtThick = vtTool * m_TParams.m_dThick ;
|
|
double dElev, dElev2 ;
|
|
if ( ! GetElevation( m_nPhase, ptStart, ptEnd, vtCorr, dElev) ||
|
|
! GetElevation( m_nPhase, ptStart + vtThick, ptEnd + vtThick, vtCorr, dElev2) ) {
|
|
m_pMchMgr->SetLastError( 2708, "Error in SawFinishing : GetElevation") ;
|
|
return false ;
|
|
}
|
|
dElev = max( dElev, dElev2) ;
|
|
if ( dElev < EPS_SMALL)
|
|
dElev = max( max( dRawMaxZ - ptStart.z, dRawMaxZ - ptEnd.z), 0.) ;
|
|
// la confronto con il massimo affondamento e con la massima lavorazione della lama
|
|
double dMaxDepth = min( dDepth, m_TParams.m_dMaxMat) ;
|
|
if ( dElev > dMaxDepth) {
|
|
ptStart += Vector3d( 0, 0, dElev - dMaxDepth) ;
|
|
ptEnd += Vector3d( 0, 0, dElev - dMaxDepth) ;
|
|
dElev = dMaxDepth ;
|
|
}
|
|
// se diverso da precedente, eseguo il taglio
|
|
bool bFirst = ( i == nIni) ;
|
|
if ( bFirst || ! AreSamePointEpsilon( ptStart, ptStartPrev, 10 * EPS_SMALL)) {
|
|
if ( m_Params.m_nStepType != SAWFIN_ST_ZIGZAG) {
|
|
if ( ! CalcAlongOneWayCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, bExtend, false))
|
|
return false ;
|
|
}
|
|
else {
|
|
if ( ! CalcAlongZigZagCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, bExtend, false, bFirst))
|
|
return false ;
|
|
}
|
|
// salvo dati correnti
|
|
dLastElev = dElev ;
|
|
ptStartPrev = ptStart ;
|
|
}
|
|
}
|
|
// se ZigZag e non centrato aggiungo risalita
|
|
if ( m_Params.m_nStepType == SAWFIN_ST_ZIGZAG && m_Params.m_nLeadLinkType != SAWFIN_LL_CENT) {
|
|
// recupero distanza di sicurezza
|
|
double dSafeZ = GetSafeZ() ;
|
|
// lunghezza di approccio/retrazione
|
|
double dAppr = m_Params.m_dStartPos ;
|
|
// aggiungo retrazione
|
|
Point3d ptNewEnd ;
|
|
if ( ! GetCurrPos( ptNewEnd) || ! AddRetract( ptNewEnd, vtCorr, dSafeZ, dLastElev, dAppr))
|
|
return false ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalcCAvSect5Ax( const ICurveComposite* pSubSect, const SECTIONVECTOR& vSections, const Vector3d& vtTool, const Vector3d& vtCorr,
|
|
const Point3d& ptP, double& dElev, bool& bOtherCollision) const
|
|
{
|
|
// verifico la validità della curva
|
|
if ( pSubSect == nullptr || ! pSubSect->IsValid())
|
|
return false ;
|
|
bOtherCollision = false ;
|
|
|
|
// definisco il numero di punti di campionamento progressivi
|
|
const int MAX_NUM = 3 ;
|
|
const double LINE_LEN = 1e4 ;
|
|
double dSqMaxElev = EPS_ZERO ;
|
|
PtrOwner<ICurveLine> pLineInters( CreateCurveLine()) ;
|
|
if ( IsNull( pLineInters) || ! pLineInters->Set( ptP, ptP + vtCorr * LINE_LEN))
|
|
return false ;
|
|
for ( int i = 0 ; i < MAX_NUM ; ++ i) {
|
|
if ( i > 0)
|
|
pLineInters->Translate( ( m_TParams.m_dThick) / ( MAX_NUM - 1) * vtTool) ;
|
|
Point3d ptLineS ; pLineInters->GetStartPoint( ptLineS) ;
|
|
IntersCurveCurve ICC( *pLineInters, *pSubSect) ;
|
|
for ( int j = ICC.GetIntersCount() - 1 ; j >= 0 ; -- j) {
|
|
IntCrvCrvInfo aInfo ;
|
|
if ( ICC.GetIntCrvCrvInfo( j, aInfo))
|
|
dSqMaxElev = max( dSqMaxElev, ( SqDist( ptLineS, ( aInfo.bOverlap ? aInfo.IciA[1].ptI : aInfo.IciA[0].ptI)))) ;
|
|
}
|
|
|
|
// controllo se la linea ricavata interseca le sezioni presenti
|
|
double dSafeShift = 1. + sqrt( dSqMaxElev) ;
|
|
pLineInters->Translate( dSafeShift * vtCorr) ;
|
|
for ( int j = 0 ; j < ssize( vSections) ; ++ j) {
|
|
if ( vSections[j].pSection != nullptr && vSections[j].pSection->IsValid()) {
|
|
IntersCurveCurve ICC( *pLineInters, *vSections[j].pSection) ;
|
|
if ( ICC.GetIntersCount() > 0) {
|
|
bOtherCollision = true ;
|
|
return true ;
|
|
}
|
|
}
|
|
}
|
|
pLineInters->Translate( - dSafeShift * vtCorr) ; // ritorno in posizione originale
|
|
}
|
|
|
|
dElev = sqrt( dSqMaxElev) ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalcAlong5ACuts( const SECTIONVECTOR& vSections, const Frame3d& frSect, bool bExtend,
|
|
const Point3d& ptGdStart, const Point3d& ptGdEnd, const Vector3d& vtGdDir, double dDepth,
|
|
const BBox3d& b3Raw, const ISurfTriMesh* pStmRaw)
|
|
{
|
|
// se non ho sezioni da lavorare, non faccio nulla
|
|
if ( vSections.empty()) {
|
|
m_pMchMgr->SetWarning( 2752, "Warning in SawFinishing : No machinable path") ;
|
|
return true ;
|
|
}
|
|
|
|
// determino angolo limite di inclinazione dell'utensile
|
|
double dAngDegSplit = 60. ;
|
|
double dAngUN = 0. ;
|
|
if ( GetValInNotes( m_Params.m_sUserNotes, UN_LIMIT_ANG, dAngUN))
|
|
dAngDegSplit = max( 15. - EPS_ANG_SMALL, dAngUN) ;
|
|
double dCosToolLimit = cos( dAngDegSplit * DEGTORAD) ;
|
|
|
|
// determino quota Zmassima dal Box del grezzo in globale
|
|
double dRawMaxZ = b3Raw.GetMax().z ;
|
|
|
|
// scorro le sezioni
|
|
for ( int nSect = 0 ; nSect < ssize( vSections) ; ++ nSect) {
|
|
|
|
// recupero la sezione
|
|
const SectionInfo& Section = vSections[nSect] ;
|
|
if ( Section.pSection == nullptr || ! Section.pSection->IsValid())
|
|
continue ;
|
|
|
|
// scorro le SubSection ottenute
|
|
for ( int nSubSect = 0 ; nSubSect < ssize( Section.vSubSections) ; ++ nSubSect) {
|
|
|
|
// recupero la SubSection corrente, se non valida, passo alla successiva
|
|
const SubSectionInfo& SubSection = Section.vSubSections[nSubSect] ;
|
|
PtrOwner<ICurveComposite> pSubSect( CloneCurveComposite( SubSection.pSubSection)) ;
|
|
if ( pSubSect == nullptr || ! pSubSect->IsValid())
|
|
continue ;
|
|
// essendo l'utensile inclinato e la testa con orientamento forzato è meglio estendere la sezione per evitare lavorazioni
|
|
// a filo dei suoi bordi
|
|
pSubSect->ExtendStartByLen( 50. * EPS_SMALL) ;
|
|
pSubSect->ExtendEndByLen( 50. * EPS_SMALL) ;
|
|
|
|
// calcolo della lunghezza dello step e del numero di step complessivi
|
|
double dStep = max( m_Params.m_dSideStep, 10. * EPS_SMALL) ;
|
|
double dLen ;
|
|
if ( ! pSubSect->GetLength( dLen))
|
|
return false ;
|
|
double dL = dLen ;
|
|
if ( dL < 10. * EPS_SMALL)
|
|
return true ;
|
|
int nStep = static_cast<int>( ceil( dL / dStep)) ;
|
|
dStep = dL / nStep ;
|
|
nStep ++ ;
|
|
|
|
// Ciclo sulle passate
|
|
double dLastElev ;
|
|
Point3d ptStartPrev ;
|
|
for ( int i = 0 ; i <= nStep ; ++ i) {
|
|
// coordinate nel punto, del versore correzione e del versore utensile
|
|
double dLcurr = i * dStep ;
|
|
double dU ; pSubSect->GetParamAtLength( dLcurr, dU) ;
|
|
Point3d ptP ;
|
|
Vector3d vtTan, vtPerp ;
|
|
if ( ! pSubSect->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP, &vtTan) || ! vtTan.Normalize())
|
|
return false ;
|
|
Vector3d vtCorr = GetToGlob( vtTan, frSect) ;
|
|
vtCorr.Rotate( vtGdDir, m_Params.m_bInvert ? - ANG_RIGHT : ANG_RIGHT) ;
|
|
Vector3d vtTool = GetToGlob( vtTan, frSect) ;
|
|
// determino la posizione della testa
|
|
if ( vtTool.z < - EPS_ZERO)
|
|
vtTool.Invert() ; // NB. vtTool deve sempre avere la componente Z come positiva
|
|
|
|
// se lama più inclinata della soglia, passo allo step successivo
|
|
if ( vtCorr * Z_AX < dCosToolLimit)
|
|
continue ;
|
|
|
|
// verifico posizionando la lama nel punto corrente se devo sposarmi per evitare collisione con la sezione
|
|
double dSectElev = 0. ;
|
|
bool bOtherColl = false ;
|
|
if ( ! CalcCAvSect5Ax( pSubSect, vSections, GetToLoc( vtTool, frSect), GetToLoc( vtCorr, frSect), ptP, dSectElev, bOtherColl)) {
|
|
m_pMchMgr->SetLastError( 2708, "Error in SawFinishing : GetElevation") ;
|
|
return false ;
|
|
}
|
|
// se collisione con altra sezione, passo allo step successivo ( non inserisco la passata corrente)
|
|
if ( bOtherColl)
|
|
continue ;
|
|
|
|
// definisco gli estremi del tratto rettilineo in globale
|
|
Point3d ptPCAvSect = GetToGlob( ptP, frSect) + vtCorr * dSectElev ;
|
|
if ( m_Params.m_bInvert)
|
|
ptPCAvSect.Translate( - vtGdDir * Dist( ptGdStart, ptGdEnd)) ;
|
|
Point3d ptStart = ptPCAvSect ;
|
|
Point3d ptEnd = ptPCAvSect + vtGdDir * ( Dist( ptGdStart, ptGdEnd)) ;
|
|
|
|
// verifico eventuale estensione degli estremi sul grezzo
|
|
if ( bExtend) {
|
|
if ( ! AdaptGuideLineToRaw( ptStart, ptEnd, vtGdDir, bExtend, pStmRaw))
|
|
return false ;
|
|
}
|
|
|
|
// determino l'elevazione del taglio (considerando l'elevazione verticiale)
|
|
Vector3d vtThick = vtTool * m_TParams.m_dThick ;
|
|
double dElev, dElev2 ;
|
|
if ( ! GetElevation( m_nPhase, ptStart, ptEnd, Z_AX, dElev) ||
|
|
! GetElevation( m_nPhase, ptStart + vtThick, ptEnd + vtThick, Z_AX, dElev2)) {
|
|
m_pMchMgr->SetLastError( 2708, "Error in SawFinishing : GetElevation") ;
|
|
return false ;
|
|
}
|
|
dElev = max( dElev, dElev2) ;
|
|
if ( dElev < EPS_SMALL)
|
|
dElev = max( max( dRawMaxZ - ptStart.z, dRawMaxZ - ptEnd.z), 0.) ;
|
|
// la confronto con il massimo affondamento e con la massima lavorazione della lama. Se sotto alla massima Depth allora riporto
|
|
// l'utensile in verticale e ricalcolo il punto più adatto in z per il tratto lineare
|
|
double dMaxDepth = min( dDepth, m_TParams.m_dMaxMat) ;
|
|
if ( dElev > dMaxDepth) {
|
|
// modifica versore correzione e direzione utensile
|
|
vtTool.z = 0. ;
|
|
if ( ! vtTool.Normalize())
|
|
return false ;
|
|
vtCorr = Z_AX ;
|
|
double dElevTmp = 0. ;
|
|
if ( ! CalcCAvSect5Ax( pSubSect, vSections, GetToLoc( vtTool, frSect), GetToLoc( vtCorr, frSect), ptP, dElevTmp, bOtherColl)) {
|
|
m_pMchMgr->SetLastError( 2708, "Error in SawFinishing : GetElevation") ;
|
|
return false ;
|
|
}
|
|
if ( bOtherColl)
|
|
continue ;
|
|
ptPCAvSect = GetToGlob( ptP, frSect) + vtCorr * dElevTmp ;
|
|
double dElev3 ;
|
|
if ( ! GetElevation( m_nPhase, ptPCAvSect, vtTool, m_TParams.m_dDiam / 2., m_TParams.m_dLen, vtCorr, dElev3)) {
|
|
m_pMchMgr->SetLastError( 2708, "Error in SawFinishing : GetElevation") ;
|
|
return false ;
|
|
}
|
|
Point3d ptPTopRaw = ptPCAvSect + ( dElev3 - m_TParams.m_dDiam / 2.) * vtCorr ;
|
|
ptStart.z = max( ptPTopRaw.z - dMaxDepth, ptPCAvSect.z) ;
|
|
ptEnd.z = max( ptPTopRaw.z - dMaxDepth, ptPCAvSect.z) ;
|
|
dElev = dMaxDepth ;
|
|
}
|
|
|
|
// Imposto dati comune
|
|
SetToolDir( vtTool) ;
|
|
SetCorrAuxDir( vtCorr) ;
|
|
// se diverso da precedente, eseguo il taglio
|
|
bool bFirst = ( i == 0) ;
|
|
dElev = dElev / max( EPS_SMALL, ( vtCorr * Z_AX)) ; // non serve fare il max, ma meglio prevenire...
|
|
if ( bFirst || ! AreSamePointEpsilon( ptStart, ptStartPrev, 10. * EPS_SMALL)) {
|
|
if ( m_Params.m_nStepType != SAWFIN_ST_ZIGZAG) {
|
|
if ( ! CalcAlongOneWayCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, bExtend, false))
|
|
return false ;
|
|
}
|
|
else {
|
|
if ( ! CalcAlongZigZagCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, bExtend, false, bFirst))
|
|
return false ;
|
|
}
|
|
// salvo dati correnti
|
|
dLastElev = dElev ;
|
|
ptStartPrev = ptStart ;
|
|
}
|
|
}
|
|
// se ZigZag e non centrato aggiungo risalita
|
|
if ( m_Params.m_nStepType == SAWFIN_ST_ZIGZAG && m_Params.m_nLeadLinkType != SAWFIN_LL_CENT) {
|
|
// recupero distanza di sicurezza
|
|
double dSafeZ = GetSafeZ() ;
|
|
// lunghezza di approccio/retrazione
|
|
double dAppr = m_Params.m_dStartPos ;
|
|
// aggiungo retrazione
|
|
Point3d ptNewEnd ;
|
|
if ( ! GetCurrPos( ptNewEnd) || ! AddRetract( ptNewEnd, Z_AX, dSafeZ, dLastElev, dAppr))
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalcAlongOneWayCut( const Point3d& ptStart, const Point3d& ptEnd, const Vector3d& vtDir,
|
|
const Vector3d& vtTool, const Vector3d& vtCorr, double dElev, bool bExtend, bool bVert)
|
|
{
|
|
// recupero distanza di sicurezza
|
|
double dSafeZ = GetSafeZ() ;
|
|
// lunghezza di approccio/retrazione
|
|
double dAlongAppr = ( bExtend ? m_Params.m_dStartPos : 0) ;
|
|
double dAppr = m_Params.m_dStartPos ;
|
|
|
|
// se attacco/uscita/collegamento esterno allungo inizio
|
|
Point3d ptNewStart = ptStart ;
|
|
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_STD) {
|
|
ptNewStart = ptStart - vtDir * dAlongAppr ;
|
|
}
|
|
else if ( m_Params.m_nLeadLinkType == SAWFIN_LL_OUT) {
|
|
// distanza XY tra centro e bordo taglio
|
|
double dDeltaT = 0 ;
|
|
if ( dElev > 0.0 && dElev < 0.5 * m_TParams.m_dDiam)
|
|
dDeltaT = sqrt( dElev * m_TParams.m_dDiam - dElev * dElev) ;
|
|
// modifico inizio
|
|
ptNewStart = ptStart - vtDir * ( dDeltaT + dAlongAppr) ;
|
|
}
|
|
|
|
// Sempre una sola passata
|
|
// 1 -> approccio
|
|
if ( ! AddApproach( ptNewStart, vtCorr, dSafeZ, dElev, dAppr))
|
|
return false ;
|
|
// 2 -> movimento in affondo al punto iniziale
|
|
SetFlag( 0) ;
|
|
if ( m_Params.m_nLeadLinkType != SAWFIN_LL_OUT)
|
|
SetFeed( GetTipFeed()) ;
|
|
else
|
|
SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ;
|
|
if ( AddLinearMove( ptNewStart) == GDB_ID_NULL)
|
|
return false ;
|
|
// 3 -> movimento di lato al punto finale
|
|
SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ;
|
|
if ( AddLinearMove( ptEnd) == GDB_ID_NULL)
|
|
return false ;
|
|
// 4 -> retrazione
|
|
if ( ! AddRetract( ptEnd, vtCorr, dSafeZ, dElev, dAppr))
|
|
return false ;
|
|
// incremento contatore passate
|
|
++ m_nCuts ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalcAlongZigZagCut( const Point3d& ptStart, const Point3d& ptEnd, const Vector3d& vtDir,
|
|
const Vector3d& vtTool, const Vector3d& vtCorr, double dElev, bool bExtend, bool bVert, bool bFirst)
|
|
{
|
|
// recupero distanza di sicurezza
|
|
double dSafeZ = GetSafeZ() ;
|
|
// lunghezza di approccio/retrazione
|
|
double dAlongAppr = ( bExtend ? m_Params.m_dStartPos : 0) ;
|
|
double dAppr = m_Params.m_dStartPos ;
|
|
|
|
// aggiorno inizio, fine e direzione movimento
|
|
Point3d ptOriStart = ptStart ;
|
|
Point3d ptOriEnd = ptEnd ;
|
|
Point3d ptNewStart = ptStart ;
|
|
Point3d ptNewEnd = ptEnd ;
|
|
Vector3d vtNewDir = vtDir ;
|
|
// se attacco/uscita/collegamento standard allungo inizio e fine dell'approccio
|
|
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_STD) {
|
|
// modifico inizio
|
|
ptNewStart = ptStart - vtDir * dAlongAppr ;
|
|
// modifico fine
|
|
ptNewEnd = ptEnd + vtDir * dAlongAppr ;
|
|
}
|
|
// se attacco/uscita/collegamento esterno allungo inizio e fine a fuori grezzo
|
|
else if ( m_Params.m_nLeadLinkType == SAWFIN_LL_OUT) {
|
|
// distanza XY tra centro e bordo taglio
|
|
double dDeltaT = 0 ;
|
|
if ( dElev > 0.0 && dElev < 0.5 * m_TParams.m_dDiam)
|
|
dDeltaT = sqrt( dElev * m_TParams.m_dDiam - dElev * dElev) ;
|
|
// modifico inizio
|
|
ptNewStart = ptStart - vtDir * ( dDeltaT + dAlongAppr) ;
|
|
// modifico fine
|
|
ptNewEnd = ptEnd + vtDir * ( dDeltaT + dAlongAppr) ;
|
|
}
|
|
// le passate dispari sono al contrario
|
|
if ( ( m_nCuts % 2) != 0) {
|
|
swap( ptOriStart, ptOriEnd) ;
|
|
swap( ptNewStart, ptNewEnd) ;
|
|
vtNewDir.Invert() ;
|
|
}
|
|
|
|
// Sempre una sola passata
|
|
// 1 -> approccio
|
|
if ( bFirst || m_Params.m_nLeadLinkType == SAWFIN_LL_CENT) {
|
|
if ( ! AddApproach( ptNewStart, vtCorr, dSafeZ, dElev, dAppr))
|
|
return false ;
|
|
}
|
|
// 2 -> movimento in affondo al punto iniziale
|
|
SetFlag( 0) ;
|
|
// con attacco centrato sono sul materiale e devo usare feed di testa
|
|
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_CENT) {
|
|
SetFeed( GetTipFeed()) ;
|
|
if ( AddLinearMove( ptNewStart) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// con attacco fuori sono in aria
|
|
else {
|
|
if ( bFirst) {
|
|
SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ;
|
|
if ( AddLinearMove( ptNewStart) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
else {
|
|
Point3d ptLast ;
|
|
GetCurrPos( ptLast) ;
|
|
double dDiff = ( ptNewStart - ptLast) * vtNewDir ;
|
|
// se precedente e corrente sono fuori allo stesso modo
|
|
if ( abs( dDiff) < 10 * EPS_SMALL) {
|
|
// inizio nuova passata
|
|
SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ;
|
|
if ( AddLinearMove( ptNewStart) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// se il precedente è più fuori
|
|
else if ( dDiff > 0) {
|
|
// allungo nuova passata
|
|
SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ;
|
|
if ( AddLinearMove( ptNewStart - dDiff * vtNewDir) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// se il corrente è più fuori
|
|
else {
|
|
// allungo passata precedente
|
|
if ( AddLinearMove( ptLast + dDiff * vtNewDir) == GDB_ID_NULL)
|
|
return false ;
|
|
// inizio nuova passata
|
|
SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ;
|
|
if ( AddLinearMove( ptNewStart) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
// 3 -> movimento di lato al punto finale
|
|
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_CENT) {
|
|
SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ;
|
|
if ( AddLinearMove( ptNewEnd) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
else {
|
|
SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ;
|
|
if ( AddLinearMove( ptOriEnd) == GDB_ID_NULL)
|
|
return false ;
|
|
SetFeed( GetEndFeed()) ;
|
|
if ( ! AreSamePointApprox( ptNewEnd, ptOriEnd) && AddLinearMove( ptNewEnd) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// 4 -> retrazione
|
|
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_CENT) {
|
|
if ( ! AddRetract( ptNewEnd, vtCorr, dSafeZ, dElev, dAppr))
|
|
return false ;
|
|
}
|
|
// incremento contatore passate
|
|
++ m_nCuts ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalcAcrossOneWayCut( const PolyLine& PL, const Vector3d& vtMove,
|
|
const Vector3d& vtTool, const Vector3d& vtCorr, double dRawZ, double dDepth)
|
|
{
|
|
// recupero distanza di sicurezza
|
|
double dSafeZ = GetSafeZ() ;
|
|
// lunghezza di approccio/retrazione
|
|
double dAppr = m_Params.m_dStartPos ;
|
|
|
|
Point3d ptP ;
|
|
// 1 -> approccio
|
|
bool bFound = PL.GetFirstPoint( ptP) ;
|
|
if ( bFound) {
|
|
ptP += vtMove - 0.5 * m_TParams.m_dThick * vtTool ;
|
|
ptP.z = max( ptP.z, dRawZ - dDepth) ;
|
|
double dElev = dRawZ - ptP.z ;
|
|
if ( ! AddApproach( ptP, vtCorr, dSafeZ, dElev, dAppr))
|
|
return false ;
|
|
}
|
|
// 2 -> movimento lungo la sezione
|
|
Point3d ptPrev ;
|
|
GetCurrPos( ptPrev) ;
|
|
while ( bFound) {
|
|
// se diverso da precedente, movimento al punto
|
|
if ( ! AreSamePointEpsilon( ptP, ptPrev, 10 * EPS_SMALL)) {
|
|
Vector3d vtDelta = ptP - ptPrev ;
|
|
if ( vtDelta.z > - EPS_SMALL)
|
|
SetFeed( GetFeed()) ;
|
|
else {
|
|
double dC = sqrt( 1 + ( vtDelta.x * vtDelta.x + vtDelta.y * vtDelta.y) / ( vtDelta.z * vtDelta.z)) ;
|
|
double dF = min( GetFeed(), dC * GetTipFeed()) ;
|
|
SetFeed( dF) ;
|
|
}
|
|
if ( AddLinearMove( ptP) == GDB_ID_NULL)
|
|
return false ;
|
|
ptPrev = ptP ;
|
|
}
|
|
// recupero punto successivo
|
|
bFound = PL.GetNextPoint( ptP) ;
|
|
if ( bFound) {
|
|
ptP += vtMove - 0.5 * m_TParams.m_dThick * vtTool ;
|
|
ptP.z = max( ptP.z, dRawZ - dDepth) ;
|
|
}
|
|
}
|
|
// 3-> retrazione
|
|
{
|
|
double dElev = dRawZ - ptP.z ;
|
|
if ( ! AddRetract( ptP, vtCorr, dSafeZ, dElev, dAppr))
|
|
return false ;
|
|
}
|
|
// incremento contatore passate
|
|
++ m_nCuts ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalcAcrossZigZagCut( const PolyLine& PL, const Vector3d& vtMove,
|
|
const Vector3d& vtTool, const Vector3d& vtCorr, double dRawZ, double dDepth, bool bFirst)
|
|
{
|
|
// recupero distanza di sicurezza
|
|
double dSafeZ = GetSafeZ() ;
|
|
// lunghezza di approccio/retrazione
|
|
double dAppr = m_Params.m_dStartPos ;
|
|
|
|
// sezione da invertire
|
|
bool bInvert = (( m_nCuts % 2) != 0) ;
|
|
|
|
Point3d ptP ;
|
|
bool bFound = ( bInvert ? PL.GetLastPoint( ptP) : PL.GetFirstPoint( ptP)) ;
|
|
// 1 -> approccio
|
|
if ( bFound) {
|
|
ptP += vtMove - 0.5 * m_TParams.m_dThick * vtTool ;
|
|
ptP.z = max( ptP.z, dRawZ - dDepth) ;
|
|
if ( bFirst) {
|
|
double dElev = dRawZ - ptP.z ;
|
|
if ( ! AddApproach( ptP, vtCorr, dSafeZ, dElev, dAppr))
|
|
return false ;
|
|
}
|
|
}
|
|
// 2 -> movimento lungo la sezione
|
|
Point3d ptPrev ;
|
|
GetCurrPos( ptPrev) ;
|
|
while ( bFound) {
|
|
// se diverso da precedente, movimento al punto
|
|
if ( ! AreSamePointEpsilon( ptP, ptPrev, 10 * EPS_SMALL)) {
|
|
Vector3d vtDelta = ptP - ptPrev ;
|
|
if ( vtDelta.z > - EPS_SMALL)
|
|
SetFeed( GetFeed()) ;
|
|
else {
|
|
double dC = sqrt( 1 + ( vtDelta.x * vtDelta.x + vtDelta.y * vtDelta.y) / ( vtDelta.z * vtDelta.z)) ;
|
|
double dF = min( GetFeed(), dC * GetTipFeed()) ;
|
|
SetFeed( dF) ;
|
|
}
|
|
if ( AddLinearMove( ptP) == GDB_ID_NULL)
|
|
return false ;
|
|
ptPrev = ptP ;
|
|
}
|
|
// recupero punto successivo
|
|
bFound = ( bInvert ? PL.GetPrevPoint( ptP) : PL.GetNextPoint( ptP)) ;
|
|
if ( bFound) {
|
|
ptP += vtMove - 0.5 * m_TParams.m_dThick * vtTool ;
|
|
ptP.z = max( ptP.z, dRawZ - dDepth) ;
|
|
}
|
|
}
|
|
// incremento contatore passate
|
|
++ m_nCuts ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalcCurvedAlongVerticalCuts( ICurve* pSect, int nUmin, int nUmax, const Frame3d& frSect,
|
|
ICurve* pGuide, double dDepth, double dRawMaxZ, const Vector3d& vtTool)
|
|
{
|
|
// Ingombro del taglio
|
|
BBox3d b3Cut ;
|
|
for ( int i = nUmin ; i <= nUmax ; ++ i) {
|
|
Point3d ptP ;
|
|
if ( pSect->GetPointD1D2( i, ICurve::FROM_MINUS, ptP))
|
|
b3Cut.Add( ptP) ;
|
|
}
|
|
if ( b3Cut.IsEmpty())
|
|
return false ;
|
|
// ordinata
|
|
double dY = ( b3Cut.GetMin().y + b3Cut.GetMax().y) / 2 ;
|
|
// Calcolo dello step tra le passate
|
|
double dL = b3Cut.GetMax().x - b3Cut.GetMin().x ;
|
|
if ( dL < 10 * EPS_SMALL)
|
|
return true ;
|
|
double dStep = max( m_Params.m_dStep, 10 * EPS_SMALL) ;
|
|
int nStep = static_cast<int>( ceil( dL / dStep)) ;
|
|
dStep = dL / nStep ;
|
|
// Ciclo sulle passate
|
|
double dLastElev ;
|
|
Point3d ptStartPrev ;
|
|
for ( int i = 0 ; i <= nStep ; ++ i) {
|
|
// ascissa
|
|
double dX = b3Cut.GetMax().x - i * dStep ;
|
|
// creo la curva di taglio
|
|
double dOffs = dX ;
|
|
Vector3d vtMove = ( dY - m_TParams.m_dThick / 2) * Z_AX ;
|
|
OffsetCurve OffsCrv ;
|
|
OffsCrv.Make( pGuide, dOffs, ICurve::OFF_FILLET) ;
|
|
PtrOwner<ICurveComposite> pCut ;
|
|
if ( ! pCut.Set( ConvertCurveToComposite( OffsCrv.GetLongerCurve())))
|
|
return false ;
|
|
VerifyArcs( pCut) ;
|
|
pCut->SimpleOffset( SAWRF_OFFS, ICurve::OFF_FORCE_OPEN) ;
|
|
pCut->Translate( vtMove) ;
|
|
Point3d ptStart ; pCut->GetStartPoint( ptStart) ;
|
|
// se diverso da precedente, eseguo il taglio
|
|
bool bFirst = ( i == 0) ;
|
|
if ( bFirst || ! AreSamePointEpsilon( ptStart, ptStartPrev, 10 * EPS_SMALL)) {
|
|
if ( m_Params.m_nStepType != SAWFIN_ST_ZIGZAG) {
|
|
//if ( ! CalcAlongOneWayCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, true))
|
|
// return false ;
|
|
}
|
|
else {
|
|
if ( ! CalcCurvedAlongZigZagCut( pCut, vtTool, true, bFirst, dLastElev))
|
|
return false ;
|
|
}
|
|
}
|
|
ptStartPrev = ptStart ;
|
|
}
|
|
// se ZigZag e non centrato aggiungo risalita
|
|
if ( m_Params.m_nStepType == SAWFIN_ST_ZIGZAG && m_Params.m_nLeadLinkType != SAWFIN_LL_CENT) {
|
|
// recupero distanza di sicurezza
|
|
double dSafeZ = GetSafeZ() ;
|
|
// lunghezza di approccio/retrazione
|
|
double dAppr = m_Params.m_dStartPos ;
|
|
// aggiungo retrazione
|
|
Point3d ptNewEnd ;
|
|
Vector3d vtNewCorr ;
|
|
if ( ! GetCurrPos( ptNewEnd) || ! GetCurrCorr( vtNewCorr) || ! AddRetract( ptNewEnd, vtNewCorr, dSafeZ, dLastElev, dAppr))
|
|
return false ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalcCurvedAlongStdCuts( ICurve* pSect, double dUmin, double dUmax,
|
|
bool bSkipMin, bool bSkipMax, bool bInvert, const Frame3d& frSect,
|
|
ICurve* pGuide, double dDepth, double dRawMaxZ, const Vector3d& vtTool)
|
|
{
|
|
// Calcolo dello step tra le passate
|
|
double dStep = max( m_Params.m_dSideStep, 10 * EPS_SMALL) ;
|
|
double dLmin, dLmax ;
|
|
if ( ! pSect->GetLengthAtParam( dUmin, dLmin) || ! pSect->GetLengthAtParam( dUmax, dLmax))
|
|
return false ;
|
|
double dL = dLmax - dLmin ;
|
|
if ( dL < 10 * EPS_SMALL)
|
|
return true ;
|
|
int nStep = static_cast<int>( ceil( dL / dStep)) ;
|
|
dStep = dL / nStep ;
|
|
// Ciclo sulle passate
|
|
double dLastElev ;
|
|
Point3d ptStartPrev ;
|
|
bool bSkipIni = ( bInvert ? bSkipMax : bSkipMin) ;
|
|
bool bSkipFin = ( bInvert ? bSkipMin : bSkipMax) ;
|
|
int nIni = ( bSkipIni ? 1 : 0) ;
|
|
int nFin = ( bSkipFin ? nStep - 1 : nStep) ;
|
|
if ( nFin < nIni)
|
|
return true ;
|
|
for ( int i = nIni ; i <= nFin ; ++ i) {
|
|
// calcolo del parametro
|
|
double dLcurr = ( bInvert ? dLmax - i * dStep : dLmin + i * dStep) ;
|
|
double dU ;
|
|
pSect->GetParamAtLength( dLcurr, dU) ;
|
|
// coordinate nel punto
|
|
Point3d ptP ;
|
|
pSect->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP) ;
|
|
// creo la curva di taglio
|
|
double dOffs = ptP.x ;
|
|
Vector3d vtMove = ( ptP.y - m_TParams.m_dThick / 2) * Z_AX ;
|
|
OffsetCurve OffsCrv ;
|
|
OffsCrv.Make( pGuide, dOffs, ICurve::OFF_FILLET) ;
|
|
PtrOwner<ICurveComposite> pCut ;
|
|
if ( ! pCut.Set( ConvertCurveToComposite( OffsCrv.GetLongerCurve())))
|
|
return false ;
|
|
VerifyArcs( pCut) ;
|
|
pCut->SimpleOffset( SAWRF_OFFS, ICurve::OFF_FORCE_OPEN) ;
|
|
pCut->Translate( vtMove) ;
|
|
Point3d ptStart ; pCut->GetStartPoint( ptStart) ;
|
|
// se diverso da precedente, eseguo il taglio
|
|
bool bFirst = ( i == nIni) ;
|
|
if ( bFirst || ! AreSamePointEpsilon( ptStart, ptStartPrev, 10 * EPS_SMALL)) {
|
|
if ( m_Params.m_nStepType != SAWFIN_ST_ZIGZAG) {
|
|
//if ( ! CalcAlongOneWayCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, false))
|
|
// return false ;
|
|
}
|
|
else {
|
|
if ( ! CalcCurvedAlongZigZagCut( Get( pCut), vtTool, false, bFirst, dLastElev))
|
|
return false ;
|
|
}
|
|
ptStartPrev = ptStart ;
|
|
}
|
|
}
|
|
// se ZigZag e non centrato aggiungo risalita
|
|
if ( m_Params.m_nStepType == SAWFIN_ST_ZIGZAG && m_Params.m_nLeadLinkType != SAWFIN_LL_CENT) {
|
|
// recupero distanza di sicurezza
|
|
double dSafeZ = GetSafeZ() ;
|
|
// lunghezza di approccio/retrazione
|
|
double dAppr = m_Params.m_dStartPos ;
|
|
// aggiungo retrazione
|
|
Point3d ptNewEnd ;
|
|
Vector3d vtNewCorr ;
|
|
if ( ! GetCurrPos( ptNewEnd) || ! GetCurrCorr( vtNewCorr) || ! AddRetract( ptNewEnd, vtNewCorr, dSafeZ, dLastElev, dAppr))
|
|
return false ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalcCurvedAlongZigZagCut( const ICurve* pCut, const Vector3d& vtTool, bool bVert, bool bFirst, double& dEndElev)
|
|
{
|
|
// recupero distanza di sicurezza
|
|
double dSafeZ = GetSafeZ() ;
|
|
// lunghezza di approccio/retrazione
|
|
double dAppr = m_Params.m_dStartPos ;
|
|
// verifico se passata da invertire (indice dispari)
|
|
bool bInvert = ( ( m_nCuts % 2) != 0) ;
|
|
// recupero la passata
|
|
PtrOwner<ICurveComposite> pCompo( CreateCurveComposite()) ;
|
|
if ( IsNull( pCompo) || ! pCompo->AddCurve( *pCut))
|
|
return false ;
|
|
if ( bInvert)
|
|
pCompo->Invert() ;
|
|
|
|
// aggiorno inizio, fine e direzione movimento
|
|
Point3d ptStart ; pCompo->GetStartPoint( ptStart) ;
|
|
Vector3d vtDirStart ; pCompo->GetStartDir( vtDirStart) ;
|
|
Vector3d vtOrtStart = vtDirStart ; vtOrtStart.Rotate( Z_AX, ( bInvert ? 90 : -90)) ;
|
|
Point3d ptEnd ; pCompo->GetEndPoint( ptEnd) ;
|
|
Vector3d vtDirEnd ; pCompo->GetEndDir( vtDirEnd) ;
|
|
Vector3d vtOrtEnd = vtDirEnd ; vtOrtEnd.Rotate( Z_AX, ( bInvert ? 90 : -90)) ;
|
|
Point3d ptNewStart = ptStart ;
|
|
Point3d ptNewEnd = ptEnd ;
|
|
|
|
// calcolo elevazioni all'inizio e alla fine
|
|
double dTgElevStart = 0 ;
|
|
GetElevation( m_nPhase, ptStart, - vtDirStart, dTgElevStart) ;
|
|
double dOrtElevStart = 0 ;
|
|
GetElevation( m_nPhase, ptStart, vtOrtStart, dOrtElevStart) ;
|
|
double dTgElevEnd = 0 ;
|
|
GetElevation( m_nPhase, ptEnd, vtDirEnd, dTgElevEnd) ;
|
|
double dOrtElevEnd = 0 ;
|
|
GetElevation( m_nPhase, ptEnd, vtOrtEnd, dOrtElevEnd) ;
|
|
dEndElev = dOrtElevEnd ;
|
|
|
|
// se attacco/uscita/collegamento standard allungo inizio e fine dell'approccio
|
|
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_STD) {
|
|
// modifico inizio
|
|
ptNewStart = ptStart - vtDirStart * dAppr ;
|
|
// modifico fine
|
|
ptNewEnd = ptEnd + vtDirEnd * dAppr ;
|
|
}
|
|
// se attacco/uscita/collegamento esterno allungo inizio e fine a fuori grezzo
|
|
else if ( m_Params.m_nLeadLinkType == SAWFIN_LL_OUT) {
|
|
// distanza XY tra centro e bordo taglio
|
|
double dDeltaTStart = 0 ;
|
|
if ( dOrtElevStart > 0.0 && dOrtElevStart < 0.5 * m_TParams.m_dDiam)
|
|
dDeltaTStart = sqrt( dOrtElevStart * m_TParams.m_dDiam - dOrtElevStart * dOrtElevStart) ;
|
|
double dDeltaTEnd = 0 ;
|
|
if ( dOrtElevEnd > 0.0 && dOrtElevEnd < 0.5 * m_TParams.m_dDiam)
|
|
dDeltaTEnd = sqrt( dOrtElevEnd * m_TParams.m_dDiam - dOrtElevEnd * dOrtElevEnd) ;
|
|
// modifico inizio
|
|
ptNewStart = ptStart - vtDirStart * ( dTgElevStart + dDeltaTStart + dAppr) ;
|
|
// modifico fine
|
|
ptNewEnd = ptEnd + vtDirEnd * ( dTgElevEnd + dDeltaTEnd + dAppr) ;
|
|
}
|
|
|
|
// Sempre una sola passata
|
|
SetCorrAuxDir( vtOrtStart) ;
|
|
// 1 -> approccio
|
|
if ( bFirst || m_Params.m_nLeadLinkType == SAWFIN_LL_CENT) {
|
|
if ( ! AddApproach( ptNewStart, vtOrtStart, dSafeZ, dOrtElevStart, dAppr))
|
|
return false ;
|
|
}
|
|
else if ( m_Params.m_nLeadLinkType == SAWFIN_LL_STD) {
|
|
// recupero ultimo punto inserito
|
|
Point3d ptCurr ;
|
|
GetCurrPos( ptCurr) ;
|
|
// differenza tra corrente e nuovo lungo direzione ortogonale
|
|
double dOrtStartDiff = ( ptNewStart - ptCurr) * vtOrtStart ;
|
|
// se punto corrente più fuori, aggiungo punto fuori allo stesso modo sul nuovo
|
|
if ( dOrtStartDiff < - 10 * EPS_SMALL) {
|
|
Point3d ptOut = ptNewStart + ( - dOrtStartDiff * vtOrtStart) ;
|
|
SetFlag( 0) ;
|
|
SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ;
|
|
if ( ! SameAsCurrPos( ptOut) && AddLinearMove( ptOut) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// se altrimenti più dentro, aggiungo punto fuori allo stesso modo sul corrente
|
|
else if ( dOrtStartDiff > 10 * EPS_SMALL) {
|
|
Point3d ptOut = ptCurr + ( dOrtStartDiff * vtOrtStart) ;
|
|
SetFlag( 0) ;
|
|
SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ;
|
|
if ( ! SameAsCurrPos( ptOut) && AddLinearMove( ptOut) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
}
|
|
// 2 -> movimento in affondo al punto iniziale
|
|
SetFlag( 0) ;
|
|
// con attacco centrato sono sul materiale e devo usare feed di testa
|
|
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_CENT) {
|
|
SetFeed( GetTipFeed()) ;
|
|
if ( AddLinearMove( ptNewStart) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// con attacco fuori sono in aria
|
|
else {
|
|
if ( bFirst) {
|
|
SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ;
|
|
if ( AddLinearMove( ptNewStart) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
else {
|
|
Point3d ptLast ;
|
|
GetCurrPos( ptLast) ;
|
|
double dDiff = ( ptNewStart - ptLast) * vtDirStart ;
|
|
// se precedente e corrente sono fuori allo stesso modo
|
|
if ( abs( dDiff) < 10 * EPS_SMALL) {
|
|
// inizio nuova passata
|
|
SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ;
|
|
if ( AddLinearMove( ptNewStart) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// se il precedente è più fuori
|
|
else if ( dDiff > 0) {
|
|
// allungo nuova passata
|
|
SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ;
|
|
if ( AddLinearMove( ptNewStart - dDiff * vtDirStart) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// se il corrente è più fuori
|
|
else {
|
|
// allungo passata precedente
|
|
if ( AddLinearMove( ptLast + dDiff * vtDirStart) == GDB_ID_NULL)
|
|
return false ;
|
|
// inizio nuova passata
|
|
SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ;
|
|
if ( AddLinearMove( ptNewStart) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
// se non ci sono già, vado all'inizio dell'arco
|
|
if ( ! SameAsCurrPos( ptStart) && AddLinearMove( ptStart) == GDB_ID_NULL)
|
|
return false ;
|
|
// 3 -> movimento di lato al punto finale
|
|
const ICurve* pCrv = pCompo->GetFirstCurve() ;
|
|
while ( pCrv != nullptr) {
|
|
Point3d ptEnd ; pCrv->GetEndPoint( ptEnd) ;
|
|
Vector3d vtDirEnd ; pCrv->GetEndDir( vtDirEnd) ;
|
|
Vector3d vtOrtEnd = vtDirEnd ; vtOrtEnd.Rotate( Z_AX, ( bInvert ? 90 : -90)) ;
|
|
SetCorrAuxDir( vtOrtEnd) ;
|
|
SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ;
|
|
if ( pCrv->GetType() == CRV_LINE) {
|
|
if ( AddLinearMove( ptEnd) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
else {
|
|
Point3d ptCen ; pCrv->GetCenterPoint( ptCen) ;
|
|
double dAngCen = GetCurveArc( pCrv)->GetAngCenter() ;
|
|
if ( AddArcMove( ptEnd, ptCen, dAngCen, vtTool) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
pCrv = pCompo->GetNextCurve() ;
|
|
}
|
|
if ( m_Params.m_nLeadLinkType != SAWFIN_LL_CENT) {
|
|
SetFeed( GetEndFeed()) ;
|
|
if ( ! SameAsCurrPos( ptNewEnd) && AddLinearMove( ptNewEnd) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// 4 -> retrazione
|
|
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_CENT) {
|
|
if ( ! AddRetract( ptNewEnd, vtOrtEnd, dSafeZ, dOrtElevEnd, dAppr))
|
|
return false ;
|
|
}
|
|
// incremento contatore passate
|
|
++ m_nCuts ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalcCurvedAcrossZigZagCut( const PolyLine& PL, const Vector3d& vtMove, const Point3d& ptAxRot, double dAngRotDeg,
|
|
const Vector3d& vtTool, const Vector3d& vtCorr, const Vector3d& vtPrev, double dDepth,
|
|
bool bFirst, bool bCorner)
|
|
{
|
|
// recupero distanza di sicurezza
|
|
double dSafeZ = GetSafeZ() ;
|
|
// lunghezza di approccio/retrazione
|
|
double dAppr = m_Params.m_dStartPos ;
|
|
|
|
// sezione da invertire
|
|
bool bInvert = (( m_nCuts % 2) != 0) ;
|
|
|
|
Point3d ptP ;
|
|
bool bFound = ( bInvert ? PL.GetLastPoint( ptP) : PL.GetFirstPoint( ptP)) ;
|
|
// 1 -> approccio
|
|
if ( bFound) {
|
|
ptP += vtMove - 0.5 * m_TParams.m_dThick * vtTool ;
|
|
ptP.Rotate( ptAxRot, Z_AX, dAngRotDeg) ;
|
|
double dElev = 0 ;
|
|
GetElevation( m_nPhase, ptP, vtCorr, dElev) ;
|
|
if ( dElev > dDepth) {
|
|
ptP += ( dElev - dDepth) * vtCorr ;
|
|
dElev = dDepth ;
|
|
}
|
|
if ( bFirst) {
|
|
if ( ! AddApproach( ptP, vtCorr, dSafeZ, dElev, dAppr))
|
|
return false ;
|
|
}
|
|
else if ( bCorner) {
|
|
if ( ! AddCornerApproach( ptP, vtCorr, vtPrev, dSafeZ, dElev, dAppr))
|
|
return false ;
|
|
}
|
|
}
|
|
// 2 -> movimento lungo la sezione
|
|
Point3d ptPrev ;
|
|
GetCurrPos( ptPrev) ;
|
|
while ( bFound) {
|
|
// se diverso da precedente, movimento al punto
|
|
if ( ! AreSamePointEpsilon( ptP, ptPrev, 10 * EPS_SMALL)) {
|
|
Vector3d vtDelta = ptP - ptPrev ;
|
|
if ( vtDelta.z > - EPS_SMALL)
|
|
SetFeed( GetFeed()) ;
|
|
else {
|
|
double dC = sqrt( 1 + ( vtDelta.x * vtDelta.x + vtDelta.y * vtDelta.y) / ( vtDelta.z * vtDelta.z)) ;
|
|
double dF = min( GetFeed(), dC * GetTipFeed()) ;
|
|
SetFeed( dF) ;
|
|
}
|
|
if ( AddLinearMove( ptP) == GDB_ID_NULL)
|
|
return false ;
|
|
ptPrev = ptP ;
|
|
}
|
|
// recupero punto successivo
|
|
bFound = ( bInvert ? PL.GetPrevPoint( ptP) : PL.GetNextPoint( ptP)) ;
|
|
if ( bFound) {
|
|
ptP += vtMove - 0.5 * m_TParams.m_dThick * vtTool ;
|
|
ptP.Rotate( ptAxRot, Z_AX, dAngRotDeg) ;
|
|
double dElev = 0 ;
|
|
GetElevation( m_nPhase, ptP, vtCorr, dElev) ;
|
|
if ( dElev > dDepth) {
|
|
ptP += ( dElev - dDepth) * vtCorr ;
|
|
dElev = dDepth ;
|
|
}
|
|
}
|
|
}
|
|
// incremento contatore passate
|
|
++ m_nCuts ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::AddApproach( const Point3d& ptP, const Vector3d& vtCorr,
|
|
double dSafeZ, double dElev, double dAppr)
|
|
{
|
|
// impongo minima distanza di approccio
|
|
dAppr = max( dAppr, 1.0) ;
|
|
// se distanza di sicurezza minore di distanza di inizio
|
|
if ( dSafeZ < dAppr + 10 * EPS_SMALL) {
|
|
// 1 -> punto sopra inizio
|
|
Point3d ptP1 = ptP + vtCorr * ( dElev + dAppr) ;
|
|
if ( m_nCuts == 0) {
|
|
SetFlag( 1) ;
|
|
if ( AddRapidStart( ptP1) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
else {
|
|
SetFlag( 0) ;
|
|
if ( ! SameAsCurrPos( ptP1) && AddRapidMove( ptP1) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
}
|
|
else {
|
|
// 1a -> punto sopra inizio
|
|
Point3d ptP1b = ptP + vtCorr * ( dElev + dAppr) ;
|
|
Point3d ptP1a = ptP1b + vtCorr * ( dSafeZ - dAppr) ;
|
|
if ( m_nCuts == 0) {
|
|
SetFlag( 1) ;
|
|
if ( AddRapidStart( ptP1a) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
else {
|
|
SetFlag( 0) ;
|
|
if ( ! SameAsCurrPos( ptP1a) && AddRapidMove( ptP1a) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// 1b -> punto appena sopra inizio
|
|
SetFlag( 0) ;
|
|
if ( AddRapidMove( ptP1b) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::AddCornerApproach( const Point3d& ptP, const Vector3d& vtCorr, const Vector3d& vtPrev,
|
|
double dSafeZ, double dElev, double dAppr)
|
|
{
|
|
// impongo minima distanza di approccio
|
|
dAppr = max( dAppr, 1.0) ;
|
|
// recupero posizione precedente (correzione precedente è passata perchè già impostata la nuova)
|
|
Point3d ptPrev ;
|
|
if ( ! GetCurrPos( ptPrev))
|
|
return false ;
|
|
// determino il numero di passi di interpolazione
|
|
double dAngDeg = 0 ;
|
|
vtCorr.GetAngleXY( vtPrev, dAngDeg) ;
|
|
int nStep = int( abs( dAngDeg) / 15) ;
|
|
// se distanza di sicurezza minore di distanza di inizio
|
|
if ( dSafeZ < dAppr + 10 * EPS_SMALL) {
|
|
// 1 -> punto sopra inizio
|
|
Point3d ptP1 = ptP + vtCorr * ( dElev + dAppr) ;
|
|
SetFlag( 0) ;
|
|
for ( int i = 1 ; i <= nStep ; ++ i) {
|
|
double dCoeff = i / double( nStep) ;
|
|
Point3d ptOut = Media( ptPrev, ptP1, dCoeff) ;
|
|
Vector3d vtOut = Media( vtPrev, vtCorr, dCoeff) ;
|
|
vtOut.Normalize() ;
|
|
SetCorrAuxDir( vtOut) ;
|
|
AddRapidMove( ptOut) ;
|
|
}
|
|
}
|
|
else {
|
|
// 1a -> punto sopra inizio
|
|
Point3d ptP1b = ptP + vtCorr * ( dElev + dAppr) ;
|
|
Point3d ptP1a = ptP1b + vtCorr * ( dSafeZ - dAppr) ;
|
|
SetFlag( 0) ;
|
|
for ( int i = 1 ; i <= nStep ; ++ i) {
|
|
double dCoeff = i / double( nStep) ;
|
|
Point3d ptOut = Media( ptPrev, ptP1a, dCoeff) ;
|
|
Vector3d vtOut = Media( vtPrev, vtCorr, dCoeff) ;
|
|
vtOut.Normalize() ;
|
|
SetCorrAuxDir( vtOut) ;
|
|
AddRapidMove( ptOut) ;
|
|
}
|
|
// 1b -> punto appena sopra inizio
|
|
SetFlag( 0) ;
|
|
if ( AddRapidMove( ptP1b) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::AddRetract( const Point3d& ptP, const Vector3d& vtCorr,
|
|
double dSafeZ, double dElev, double dAppr)
|
|
{
|
|
// impongo minima distanza di approccio
|
|
dAppr = max( dAppr, 1.0) ;
|
|
// se distanza di sicurezza minore di distanza di fine
|
|
if ( dSafeZ < dAppr + 10 * EPS_SMALL) {
|
|
// 4 -> movimento di risalita sopra il punto finale
|
|
SetFeed( GetEndFeed()) ;
|
|
Point3d ptP4 = ptP + vtCorr * ( dElev + dAppr) ;
|
|
if ( ! SameAsCurrPos( ptP4) && AddLinearMove( ptP4) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
else {
|
|
// 4a -> movimento di risalita appena sopra il punto finale
|
|
Point3d ptP4a = ptP + vtCorr * ( dElev + dAppr) ;
|
|
SetFeed( GetEndFeed()) ;
|
|
if ( ! SameAsCurrPos( ptP4a) && AddLinearMove( ptP4a) == GDB_ID_NULL)
|
|
return false ;
|
|
// 4b -> movimento di risalita sopra il punto finale
|
|
Point3d ptP4b = ptP4a + vtCorr * ( dSafeZ - dAppr) ;
|
|
if ( AddRapidMove( ptP4b) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::CalculateToolAndCorrVersors( const Vector3d& vtTang, int nHeadSide, Vector3d& vtTool, Vector3d& vtCorr) const
|
|
{
|
|
// Versore fresa : annullo la componente in Z e normalizzo
|
|
vtTool = vtTang ;
|
|
vtTool.z = 0 ;
|
|
if ( ! vtTool.Normalize())
|
|
return false ;
|
|
// ruoto attorno a Zglob+ a seconda del lato mandrino
|
|
if ( nHeadSide == SAW_HS_LEFT)
|
|
vtTool.Rotate( Z_AX, 0, 1) ;
|
|
else
|
|
vtTool.Rotate( Z_AX, 0, -1) ;
|
|
|
|
// Versore correzione
|
|
vtCorr = Z_AX ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SawFinishing::GetHeightOnSection( const ICurve* pSect, double dX, double dYmin, double dYmax, double& dY)
|
|
{
|
|
// creo raggio per intersezione con direzione Y+
|
|
PtrOwner<ICurveLine>pRay( CreateCurveLine()) ;
|
|
if ( IsNull( pRay) ||
|
|
! pRay->Set( Point3d( dX, dYmin - EPS_SMALL, 0), Point3d( dX, dYmax + EPS_SMALL, 0)))
|
|
return false ;
|
|
// eseguo intersezione (considero l'ultima, ovvero quella con Y maggiore)
|
|
IntersCurveCurve intCC( *pRay, *pSect) ;
|
|
IntCrvCrvInfo aInfo ;
|
|
if ( intCC.GetIntCrvCrvInfo( intCC.GetIntersCount() - 1, aInfo)) {
|
|
// nel caso di sovrapposizione devo prendere la Y in basso del tratto
|
|
dY = aInfo.IciA[0].ptI.y ;
|
|
return true ;
|
|
}
|
|
// se non c'è intersezione assegno il minimo
|
|
dY = dYmin ;
|
|
return true ;
|
|
}
|