Files
EgtMachKernel/SawFinishing.cpp
Dario Sassi 8fed51ca79 EgtMachKernel :
- aggiunta scrittura nota "EXTR" in Px di CL per SawRoughing e SawFinishing.
2026-03-20 10:40:18 +01:00

2961 lines
106 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 "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/EGkOffsetCurve.h"
#include "/EgtDev/Include/EGkOffsetCurveOnX.h"
#include "/EgtDev/Include/EGkSfrCreate.h"
#include "/EgtDev/Include/EGkIntervals.h"
#include "/EgtDev/Include/EGkUserObjFactory.h"
#include "/EgtDev/Include/EGnStringKeyVal.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
// 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"
// 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)"
//----------------------------------------------------------------------------
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 ;
}
}
}
// 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) ||
( 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
ICurve* pSect ;
int nSectGrpId = m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_SECTION) ;
if ( ! CalculateSection( nSectGrpId, pSect))
return false ;
PtrOwner<ICurve> pCrv( pSect) ;
// 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 ed elaboro la linea guida
Point3d ptGdStart, ptGdEnd ;
Vector3d vtGdDir ;
int nGuideId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_GUIDE)) ;
if ( ! CalculateGuideLine( nGuideId, b3Sect, ptGdStart, ptGdEnd, vtGdDir))
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) ;
// 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,
ptGdStart, ptGdEnd, vtGdDir,
dDepth, b3Raw.GetMax().z, vtTool, vtCorr))
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,
ptGdStart, ptGdEnd, vtGdDir,
dDepth, b3Raw.GetMax().z, vtTool, vtCorr))
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,
ptGdStart, ptGdEnd, vtGdDir,
dDepth, b3Raw.GetMax().z, vtTool, vtCorr))
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
ICurve* pSect ;
int nSectGrpId = m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_SECTION) ;
if ( ! CalculateSection( nSectGrpId, pSect))
return false ;
PtrOwner<ICurve> pCrv( pSect) ;
// 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 ed elaboro la linea guida
Point3d ptGdStart, ptGdEnd ;
Vector3d vtGdDir ;
int nGuideId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_GUIDE)) ;
if ( ! CalculateGuideLine( nGuideId, b3Sect, ptGdStart, ptGdEnd, vtGdDir))
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 ;
}
// 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
ICurve* pSect ;
if ( ! CalculateSection( nSectGrpId, pSect))
return false ;
// Contro rotazione della curva
m_pGeomDB->Rotate( nCrvId, ORIG, Z_AX, -90.0) ;
PtrOwner<ICurve> pCrv( pSect) ;
// 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) ;
// 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
ICurve* pSect ;
if ( ! CalculateSection( nSectGrpId, pSect))
return false ;
// Contro rotazione della curva
m_pGeomDB->Rotate( nCrvId, ORIG, Z_AX, -90.0) ;
PtrOwner<ICurve> pCrv( pSect) ;
// 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) ;
// 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::CalculateSection( int nSectGrpId, ICurve*& pSect)
{
// 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 < int( vpNucCrvs.size()) ; ++ 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 ; }) ;
// 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 < int( vpNucCrvs.size()) ; ++ 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 ;
}
// offset radiale delle sezioni per il sovramateriale
double dOffsR = GetOffsR() ;
PtrOwner<ICurve> pOvrCrv ;
OffsetCurve OffsCrv ;
OffsCrv.Make( pCurve, dOffsR, ICurve::OFF_FILLET) ;
pOvrCrv.Set( OffsCrv.GetLongerCurve()) ;
// ricavo dalla sezione la curva per centro in basso della lama
double dOffsX = 0.5 * m_TParams.m_dThick ;
PtrOwner<ICurve> pCrv ;
OffsetCurveOnX OffsCrvX ;
OffsCrvX.Make( pOvrCrv, dOffsX) ;
pCrv.Set( OffsCrvX.GetLongerCurve()) ;
// eseguo trim (se richiesto)
if ( IsNull( pCrv) || ! TrimSection( pCrv))
return false ;
pSect = Release( pCrv) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::TrimSection( ICurve* pCrv)
{
// 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 ( auto& 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::CalculateGuideLine( int nGuideId, const BBox3d& b3Sect,
Point3d& ptGdStart, Point3d& ptGdEnd, Vector3d& vtGdDir)
{
// 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) ;
// per ora ammesse solo linee guida rettilinee dirette lungo X o Y
if ( ! AreSameOrOppositeVectorApprox( vtGdDir, X_AX) &&
! AreSameOrOppositeVectorApprox( vtGdDir, Y_AX)) {
m_pMchMgr->SetLastError( 2707, "Error in SawFinishing : Guide Line not along X or Y") ;
return false ;
}
// 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 ;
}
// aggiusto la linea guida al bordo del box
if ( AreSameVectorApprox( vtGdDir, X_AX)) {
ptGdStart.x = b3Raw.GetMin().x ;
ptGdEnd.x = b3Raw.GetMax().x ;
}
else if ( AreOppositeVectorApprox( vtGdDir, X_AX)) {
ptGdStart.x = b3Raw.GetMax().x ;
ptGdEnd.x = b3Raw.GetMin().x ;
}
else if ( AreSameVectorApprox( vtGdDir, Y_AX)) {
ptGdStart.y = b3Raw.GetMin().y ;
ptGdEnd.y = b3Raw.GetMax().y ;
}
else {
ptGdStart.y = b3Raw.GetMax().y ;
ptGdEnd.y = b3Raw.GetMin().y ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::ClassifySection( ICurve* pCrv, INTVECTOR& vnClass)
{
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, 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) ;
// 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,
const Point3d& ptGdStart, const Point3d& ptGdEnd, const Vector3d& vtGdDir,
double dDepth, double dRawMaxZ, const Vector3d& vtTool, const Vector3d& vtCorr)
{
// 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 ;
// 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, true))
return false ;
}
else {
if ( ! CalcAlongZigZagCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, 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,
const Point3d& ptGdStart, const Point3d& ptGdEnd, const Vector3d& vtGdDir,
double dDepth, double dRawMaxZ, const Vector3d& vtTool, const Vector3d& vtCorr)
{
// 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) ;
// 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 ;
// 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, false))
return false ;
}
else {
if ( ! CalcAlongZigZagCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, 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::CalcAlongOneWayCut( const Point3d& ptStart, const Point3d& ptEnd, const Vector3d& vtDir,
const Vector3d& vtTool, const Vector3d& vtCorr, double dElev, bool bVert)
{
// recupero distanza di sicurezza
double dSafeZ = GetSafeZ() ;
// lunghezza di approccio/retrazione
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 * dAppr ;
}
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 + dAppr) ;
}
// 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 bVert, bool bFirst)
{
// recupero distanza di sicurezza
double dSafeZ = GetSafeZ() ;
// lunghezza di approccio/retrazione
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 * dAppr ;
// modifico fine
ptNewEnd = ptEnd + vtDir * 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 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 + dAppr) ;
// modifico fine
ptNewEnd = ptEnd + vtDir * ( dDeltaT + dAppr) ;
}
// 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)
{
// 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 ;
}