//---------------------------------------------------------------------------- // EgalTech 2015-2015 //---------------------------------------------------------------------------- // File : Sawing.cpp Data : 24.10.15 Versione : 1.6j3 // Contenuto : Implementazione gestione tagli con lama. // // Note : Questa lavorazione è sempre espressa nel riferimento globale. // // Modifiche : 07.06.15 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "MachMgr.h" #include "DllMain.h" #include "Sawing.h" #include "OperationConst.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/EGkChainCurves.h" #include "/EgtDev/Include/EGkDistPointCurve.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EGkSurfTriMesh.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 -------------------------------------- // 2201 = "Error in Sawing : UpdateToolData failed" // 2202 = "Error in Sawing : Center work not allowed with side angle" // 2203 = "Error in Sawing : External side angle HeadSide must equal WorkSide" // 2204 = "Error in Sawing : Internal side angle HeadSide must opposite WorkSide" // 2205 = "Error in Sawing : Depth not computable" // 2206 = "Error in Sawing : machining depth (xx) bigger than MaxMaterial (yy)" // 2207 = "Error in Sawing : SideAngle not allowed on Arc" // 2208 = "Error in Sawing : Entity CalculateToolAndCorrVersors" // 2209 = "Error in Sawing : Entity AdjustForSide" // 2210 = "Error in Sawing : Entity GetElevation" // 2211 = "Error in Sawing : Entity AdjustForEdges" // 2212 = "Error in Sawing : Entity CalculateToolAndCorrVersors 2nd" // 2213 = "Error in Sawing : Center work not allowed with internal arc" // 2214 = "Error in Sawing : Chaining failed" // 2215 = "Error in Sawing : axes values not calculable" // 2216 = "Error in Sawing : outstroke xxx" // 2217 = "Error in Sawing : link movements not calculable" // 2218 = "Error in Sawing : link outstroke xxx" // 2219 = "Error in Sawing : post apply not calculable" //---------------------------------------------------------------------------- USEROBJ_REGISTER( GetOperationClass( OPER_SAWING), Sawing) ; //---------------------------------------------------------------------------- const string& Sawing::GetClassName( void) const { return USEROBJ_GETNAME( Sawing) ; } //---------------------------------------------------------------------------- Sawing* Sawing::Clone( void) const { // alloco oggetto Sawing* pSaw = new(nothrow) Sawing ; // eseguo copia dei dati if ( pSaw != nullptr) { try { pSaw->m_Params = m_Params ; pSaw->m_TParams = m_TParams ; } catch( ...) { delete pSaw ; return nullptr ; } } // ritorno l'oggetto return pSaw ; } //---------------------------------------------------------------------------- bool Sawing::Dump( string& sOut, bool bMM, const char* szNewLine) const { sOut += GetClassName() + "[mm]" + szNewLine ; sOut += KEY_PHASE + EQUAL + ToString( m_nPhase) + szNewLine ; sOut += KEY_IDS + EQUAL + ToString( m_vId) + szNewLine ; for ( int i = 0 ; i < m_Params.GetSize() ; ++ i) sOut += m_Params.ToString( i) + szNewLine ; for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i) sOut += m_TParams.ToString( i) + szNewLine ; sOut += KEY_NUM + EQUAL + ToString( m_nCuts) + szNewLine ; return true ; } //---------------------------------------------------------------------------- bool Sawing::Save( int nBaseId, STRVECTOR& vString) const { try { int nSize = 1 + m_Params.GetSize() + m_TParams.GetSize() + 2 ; 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 ; } catch( ...) { return false ; } return true ; } //---------------------------------------------------------------------------- bool Sawing::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 ; } } return true ; } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- Sawing::Sawing( void) { m_Params.m_sName = "*" ; m_Params.m_sToolName = "*" ; m_TParams.m_sName = "*" ; m_TParams.m_sHead = "*" ; m_nCuts = 0 ; } //---------------------------------------------------------------------------- bool Sawing::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 SawingData* pDdata = GetSawingData( 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 Sawing::SetParam( int nType, bool bVal) { switch ( nType) { case MPA_INVERT : m_Params.m_bInvert = bVal ; return true ; } return false ; } //---------------------------------------------------------------------------- bool Sawing::SetParam( int nType, int nVal) { switch ( nType) { case MPA_WORKSIDE : if ( ! m_Params.VerifyWorkSide( nVal)) return false ; m_Params.m_nWorkSide = nVal ; return true ; case MPA_HEADSIDE : if ( ! m_Params.VerifyHeadSide( nVal)) return false ; m_Params.m_nHeadSide = nVal ; return true ; case MPA_STEPTYPE : if ( ! m_Params.VerifyStepType( nVal)) return false ; m_Params.m_nStepType = nVal ; return true ; case MPA_LEADINTYPE : if ( ! m_Params.VerifyLeadInType( nVal)) return false ; m_Params.m_nLeadInType = nVal ; return true ; case MPA_EXTLINKTYPE : if ( ! m_Params.VerifyExtLinkType( nVal)) return false ; m_Params.m_nExtLinkType = nVal ; return true ; case MPA_LEADOUTTYPE : if ( ! m_Params.VerifyLeadOutType( nVal)) return false ; m_Params.m_nLeadOutType = nVal ; return true ; case MPA_CURVEUSE : if ( ! m_Params.VerifyCurveUse( nVal)) return false ; m_Params.m_nCurveUse = nVal ; return true ; case MPA_SCC : if ( ! m_Params.VerifySolCh( nVal)) return false ; m_Params.m_nSolCh = nVal ; return true ; } return false ; } //---------------------------------------------------------------------------- bool Sawing::SetParam( int nType, double dVal) { switch ( nType) { case MPA_SPEED : if ( ! m_TParams.VerifySpeed( dVal)) return false ; if ( abs( m_TParams.m_dSpeed - dVal) < EPS_MACH_ANG_PAR) m_Params.m_dSpeed = 0 ; else m_Params.m_dSpeed = dVal ; return true ; case MPA_FEED : if ( abs( m_TParams.m_dFeed - dVal) < EPS_MACH_LEN_PAR) m_Params.m_dFeed = 0 ; else m_Params.m_dFeed = dVal ; return true ; case MPA_STARTFEED : if ( abs( m_TParams.m_dStartFeed - dVal) < EPS_MACH_LEN_PAR) m_Params.m_dStartFeed = 0 ; else m_Params.m_dStartFeed = dVal ; return true ; case MPA_ENDFEED : if ( abs( m_TParams.m_dEndFeed - dVal) < EPS_MACH_LEN_PAR) m_Params.m_dEndFeed = 0 ; else m_Params.m_dEndFeed = dVal ; return true ; case MPA_TIPFEED : if ( abs( m_TParams.m_dTipFeed - dVal) < EPS_MACH_LEN_PAR) m_Params.m_dTipFeed = 0 ; else m_Params.m_dTipFeed = dVal ; return true ; case MPA_OFFSR : if ( abs( m_TParams.m_dOffsR - dVal) < EPS_MACH_LEN_PAR) m_Params.m_dOffsR = UNKNOWN_PAR ; else m_Params.m_dOffsR = dVal ; return true ; case MPA_OFFSL : if ( abs( m_TParams.m_dOffsL - dVal) < EPS_MACH_LEN_PAR) m_Params.m_dOffsL = UNKNOWN_PAR ; else m_Params.m_dOffsL = dVal ; return true ; case MPA_DEPTH : m_Params.m_sDepth = ToString( dVal) ; return true ; case MPA_STARTPOS : m_Params.m_dStartPos = dVal ; return true ; case MPA_STEP : m_Params.m_dStep = dVal ; return true ; case MPA_STEPEXTARC : m_Params.m_dStepExtArc = dVal ; return true ; case MPA_STEPINTARC : m_Params.m_dStepIntArc = dVal ; return true ; case MPA_STEPSIDEANG : if ( abs( m_Params.m_dStep - dVal) < EPS_MACH_LEN_PAR) m_Params.m_dStepSideAng = UNKNOWN_PAR ; else m_Params.m_dStepSideAng = dVal ; return true ; case MPA_SIDEANGLE : if ( ! m_Params.VerifySideAngle( dVal)) return false ; m_Params.m_dSideAngle = dVal ; return true ; case MPA_STARTADDLEN : m_Params.m_dStartAddLen = dVal ; return true ; case MPA_ENDADDLEN : m_Params.m_dEndAddLen = dVal ; return true ; case MPA_APPROX : m_Params.m_dApprox = dVal ; return true ; } return false ; } //---------------------------------------------------------------------------- bool Sawing::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 ; m_Params.m_sToolName = sVal ; m_Params.m_ToolUuid = pTdata->m_Uuid ; m_TParams = *pTdata ; } return true ; case MPA_DEPTH_STR : m_Params.m_sDepth = sVal ; return true ; case MPA_SYSNOTES : m_Params.m_sSysNotes = sVal ; break ; case MPA_USERNOTES : m_Params.m_sUserNotes = sVal ; break ; case MPA_INITANGS : m_Params.m_sInitAngs = sVal ; break ; case MPA_BLOCKEDAXIS : m_Params.m_sBlockedAxis = sVal ; break ; } return false ; } //---------------------------------------------------------------------------- bool Sawing::SetGeometry( const SELVECTOR& vIds) { // verifico validità gestore DB geometrico if ( m_pGeomDB == nullptr) return false ; // reset della geometria corrente m_vId.clear() ; // verifico che gli identificativi rappresentino delle entità ammissibili int nType = GEO_NONE ; for ( const auto& Id : vIds) { // test sull'entità int nSubs ; if ( ! VerifyGeometry( Id, nSubs, nType)) { string sOut = "Warning in Sawing : Skipped entity " + ToString( Id) ; LOG_INFO( GetEMkLogger(), sOut.c_str()) ; continue ; } // posso aggiungere alla lista m_vId.emplace_back( Id) ; } return ( ! m_vId.empty() || vIds.empty()) ; } //---------------------------------------------------------------------------- bool Sawing::Preview( bool bRecalc) { // reset numero tagli nella lavorazione m_nCuts = 0 ; // verifico validità gestore DB geometrico e Id del gruppo if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId)) return false ; // recupero gruppo per geometria ausiliaria int nAuxId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_AUX) ; bool bChain = false ; // se non c'è, lo aggiungo if ( nAuxId == GDB_ID_NULL) { nAuxId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; if ( nAuxId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nAuxId, MCH_AUX) ; m_pGeomDB->SetStatus( nAuxId, GDB_ST_OFF) ; bChain = true ; } // altrimenti, se chiesto ricalcolo, lo svuoto else if ( bRecalc) { m_pGeomDB->EmptyGroup( nAuxId) ; bChain = true ; } // aggiorno dati geometrici dell'utensile if ( ! UpdateToolData()) { m_pMchMgr->SetLastError( 2201, "Error in Sawing : UpdateToolData failed") ; return false ; } // se necessario, eseguo concatenamento ed inserisco i percorsi sotto la geometria ausiliaria if ( bChain && ! Chain( nAuxId)) { m_pMchMgr->SetLastError( 2214, "Error in Sawing : Chaining failed") ; return false ; } // verifiche per angolo di sbandamento if ( ! VerifySideAngle()) return false ; // recupero gruppo per anteprima di lavorazione (PreView) int nPvId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_PV) ; // se non c'è, lo aggiungo if ( nPvId == GDB_ID_NULL) { nPvId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; if ( nPvId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPvId, MCH_PV) ; } // altrimenti lo svuoto else m_pGeomDB->EmptyGroup( nPvId) ; // calcolo anteprima di ogni singola catena int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ; while ( nPathId != GDB_ID_NULL) { if ( ! ProcessPath( nPathId, nPvId, GDB_ID_NULL)) return false ; nPathId = m_pGeomDB->GetNextGroup( nPathId) ; } return true ; } //---------------------------------------------------------------------------- bool Sawing::Apply( bool bRecalc, bool bPostApply) { // reset numero tagli nella lavorazione m_nCuts = 0 ; // verifico validità gestore DB geometrico e Id del gruppo if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId)) return false ; // recupero gruppo per geometria ausiliaria int nAuxId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_AUX) ; bool bChain = false ; // se non c'è, lo aggiungo if ( nAuxId == GDB_ID_NULL) { nAuxId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; if ( nAuxId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nAuxId, MCH_AUX) ; m_pGeomDB->SetStatus( nAuxId, GDB_ST_OFF) ; bChain = true ; } // altrimenti, se chiesto ricalcolo, lo svuoto else if ( bRecalc) { m_pGeomDB->EmptyGroup( nAuxId) ; bChain = true ; } // aggiorno dati geometrici dell'utensile if ( ! UpdateToolData()) { m_pMchMgr->SetLastError( 2201, "Error in Sawing : UpdateToolData failed") ; return false ; } // se necessario, eseguo concatenamento ed inserisco i percorsi sotto la geometria ausiliaria if ( bChain && ! Chain( nAuxId)) { m_pMchMgr->SetLastError( 2214, "Error in Sawing : Chaining failed") ; return false ; } // verifiche per angolo di sbandamento if ( ! VerifySideAngle()) return false ; // recupero gruppo per geometria di lavorazione (Cutter Location) int nClId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_CL) ; // se non c'è, lo aggiungo if ( nClId == GDB_ID_NULL) { nClId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; if ( nClId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nClId, MCH_CL) ; } // altrimenti lo svuoto else m_pGeomDB->EmptyGroup( nClId) ; // lavoro ogni singola catena bool bOk = true ; int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ; while ( nPathId != GDB_ID_NULL) { if ( ! ProcessPath( nPathId, GDB_ID_NULL, nClId)) bOk = false ; nPathId = m_pGeomDB->GetNextGroup( nPathId) ; } if ( ! bOk) return false ; // assegno ingombri dei vari percorsi di lavorazione e della lavorazione nel suo complesso CalcAndSetBBox( nClId) ; // eseguo aggiornamento assi macchina e collegamento con operazione precedente return Update( bPostApply) ; } //---------------------------------------------------------------------------- bool Sawing::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) { LOG_INFO( GetEMkLogger(), "Warning in Sawing : No machinable path") return true ; } // imposto eventuale asse bloccato da lavorazione if ( ! m_Params.m_sBlockedAxis.empty()) { string sAxis, sVal ; Split( m_Params.m_sBlockedAxis, "=", true, sAxis, sVal) ; double dVal = 0 ; FromString( sVal, dVal) ; m_pMchMgr->ClearRotAxisBlock() ; m_pMchMgr->SetRotAxisBlock( sAxis, dVal) ; } // 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( 2215, "Error in Sawing : axes values not calculable") ; else m_pMchMgr->SetLastError( 2216, "Error in Sawing : outstroke ") ; return false ; } // gestione movimenti all'inizio di ogni singolo percorso di lavorazione e alla fine della lavorazione if ( ! AdjustStartEndMovements()) { string sInfo = m_pMchMgr->GetOutstrokeInfo() ; if ( sInfo.empty()) m_pMchMgr->SetLastError( 2217, "Error in Sawing : link movements not calculable") ; else m_pMchMgr->SetLastError( 2218, "Error in Sawing : link outstroke ") ; return false ; } // esecuzione eventuali personalizzazioni if ( bPostApply && ! PostApply()) { m_pMchMgr->SetLastError( 2219, "Error in Sawing : post apply not calculable") ; return false ; } return true ; } //---------------------------------------------------------------------------- bool Sawing::GetParam( int nType, bool& bVal) const { switch ( nType) { case MPA_INVERT : bVal = m_Params.m_bInvert ; return true ; } bVal = false ; return false ; } //---------------------------------------------------------------------------- bool Sawing::GetParam( int nType, int& nVal) const { switch ( nType) { case MPA_TYPE : nVal = MT_SAWING ; return true ; case MPA_WORKSIDE : nVal = m_Params.m_nWorkSide ; return true ; case MPA_HEADSIDE : nVal = m_Params.m_nHeadSide ; return true ; case MPA_STEPTYPE : nVal = m_Params.m_nStepType ; return true ; case MPA_LEADINTYPE : nVal = m_Params.m_nLeadInType ; return true ; case MPA_EXTLINKTYPE : nVal = m_Params.m_nExtLinkType ; return true ; case MPA_LEADOUTTYPE : nVal = m_Params.m_nLeadOutType ; return true ; case MPA_CURVEUSE : nVal = m_Params.m_nCurveUse ; return true ; case MPA_SCC : nVal = m_Params.m_nSolCh ; return true ; } nVal = 0 ; return false ; } //---------------------------------------------------------------------------- bool Sawing::GetParam( int nType, double& dVal) const { switch ( nType) { case MPA_SPEED : dVal = GetSpeed() ; return true ; case MPA_FEED : dVal = GetFeed() ; return true ; case MPA_STARTFEED : dVal = GetStartFeed() ; return true ; case MPA_ENDFEED : dVal = GetEndFeed() ; return true ; case MPA_TIPFEED : dVal = GetTipFeed() ; return true ; case MPA_OFFSR : dVal =GetOffsR() ; return true ; case MPA_OFFSL : dVal = GetOffsL() ; return true ; case MPA_STARTPOS : dVal = m_Params.m_dStartPos ; return true ; case MPA_STEP : dVal = m_Params.m_dStep ; return true ; case MPA_STEPEXTARC : dVal = m_Params.m_dStepExtArc ; return true ; case MPA_STEPINTARC : dVal = m_Params.m_dStepIntArc ; return true ; case MPA_STEPSIDEANG : dVal = GetStepSideAng() ; return true ; case MPA_SIDEANGLE : dVal = m_Params.m_dSideAngle ; return true ; case MPA_STARTADDLEN : dVal = m_Params.m_dStartAddLen ; return true ; case MPA_ENDADDLEN : dVal = m_Params.m_dEndAddLen ; return true ; case MPA_APPROX : dVal = m_Params.m_dApprox ; return true ; } dVal = 0 ; return false ; } //---------------------------------------------------------------------------- bool Sawing::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& Sawing::GetToolData( void) const { return m_TParams ; } //---------------------------------------------------------------------------- bool Sawing::UpdateToolData( bool* pbChanged) { // recupero il gestore DB utensili della macchina corrente ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ; if ( pTMgr == nullptr) return false ; // recupero l'utensile nel DB utensili const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ; if ( pTdata == nullptr) return false ; // verifico se sono diversi (ad esclusione del nome) m_TParams.m_sName = pTdata->m_sName ; bool bChanged = ! SameTool( m_TParams, *pTdata) ; // aggiorno comunque i parametri m_TParams = *pTdata ; // eventuali segnalazioni if ( ! EqualNoCase( m_Params.m_sToolName, m_TParams.m_sName)) { string sLog = "Warning in Sawing : tool name changed (" + m_Params.m_sToolName + "->" + m_TParams.m_sName + ")" ; LOG_INFO( GetEMkLogger(), sLog.c_str()) ; m_Params.m_sToolName = m_TParams.m_sName ; } if ( bChanged) { string sLog = "Warning in Sawing : tool data changed (" + m_Params.m_sToolName + ")" ; LOG_INFO( GetEMkLogger(), sLog.c_str()) ; } // se definito parametro di ritorno, lo assegno if ( pbChanged != nullptr) *pbChanged = bChanged ; return true ; } //---------------------------------------------------------------------------- bool Sawing::GetGeometry( SELVECTOR& vIds) const { // restituisco l'elenco delle entità vIds = m_vId ; return true ; } //---------------------------------------------------------------------------- bool Sawing::AdjustEndPointForAxesCalc( const CamData* pCamData, Point3d& ptP) const { // compenso il raggio dell'utensile ptP += pCamData->GetCorrDir() * ( m_TParams.m_dDiam / 2) ; return true ; } //---------------------------------------------------------------------------- bool Sawing::VerifyGeometry( SelData Id, int& nSubs, int& nType) { // ammessi : tutte curve o tutte facce di trimesh const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ; if ( pGObj == nullptr) return false ; // se ammesse curve ed è tale if ( nType != GEO_SURF && ( pGObj->GetType() & GEO_CURVE) != 0) { const ICurve* pCurve = nullptr ; const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ; // se direttamente la curva if ( Id.nSub == SEL_SUB_ALL) { pCurve = ::GetCurve( m_pGeomDB->GetGeoObj( Id.nId)) ; if ( pCurve != nullptr) { if ( pCurve->GetType() == CRV_COMPO) nSubs = ::GetCurveComposite( pCurve)->GetCurveCount() ; else nSubs = 0 ; } } // altrimenti sottocurva di composita else { const ICurveComposite* pCompo = GetCurveComposite( m_pGeomDB->GetGeoObj( Id.nId)) ; if ( pCompo != nullptr) pCurve = pCompo->GetCurve( Id.nSub) ; nSubs = 0 ; } return ( pCurve != nullptr) ; } // se altrimenti ammesse superfici trimesh ed è tale else if ( nType != GEO_CURVE && ( pGObj->GetType() & GEO_SURF) != 0) { const ISurfTriMesh* pSurf = ::GetSurfTriMesh( pGObj) ; if ( pSurf == nullptr) return false ; // se direttamente la superficie if ( Id.nSub == SEL_SUB_ALL) { nSubs = pSurf->GetFacetCount() ; return true ; } // altrimenti faccia di superficie trimesh else { // se faccia non esistente if ( Id.nSub > pSurf->GetFacetCount()) return false ; // tutto bene nSubs = 0 ; return true ; } } // altrimenti errore else return false ; } //---------------------------------------------------------------------------- ICurve* Sawing::GetCurve( SelData Id) { // ammessi : curve o facce di polymesh const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ; if ( pGObj == nullptr) return nullptr ; // ne recupero il riferimento globale Frame3d frGlob ; if ( ! m_pGeomDB->GetGlobFrame( Id.nId, frGlob)) return nullptr ; // se curva if ( ( pGObj->GetType() & GEO_CURVE) != 0) { PtrOwner pCurve ; // se direttamente curva if ( Id.nSub == SEL_SUB_ALL) { // recupero e duplico la curva const ICurve* pOriCurve = ::GetCurve( pGObj) ; if ( pOriCurve != nullptr) pCurve.Set( pOriCurve->Clone()) ; } // altrimenti sottocurva di composita else { // recupero la composita const ICurveComposite* pCompo = GetCurveComposite( pGObj) ; 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 ; // la porto in globale pCurve->ToGlob( frGlob) ; // la restituisco return Release( pCurve) ; } // se altrimenti superficie else if ( ( pGObj->GetType() & GEO_SURF) != 0) { // recupero la trimesh const ISurfTriMesh* pSurf = ::GetSurfTriMesh( pGObj) ; if ( pSurf == nullptr) return nullptr ; // recupero l'indice della faccia int nFacet = ( ( Id.nSub == SEL_SUB_ALL) ? 0 : Id.nSub) ; // recupero i contorni della faccia POLYLINEVECTOR vPL ; pSurf->GetFacetLoops( nFacet, vPL) ; if ( vPL.empty()) return nullptr ; // recupero la normale esterna della faccia Vector3d vtN ; if ( ! pSurf->GetFacetNormal( nFacet, vtN)) return nullptr ; // creo la curva a partire da quello esterno PtrOwner pCrvCompo( CreateCurveComposite()) ; pCrvCompo->FromPolyLine( vPL[0]) ; if ( ! pCrvCompo->IsValid()) return nullptr ; // assegno l'estrusione dalla normale alla faccia pCrvCompo->SetExtrusion( vtN) ; // unisco le eventuali parti allineate pCrvCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; // la porto in globale pCrvCompo->ToGlob( frGlob) ; // sistemazioni varie AdjustCurveFromSurf( pCrvCompo, TOOL_ORTUP, FACE_DOWN, m_TParams.m_dThick) ; // aggiusto lato lavoro e inverti, angolo di fianco e lato mandrino !!! da verificare !!! if ( m_Params.m_nWorkSide == SAW_WS_CENTER) m_Params.m_nWorkSide = SAW_WS_RIGHT ; m_Params.m_bInvert = ( m_Params.m_nWorkSide == SAW_WS_LEFT) ; double dSideAng ; Z_AX.GetAngle( vtN, dSideAng) ; // taglio verticale if ( abs( dSideAng - ANG_RIGHT) < 10 * EPS_ANG_SMALL) m_Params.m_dSideAngle = 0 ; // taglio soprasquadra else if ( dSideAng < ANG_RIGHT) { m_Params.m_dSideAngle = ANG_RIGHT - dSideAng ; m_Params.m_nHeadSide = ( m_Params.m_nWorkSide = SAW_WS_RIGHT ? SAW_HS_RIGHT : SAW_HS_LEFT) ; } // taglio sottosquadra else { m_Params.m_dSideAngle = ANG_RIGHT - dSideAng ; m_Params.m_nHeadSide = ( m_Params.m_nWorkSide = SAW_WS_RIGHT ? SAW_HS_LEFT : SAW_HS_RIGHT) ; } // la restituisco return Release( pCrvCompo) ; } // altrimenti errore else return nullptr ; } //---------------------------------------------------------------------------- bool Sawing::Chain( int nGrpDestId) { // vettore puntatori alle curve ICURVEPOVECTOR vpCrvs ; vpCrvs.reserve( m_vId.size()) ; // recupero tutte le curve e le porto in globale for ( const auto& Id : m_vId) { // prendo curva vpCrvs.emplace_back( GetCurve( Id)) ; // ne verifico la validità if ( IsNull( vpCrvs.back())) { string sOut = "Warning in Sawing : Skipped entity " + ToString( Id) ; LOG_INFO( GetEMkLogger(), sOut.c_str()) ; vpCrvs.back().Reset() ; } } // preparo i dati per il concatenamento bool bFirst = true ; Point3d ptNear = ORIG ; double dToler = 10 * EPS_SMALL ; ChainCurves chainC ; chainC.Init( true, dToler, int( vpCrvs.size())) ; for ( size_t i = 0 ; i < vpCrvs.size() ; ++ i) { // recupero la curva e il suo riferimento ICurve* pCrv = vpCrvs[i] ; if ( pCrv == nullptr) continue ; // recupero i dati della curva necessari al concatenamento e li assegno Point3d ptStart, ptEnd ; Vector3d vtStart, vtEnd ; if ( ! pCrv->GetStartPoint( ptStart) || ! pCrv->GetStartDir( vtStart) || ! pCrv->GetEndPoint( ptEnd) || ! pCrv->GetEndDir( vtEnd)) return false ; if ( ! chainC.AddCurve( int( i + 1), ptStart, vtStart, ptEnd, vtEnd)) return false ; // se prima curva, assegno inizio della ricerca if ( bFirst) { ptNear = ptStart + 10 * EPS_SMALL * vtStart ; bFirst = false ; } } // recupero i percorsi concatenati int nCount = 0 ; INTVECTOR vnId2 ; while ( chainC.GetChainFromNear( ptNear, false, vnId2)) { // creo una curva composita PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo)) return false ; // estrusione e spessore Vector3d vtExtr = Z_AX ; double dThick = 0 ; // vettore Id originali SELVECTOR vId2 ; vId2.reserve( vnId2.size()) ; // recupero le curve semplici e le inserisco nella curva composita for ( size_t i = 0 ; i < vnId2.size() ; ++ i) { int nId = abs( vnId2[i]) - 1 ; bool bInvert = ( vnId2[i] < 0) ; vId2.emplace_back( m_vId[nId]) ; // recupero la curva ICurve* pCrv = vpCrvs[nId] ; // se necessario, la inverto if ( bInvert) pCrv->Invert() ; // recupero eventuali estrusione e spessore Vector3d vtTemp ; if ( pCrv->GetExtrusion( vtTemp)) { vtExtr = vtTemp ; double dTemp ; if ( pCrv->GetThickness( dTemp) && fabs( dTemp) > fabs( dThick)) dThick = dTemp ; } // la aggiungo alla curva composta if ( ! pCrvCompo->AddCurve( ::Release( vpCrvs[nId]), true, dToler)) return false ; } // se non sono state inserite curve, vado oltre if ( pCrvCompo->GetCurveCount() == 0) continue ; // imposto estrusione e spessore pCrvCompo->SetExtrusion( vtExtr) ; pCrvCompo->SetThickness( dThick) ; // aggiorno il nuovo punto vicino pCrvCompo->GetEndPoint( ptNear) ; // creo nuovo gruppo int nPathId = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrpDestId, Frame3d()) ; if ( nPathId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPathId, MCH_PATH + ToString( ++ nCount)) ; m_pGeomDB->SetInfo( nPathId, KEY_IDS, ToString( vId2)) ; // inserisco la curva composita nel gruppo destinazione int nNewId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, ::Release( pCrvCompo)) ; if ( nNewId == GDB_ID_NULL) return false ; } return true ; } //---------------------------------------------------------------------------- bool Sawing::VerifySideAngle( void) { // verifiche per angolo di sbandamento if ( abs( m_Params.m_dSideAngle) > EPS_ANG_SMALL) { // non ammesso lato di lavoro in centro if ( m_Params.m_nWorkSide == SAW_WS_CENTER) { m_pMchMgr->SetLastError( 2202, "Error in Sawing : Center work not allowed with side angle") ; return false ; } // se angolo esterno lato mandrino deve uguagliare lato di lavoro if ( m_Params.m_dSideAngle > 0) { if ( m_Params.m_nWorkSide == SAW_WS_RIGHT) { if ( m_Params.m_nHeadSide == SAW_HS_LEFT) { m_pMchMgr->SetLastError( 2203, "Error in Sawing : External side angle HeadSide must equal WorkSide") ; m_Params.m_nHeadSide = SAW_HS_RIGHT ; } } if ( m_Params.m_nWorkSide == SAW_WS_LEFT) { if ( m_Params.m_nHeadSide == SAW_HS_RIGHT) { m_pMchMgr->SetLastError( 2203, "Error in Sawing : External side angle HeadSide must equal WorkSide") ; m_Params.m_nHeadSide = SAW_HS_LEFT ; } } } // altrimenti angolo interno, lato mandrino deve essere opposto a lato di lavoro else { if ( m_Params.m_nWorkSide == SAW_WS_RIGHT) { if ( m_Params.m_nHeadSide == SAW_HS_RIGHT) { m_pMchMgr->SetLastError( 2204, "Error in Sawing : Internal side angle HeadSide must opposite WorkSide") ; m_Params.m_nHeadSide = SAW_HS_LEFT ; } } if ( m_Params.m_nWorkSide == SAW_WS_LEFT) { if ( m_Params.m_nHeadSide == SAW_HS_LEFT) { m_pMchMgr->SetLastError( 2204, "Error in Sawing : Internal side angle HeadSide must opposite WorkSide") ; m_Params.m_nHeadSide = SAW_HS_RIGHT ; } } } } return true ; } //---------------------------------------------------------------------------- bool Sawing::ProcessPath( int nPathId, int nPvId, int nClId) { // recupero gruppo per geometria temporanea const string GRP_TEMP = "Temp" ; int nTempId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, GRP_TEMP) ; // se non c'è, lo aggiungo if ( nTempId == GDB_ID_NULL) { nTempId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; if ( nTempId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nTempId, GRP_TEMP) ; } // altrimenti lo svuoto else m_pGeomDB->EmptyGroup( nTempId) ; // in ogni caso lo dichiaro temporaneo e non visibile m_pGeomDB->SetLevel( nTempId, GDB_LV_TEMP) ; m_pGeomDB->SetStatus( nTempId, GDB_ST_OFF) ; // copio la curva composita da elaborare int nCrvId = m_pGeomDB->GetFirstInGroup( nPathId) ; if ( m_pGeomDB->GetGeoType( nCrvId) != CRV_COMPO) return false ; int nCopyId = m_pGeomDB->CopyGlob( nCrvId, GDB_ID_NULL, nTempId) ; if ( nCopyId == GDB_ID_NULL) return false ; ICurveComposite* pCompo = GetCurveComposite( m_pGeomDB->GetGeoObj( nCopyId)) ; // unisco le parti allineate if ( ! pCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL)) return false ; // eventuale inversione percorso if ( m_Params.m_bInvert) pCompo->Invert() ; // verifico che il percorso sia abbastanza lungo double dLen ; pCompo->GetLength( dLen) ; if ( dLen + m_Params.m_dStartAddLen + m_Params.m_dEndAddLen < 10 * EPS_SMALL) { LOG_INFO( GetEMkLogger(), "Warning in Sawing : skipped Path too small") ; return true ; } // eventuali allungamenti if ( m_Params.m_dStartAddLen > EPS_SMALL) { if ( ! pCompo->ExtendStartByLen( m_Params.m_dStartAddLen)) return false ; dLen += m_Params.m_dStartAddLen ; } if ( m_Params.m_dEndAddLen > EPS_SMALL) { if ( ! pCompo->ExtendEndByLen( m_Params.m_dEndAddLen)) return false ; dLen += m_Params.m_dEndAddLen ; } // eventuale accorciamenti (da fare dopo tutti gli allungamenti) if ( m_Params.m_dStartAddLen < - EPS_SMALL) { if ( ! pCompo->TrimStartAtLen( - m_Params.m_dStartAddLen)) return false ; dLen += m_Params.m_dStartAddLen ; } if ( m_Params.m_dEndAddLen < - EPS_SMALL) { if ( ! pCompo->TrimEndAtLen( dLen + m_Params.m_dEndAddLen)) return false ; dLen += m_Params.m_dEndAddLen ; } // elaboro la curva composita e la esplodo nelle curve componenti if ( m_Params.m_nCurveUse == SAW_CRV_APPROX || m_Params.m_nCurveUse == SAW_CRV_CONVEX) { // calcolo l'approssimazione lineare con eventuale convessità PolyLine PL ; int nType = ICurve::APL_STD ; if ( m_Params.m_nWorkSide == SAW_WS_LEFT) nType = (( m_Params.m_nCurveUse == SAW_CRV_APPROX) ? ICurve::APL_LEFT : ICurve::APL_LEFT_CONVEX) ; else if ( m_Params.m_nWorkSide == SAW_WS_RIGHT) nType = (( m_Params.m_nCurveUse == SAW_CRV_APPROX) ? ICurve::APL_RIGHT : ICurve::APL_RIGHT_CONVEX) ; if ( ! pCompo->ApproxWithLines( m_Params.m_dApprox, ANG_RIGHT, nType, PL)) return false ; // salvo estrusione e spessore Vector3d vtExtr ; pCompo->GetExtrusion( vtExtr) ; double dThick ; pCompo->GetThickness( dThick) ; // sostituisco la curva composita con la sua approssimazione if ( ! pCompo->Clear() || ! pCompo->FromPolyLine( PL)) return false ; // assegno estrusione e spessore originali pCompo->SetExtrusion( vtExtr) ; pCompo->SetThickness( dThick) ; } // se lama non centrata e richiesto, eseguo offset if ( m_Params.m_nWorkSide != SAW_WS_CENTER && fabs( GetOffsL()) > EPS_SMALL) { double dOffs = ( m_Params.m_nWorkSide == SAW_WS_RIGHT) ? GetOffsL() : - GetOffsL() ; if ( ! pCompo->SimpleOffset( dOffs, ICurve::OFF_EXTEND)) return false ; } // recupero estrusione e spessore Vector3d vtExtr ; pCompo->GetExtrusion( vtExtr) ; double dThick ; pCompo->GetThickness( dThick) ; // recupero distanza da fondo dei grezzi interessati dal percorso double dRbDist ; double dToler = 2 * m_TParams.m_dThick + tan( abs( m_Params.m_dSideAngle) * DEGTORAD) * m_TParams.m_dMaxMat ; if ( ! GetDistanceFromRawBottom( m_nPhase, nCopyId, dToler, dRbDist)) return false ; // valuto l'espressione dell'affondamento ExeLuaSetGlobNumVar( "TH", abs( dThick)) ; ExeLuaSetGlobNumVar( "RB", dRbDist) ; double dDepth ; string sMyDepth = m_Params.m_sDepth ; if ( ! ExeLuaEvalNumExpr( ToUpper( sMyDepth), &dDepth)) { m_pMchMgr->SetLastError( 2205, "Error in Sawing : Depth not computable") ; return false ; } // se spessore positivo, lo sottraggo dal risultato if ( dThick * vtExtr.z > 0) dDepth -= dThick ; // determino l'eccesso di taglio double dExtraCut = max( 0., dDepth - dRbDist) ; // determino la quota dal fondo del grezzo double dRbHeight = dRbDist - dDepth ; // correzione per angolo di fianco if ( abs( m_Params.m_dSideAngle) > EPS_ANG_SMALL) { // generale double dCoeff = 1 / cos( m_Params.m_dSideAngle * DEGTORAD) ; dDepth *= dCoeff ; dExtraCut *= dCoeff ; // se sottosquadra (controllo il lato opposto della lama, quindi ...) if ( m_Params.m_dSideAngle < 0) { dDepth += m_TParams.m_dThick * tan( abs( m_Params.m_dSideAngle) * DEGTORAD) ; dRbHeight -= m_TParams.m_dThick * sin( abs( m_Params.m_dSideAngle) * DEGTORAD) ; } } // verifico di non superare il massimo materiale if ( dDepth > m_TParams.m_dMaxMat) { string sOut = "Error in Sawing : machining depth (" + ToString( dDepth, 1) + ") bigger than MaxMaterial (" + ToString( m_TParams.m_dMaxMat, 1) + ")" ; m_pMchMgr->SetLastError( 2206, sOut.c_str()) ; return false ; } // recupero nome del path string sPathName ; m_pGeomDB->GetName( nPathId, sPathName) ; // verifiche sull'ampiezza dell'angolo al centro degli eventuali archi VerifyArcs( pCompo, 2 * MAX_ANG_CEN) ; // flag di curva chiusa bool bClosed = pCompo->IsClosed() ; // calcolo gli eventuali punti di perdita di tangenza e di cambio di concavità DBLVECTOR vU ; const double ANG_PERD_TG = 1.0 ; const ICurveArc* pArc = ( bClosed ? GetCurveArc( pCompo->GetLastCurve()) : nullptr) ; int nCurrConv = ( pArc != nullptr ? ( pArc->GetAngCenter() > 0 ? 1 : - 1) : 0) ; for ( int i = ( bClosed ? 0 : 1) ; i < pCompo->GetCurveCount() ; ++ i) { // verifico perdita di tangenza Point3d ptPrev, ptNext ; Vector3d vtPrev, vtNext ; if ( pCompo->GetPointTang( i, ICurve::FROM_MINUS, ptPrev, vtPrev) && pCompo->GetPointTang( i, ICurve::FROM_PLUS, ptNext, vtNext) && vtPrev * vtNext < cos( ANG_PERD_TG * DEGTORAD)) { vU.push_back( i) ; nCurrConv = 0 ; continue ; } // verifico cambio di concavità e/o lavorazione interna const ICurve* pCrv = pCompo->GetCurve( i) ; if ( pCrv->GetType() == CRV_ARC) { if ( GetCurveArc( pCrv)->GetAngCenter() > 0) { if ( nCurrConv == - 1 || m_Params.m_nWorkSide == SAW_WS_LEFT) vU.push_back( i) ; nCurrConv = 1 ; } else { if ( nCurrConv == 1 || m_Params.m_nWorkSide == SAW_WS_RIGHT) vU.push_back( i) ; nCurrConv = - 1 ; } } } // creo i tratti di curva continui e uniformi ICURVEPOVECTOR vpCrvs ; vpCrvs.reserve( vU.size() + 2) ; if ( vU.size() == 0) vpCrvs.emplace_back( pCompo->Clone()) ; else { if ( bClosed) { vpCrvs.emplace_back( pCompo->CopyParamRange( vU.back(), vU.front())) ; for ( int i = 1 ; i < int( vU.size()) ; ++ i) vpCrvs.emplace_back( pCompo->CopyParamRange( vU[i-1], vU[i])) ; } else { vpCrvs.emplace_back( pCompo->CopyParamRange( 0, vU.front())) ; for ( int i = 1 ; i < int( vU.size()) ; ++ i) vpCrvs.emplace_back( pCompo->CopyParamRange( vU[i-1], vU[i])) ; vpCrvs.emplace_back( pCompo->CopyParamRange( vU.back(), pCompo->GetCurveCount())) ; } } // ciclo sulle curve int nMaxInd = int( vpCrvs.size()) - 1 ; for ( int i = 0 ; i <= nMaxInd ; ++ i) { // curva precedente const ICurve* pCrvP = nullptr ; if ( i > 0) pCrvP = vpCrvs[i - 1] ; else if ( bClosed) pCrvP = vpCrvs[nMaxInd] ; // curva corrente const ICurve* pCrvC = vpCrvs[i] ; // curva successiva const ICurve* pCrvN = nullptr ; if ( i < nMaxInd) pCrvN = vpCrvs[i + 1] ; else if ( bClosed) pCrvN = vpCrvs[0] ; // elaborazioni sulla curva corrente string sName = sPathName + "_" + ToString( i) ; if ( ! ProcessEntity( pCrvP, pCrvC, pCrvN, dDepth, dExtraCut, dRbHeight, i == 0, i == nMaxInd, sName, nPvId, nClId)) return false ; } return true ; } //---------------------------------------------------------------------------- bool Sawing::ProcessEntity( const ICurve* pCrvP, const ICurve* pCrvC, const ICurve* pCrvN, double dDepth, double dExtraCut, double dRbHeight, bool bIsFirst, bool bIsLast, const string& sName, int nPvId, int nClId) { // la curva corrente deve essere una composita const ICurveComposite* pCompo = GetCurveComposite( pCrvC) ; if ( pCompo == nullptr) return false ; // se formata da una sola linea if ( pCompo->GetCurveCount() == 1 && pCompo->GetFirstCurve()->GetType() == CRV_LINE) { const ICurveLine* pLine = GetCurveLine( pCompo->GetFirstCurve()) ; if ( pLine == nullptr) return false ; return ProcessLine( pCrvP, pLine, pCrvN, dDepth, dExtraCut, dRbHeight, bIsFirst, bIsLast, sName, nPvId, nClId) ; } // altrimenti else { if ( m_Params.m_nCurveUse == SAW_CRV_KEEP) { // verifico che non ci sia angolo di fianco if ( abs( m_Params.m_dSideAngle) > EPS_ANG_SMALL) { m_pMchMgr->SetLastError( 2207, "Error in Sawing : SideAngle not allowed on Arc") ; return false ; } // determino la convessità int nConv = 0 ; for ( int i = 0 ; i < pCompo->GetCurveCount() ; ++ i) { const ICurveArc* pArc = GetCurveArc( pCompo->GetCurve( i)) ; if ( pArc != nullptr) { nConv = ( pArc->GetAngCenter() > 0 ? 1 : - 1) ; break ; } } // se curva lavorata dall'esterno if ( ( nConv > 0 && m_Params.m_nWorkSide == SAW_WS_RIGHT) || ( nConv < 0 && m_Params.m_nWorkSide == SAW_WS_LEFT)) return ProcessExtCurve( pCrvP, pCompo, pCrvN, dDepth, dExtraCut, dRbHeight, bIsFirst, bIsLast, sName, nPvId, nClId) ; // altrimenti curva lavorata dall'interno else { // deve essere un solo arco const ICurveArc* pArc = GetCurveArc( pCompo->GetFirstCurve()) ; if ( pArc == nullptr || pCompo->GetCurveCount() != 1) return false ; // eseguo return ProcessIntArc( pCrvP, pArc, pCrvN, dDepth, dExtraCut, dRbHeight, bIsFirst, bIsLast, sName, nPvId, nClId) ; } } else { LOG_INFO( GetEMkLogger(), "Warning in Sawing : Skipped Arc") ; return true ; } } } //---------------------------------------------------------------------------- bool Sawing::ProcessLine( const ICurve* pCrvP, const ICurveLine* pLineC, const ICurve* pCrvN, double dDepth, double dExtraCut, double dRbHeight, bool bIsFirst, bool bIsLast, const string& sName, int nPvId, int nClId) { // copio la curva PtrOwner pLine( pLineC->Clone()) ; if ( IsNull( pLine)) return false ; // direzione linea corrente Vector3d vtDirC ; pLine->GetStartDir( vtDirC) ; // calcolo i versori fresa e correzione Vector3d vtTool, vtCorr ; if ( ! CalculateToolAndCorrVersors( vtDirC, m_Params.m_nHeadSide, m_Params.m_nWorkSide, m_Params.m_dSideAngle, vtTool, vtCorr)) { m_pMchMgr->SetLastError( 2208, "Error in Sawing : Entity CalculateToolAndCorrVersors") ; return false ; } // correzioni per lato lama, lato mandrino if ( ! AdjustForSide( pLine)) { m_pMchMgr->SetLastError( 2209, "Error in Sawing : Entity AdjustForSide") ; return false ; } // aggiungo affondamento pLine->Translate( - vtCorr * dDepth) ; // calcolo elevazione (sui due bordi della striscia, leggermente allargata) double dElev, dElev2 ; Vector3d vtToolH( vtTool.x, vtTool.y, 0) ; Vector3d vtSafe = vtToolH * ( 10 * EPS_SMALL) ; Vector3d vtThick = vtToolH * ( m_TParams.m_dThick / vtToolH.SqLen() + 10 * EPS_SMALL) ; if ( ! GetElevation( m_nPhase, pLine->GetStart() - vtSafe, pLine->GetEnd() - vtSafe, vtCorr, dElev) || ! GetElevation( m_nPhase, pLine->GetStart() + vtThick, pLine->GetEnd() + vtThick, vtCorr, dElev2) ) { m_pMchMgr->SetLastError( 2210, "Error in Sawing : Entity GetElevation") ; return false ; } dElev = max( dElev, dElev2) ; // per gestire casi di taglio vicino a grezzi ma esterni ad essi if ( dElev < EPS_SMALL) dElev = max( 0., dDepth) ; // per posizionare l'anteprima alla quota standard else if ( nPvId != GDB_ID_NULL && nClId == GDB_ID_NULL) dElev = max( dElev, dDepth) ; // calcolo tipo angolo con precedente bool bExtAngPC = true ; if ( pCrvP != nullptr) { Vector3d vtDirP ; pCrvP->GetEndDir( vtDirP) ; double dAngPC ; vtDirP.GetAngleXY( vtDirC, dAngPC) ; if ( ( m_Params.m_nWorkSide == SAW_WS_LEFT && dAngPC > EPS_ANG_SMALL) || ( m_Params.m_nWorkSide == SAW_WS_RIGHT && dAngPC < - EPS_ANG_SMALL)) bExtAngPC = false ; } // calcolo tipo angolo con successivo bool bExtAngCN = true ; if ( pCrvN != nullptr) { Vector3d vtDirN ; pCrvN->GetStartDir( vtDirN) ; double dAngCN ; vtDirC.GetAngleXY( vtDirN, dAngCN) ; if ( ( m_Params.m_nWorkSide == SAW_WS_LEFT && dAngCN > EPS_ANG_SMALL) || ( m_Params.m_nWorkSide == SAW_WS_RIGHT && dAngCN < - EPS_ANG_SMALL)) bExtAngCN = false ; } // aggiusto per tipo estremi bool bToSkip = false ; double dDeltaLiExt = 0, dDeltaLoExt = 0 ; if ( ! AdjustLineForEdges( pLine, dElev, vtCorr, vtThick, bIsFirst, bIsLast, bExtAngPC, bExtAngCN, bToSkip, dDeltaLiExt, dDeltaLoExt)) { m_pMchMgr->SetLastError( 2211, "Error in Sawing : Entity AdjustForEdges") ; return false ; } if ( bToSkip) { LOG_INFO( GetEMkLogger(), "Warning in Sawing : skipped Entity too small") ; return true ; } // Se richiesto Preview if ( nPvId != GDB_ID_NULL) { if ( ! GenerateLinePv( pLine, vtTool, vtCorr, dElev, dExtraCut, dRbHeight, sName, nPvId)) return false ; } // Se richiesta geometria di lavorazione if ( nClId != GDB_ID_NULL) { if ( ! GenerateLineCl( pLine, vtTool, vtCorr, dElev, dExtraCut, sName, dDeltaLiExt, dDeltaLoExt, nClId)) return false ; } // incremento numero di tagli ++ m_nCuts ; return true ; } //---------------------------------------------------------------------------- bool Sawing::GenerateLinePv( const ICurveLine* pLine, const Vector3d& vtTool, const Vector3d& vtCorr, double dElev, double dExtraCut, double dRbHeight, const string& sName, int nPvId) { // creo gruppo per anteprima di lavorazione della linea int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nPvId, Frame3d()) ; if ( nPxId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPxId, sName) ; m_pGeomDB->SetMaterial( nPxId, BLUE) ; // punti notevoli Point3d ptIni = pLine->GetStart() + dElev * vtCorr ; Point3d ptEnd = pLine->GetEnd() + dElev * vtCorr ; Vector3d vtToolH( vtTool.x, vtTool.y, 0) ; vtToolH *= m_TParams.m_dThick / vtToolH.SqLen() ; Point3d ptCross = ptEnd + vtToolH ; Vector3d vtDZ( 0, 0, 0.1) ; // distanza XY tra centro e bordo taglio double dDeltaT = (( dElev < 0.5 * m_TParams.m_dDiam) ? sqrt( dElev * m_TParams.m_dDiam - dElev * dElev) : 0) ; // direzione del taglio Vector3d vtDir ; pLine->GetStartDir( vtDir) ; // colore taglio, dipendente da angolo di inclinazione Color colCut = LIME ; if ( abs( m_Params.m_dSideAngle) > EPS_ANG_SMALL) colCut = FUCHSIA ; // disabilito eventuale registrazione comandi EXE (riabilitazione automatica) CmdLogOff cmdLogOff ; // rettangolo per parte di taglio completo int nId = ExeCreateRectangle3P( nPxId, ptIni + vtDZ, ptCross + vtDZ, ptEnd + vtDZ, RTY_LOC) ; m_pGeomDB->SetName( nId, MCH_PV_CUT) ; m_pGeomDB->SetMaterial( nId, colCut) ; // rettangolo per parte parziale iniziale int nId2 = ExeCreateRectangle3P( nPxId, ptIni - vtDir * dDeltaT, ptIni + vtToolH, ptIni, RTY_LOC) ; // assegno nome e colore m_pGeomDB->SetName( nId2, MCH_PV_PRE_CUT) ; m_pGeomDB->SetMaterial( nId2, BLUE) ; // rettangolo per parte parziale finale int nId3 = ExeCreateRectangle3P( nPxId, ptEnd, ptCross + vtDir * dDeltaT, ptEnd + vtDir * dDeltaT, RTY_LOC) ; // assegno nome e colore m_pGeomDB->SetName( nId3, MCH_PV_POST_CUT) ; m_pGeomDB->SetMaterial( nId3, BLUE) ; // valore di allungamento double dExtraL = m_pMchMgr->GetCurrMachiningsMgr()->GetExtraLOnCutRegion() ; // punti notevoli per regioni Point3d ptRIni = ptIni ; Point3d ptRCross = ptCross ; Point3d ptREnd = ptEnd ; Vector3d vtRToolH = vtToolH ; // allargamento per taglio sottosquadra (WorkSide e HeadSide sempre opposti) if ( m_Params.m_dSideAngle < - EPS_ANG_SMALL) { Vector3d vtOrtho = vtToolH ; vtOrtho.Normalize() ; ptRIni -= vtOrtho * dExtraL ; ptREnd -= vtOrtho * dExtraL ; vtRToolH += vtOrtho * dExtraL ; } // regione di taglio completo per nesting int nRId = ExeCreateSurfFrRectangle3P( nPxId, ptRIni - vtDir * ( dDeltaT + dExtraL), ptRCross + vtDir * ( dDeltaT + dExtraL), ptREnd, RTY_LOC) ; m_pGeomDB->SetName( nRId, MCH_PV_RCUT) ; m_pGeomDB->SetMaterial( nRId, INVISIBLE) ; // regione di taglio ridotto per nesting (sono escluse le parti iniziale e finale) const double EXTRALEN_R = 10 * EPS_SMALL ; int nRrId = ExeCreateSurfFrRectangle3P( nPxId, ptRIni - vtDir * EXTRALEN_R, ptRCross + vtDir * EXTRALEN_R, ptREnd, RTY_LOC) ; m_pGeomDB->SetName( nRrId, MCH_PV_RRCUT) ; m_pGeomDB->SetMaterial( nRrId, INVISIBLE) ; // regione di ingresso al taglio (parte iniziale) int nRsId = ExeCreateSurfFrRectangle3P( nPxId, ptRIni - vtDir * ( dDeltaT + dExtraL), ptRIni + vtRToolH, ptRIni, RTY_LOC) ; m_pGeomDB->SetName( nRsId, MCH_PV_RLICUT) ; m_pGeomDB->SetMaterial( nRsId, INVISIBLE) ; // regione di uscita dal taglio (parte finale) int nReId = ExeCreateSurfFrRectangle3P( nPxId, ptREnd, ptRCross + vtDir * ( dDeltaT + dExtraL), ptREnd + vtDir * ( dDeltaT + dExtraL) , RTY_LOC) ; m_pGeomDB->SetName( nReId, MCH_PV_RLOCUT) ; m_pGeomDB->SetMaterial( nReId, INVISIBLE) ; // eventuali ripetizioni in basso per tagli inclinati if ( abs( m_Params.m_dSideAngle) > EPS_ANG_SMALL) { // lunghezza movimento double dMove = ( dElev - dExtraCut) ; // se sottosquadra (controllo il lato opposto della lama, quindi ...) if ( m_Params.m_dSideAngle < 0) dMove -= m_TParams.m_dThick * tan( abs( m_Params.m_dSideAngle) * DEGTORAD) ; // vettore movimento Vector3d vtMove = - dMove * vtCorr ; vtMove.z = 0 ; // rettangolo per parte di taglio completo int nDwnId = ExeCreateRectangle3P( nPxId, ptIni + vtDZ, ptCross + vtMove + vtDZ, ptEnd + vtDZ, RTY_LOC) ; m_pGeomDB->SetName( nDwnId, MCH_PV_DOWN_CUT) ; m_pGeomDB->SetMaterial( nDwnId, colCut) ; // rettangolo per parte parziale iniziale int nDwnId2 = ExeCreateRectangle3P( nPxId, ptIni - vtDir * dDeltaT, ptIni + vtToolH + vtMove, ptIni, RTY_LOC) ; m_pGeomDB->SetName( nDwnId2, MCH_PV_DOWN_PRE_CUT) ; m_pGeomDB->SetMaterial( nDwnId2, BLUE) ; // rettangolo per parte parziale finale int nDwnId3 = ExeCreateRectangle3P( nPxId, ptEnd, ptCross + vtDir * dDeltaT + vtMove, ptEnd + vtDir * dDeltaT, RTY_LOC) ; m_pGeomDB->SetName( nDwnId3, MCH_PV_DOWN_POST_CUT) ; m_pGeomDB->SetMaterial( nDwnId3, BLUE) ; // regione di taglio completo per nesting int nDwnRId = m_pGeomDB->Copy( nRId, GDB_ID_NULL, nPxId) ; m_pGeomDB->Translate( nDwnRId, vtMove) ; m_pGeomDB->SetName( nDwnRId, MCH_PV_DOWN_RCUT) ; // regione di taglio ridotto per nesting (sono escluse le parti iniziale e finale) int nDwnRrId = m_pGeomDB->Copy( nRrId, GDB_ID_NULL, nPxId) ; m_pGeomDB->Translate( nDwnRrId, vtMove) ; m_pGeomDB->SetName( nDwnRrId, MCH_PV_DOWN_RRCUT) ; // regione di ingresso al taglio (parte iniziale) int nDwnRsId = m_pGeomDB->Copy( nRsId, GDB_ID_NULL, nPxId) ; m_pGeomDB->Translate( nDwnRsId, vtMove) ; m_pGeomDB->SetName( nDwnRsId, MCH_PV_DOWN_RLICUT) ; // regione di uscita dal taglio (parte finale) int nDwnReId = m_pGeomDB->Copy( nReId, GDB_ID_NULL, nPxId) ; m_pGeomDB->Translate( nDwnReId, vtMove) ; m_pGeomDB->SetName( nDwnReId, MCH_PV_DOWN_RLOCUT) ; } // salvo in info gruppo : larghezza XY del taglio, distanza XY tra centro e bordo taglio, extra taglio e quota minima della lama m_pGeomDB->SetInfo( nPxId, MCH_PV_KEY_WT, vtToolH.LenXY()) ; m_pGeomDB->SetInfo( nPxId, MCH_PV_KEY_DT, dDeltaT) ; m_pGeomDB->SetInfo( nPxId, MCH_PV_KEY_EC, dExtraCut) ; m_pGeomDB->SetInfo( nPxId, MCH_PV_KEY_RBH, dRbHeight) ; return true ; } //---------------------------------------------------------------------------- bool Sawing::GenerateLineCl( const ICurveLine* pLine, const Vector3d& vtTool, const Vector3d& vtCorr, double dElev, double dExtraCut, const string& sName, double dDeltaLiExt, double dDeltaLoExt, int nClId) { // creo gruppo per geometria di lavorazione della linea int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ; if ( nPxId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPxId, sName) ; m_pGeomDB->SetMaterial( nPxId, BLUE) ; // assegno il vettore estrazione al gruppo del percorso m_pGeomDB->SetInfo( nPxId, KEY_EXTR, Vector3d( 0, 0, 1)) ; // assegno i punti di inizio e fine al gruppo del percorso m_pGeomDB->SetInfo( nPxId, KEY_START, pLine->GetStart()) ; m_pGeomDB->SetInfo( nPxId, KEY_END, pLine->GetEnd()) ; // assegno l'elevazione massima m_pGeomDB->SetInfo( nPxId, KEY_ELEV, dElev) ; // assegno delta per taglio esteso al bordo grezzo m_pGeomDB->SetInfo( nPxId, KEY_DELTALIEXT, dDeltaLiExt) ; m_pGeomDB->SetInfo( nPxId, KEY_DELTALOEXT, dDeltaLoExt) ; // Imposto dati comuni SetPathId( nPxId) ; SetToolDir( vtTool) ; SetCorrAuxDir( vtCorr) ; // recupero distanza di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; if ( abs( m_Params.m_dSideAngle) > EPS_ANG_SMALL) dAppr /= cos( m_Params.m_dSideAngle * DEGTORAD) ; // valore di step double dActStep = m_Params.m_dStep ; if ( abs( m_Params.m_dSideAngle) > 10 * EPS_ANG_SMALL) dActStep = GetStepSideAng() ; // Se una sola passata if ( dActStep < EPS_SMALL || ( dElev - dExtraCut) <= dActStep) { // 1 -> approccio if ( ! AddApproach( pLine->GetStart(), vtCorr, dSafeZ, dElev, dAppr)) return false ; // 2 -> movimento in affondo al punto iniziale SetFlag( 0) ; SetFeed( GetTipFeed()) ; Point3d ptP2 = pLine->GetStart() ; if ( AddLinearMove( ptP2) == GDB_ID_NULL) return false ; // 3 -> movimento di lato al punto finale SetFeed( GetFeed()) ; Point3d ptP3 = pLine->GetEnd() ; if ( AddLinearMove( ptP3) == GDB_ID_NULL) return false ; // 4 -> retrazione if ( ! AddRetract( pLine->GetEnd(), vtCorr, dSafeZ, dElev, dAppr)) return false ; } // Se step a Zig-Zag o ToAndFrom else if ( m_Params.m_nStepType == SAW_ST_ZIGZAG || m_Params.m_nStepType == SAW_ST_TOANDFROM) { // 1 -> approccio if ( ! AddApproach( pLine->GetStart(), vtCorr, dSafeZ, dElev, dAppr)) return false ; // 2-3 -> lavorazione (sempre numero pari di passate) // calcolo numero e valore degli step double dCutH = dElev - dExtraCut ; int nStep = 2 ; if ( m_Params.m_nStepType == SAW_ST_ZIGZAG) { nStep = static_cast( ceil( dCutH / ( dActStep + EPS_SMALL))) ; if ( ( nStep % 2) == 1) nStep += 1 ; } double dStep = dCutH / nStep ; // esecuzione degli step for ( int i = nStep - 1 ; i >= 0 ; -- i) { // distanza dal fondo double dDelta = ( ( i != 0) ? dExtraCut + i * dStep : 0) ; // estremi del movimento (dispari vanno, pari tornano) Point3d ptP2 = pLine->GetStart() + vtCorr * dDelta ; Point3d ptP3 = pLine->GetEnd() + vtCorr * dDelta ; if ( ( i % 2) == 0) swap( ptP2, ptP3) ; // movimento in affondo SetFlag( 0) ; SetFeed( GetTipFeed()) ; if ( AddLinearMove( ptP2) == GDB_ID_NULL) return false ; // movimento di lato SetFeed( GetFeed()) ; if ( AddLinearMove( ptP3) == GDB_ID_NULL) return false ; } // 4 -> retrazione if ( ! AddRetract( pLine->GetStart(), vtCorr, dSafeZ, dElev, dAppr)) return false ; } // Altrimenti step a una via else { // 1 -> approccio if ( ! AddApproach( pLine->GetStart(), vtCorr, dSafeZ, dElev, dAppr)) return false ; // 2-3 -> lavorazione // calcolo numero e valore degli step double dCutH = dElev - dExtraCut ; int nStep = static_cast( ceil( dCutH / ( dActStep + EPS_SMALL))) ; double dStep = dCutH / nStep ; // esecuzione degli step for ( int i = nStep - 1 ; i >= 0 ; -- i) { // distanza dal fondo double dDelta = ( ( i != 0) ? dExtraCut + i * dStep : 0) ; // movimento in affondo al punto iniziale SetFlag( 0) ; SetFeed( GetTipFeed()) ; Point3d ptP2 = pLine->GetStart() + vtCorr * dDelta ; if ( AddLinearMove( ptP2) == GDB_ID_NULL) return false ; // movimento di lato al punto finale SetFeed( GetFeed()) ; Point3d ptP3 = pLine->GetEnd() + vtCorr * dDelta ; if ( AddLinearMove( ptP3) == GDB_ID_NULL) return false ; // se non è ultimo passo if ( i != 0) { // movimento di risalita sopra il punto finale SetFeed( GetEndFeed()) ; Point3d ptP4 = pLine->GetEnd() + vtCorr * ( dElev + dAppr) ; if ( AddLinearMove( ptP4) == GDB_ID_NULL) return false ; // movimento di ritorno spora il punto iniziale SetFeed( GetEndFeed()) ; Point3d ptP5 = pLine->GetStart() + vtCorr * ( dElev + dAppr) ; if ( AddLinearMove( ptP5) == GDB_ID_NULL) return false ; } } // 4 -> retrazione if ( ! AddRetract( pLine->GetEnd(), vtCorr, dSafeZ, dElev, dAppr)) return false ; } return true ; } //---------------------------------------------------------------------------- bool Sawing::ProcessExtCurve( const ICurve* pCrvP, const ICurveComposite* pCrvC, const ICurve* pCrvN, double dDepth, double dExtraCut, double dRbHeight, bool bIsFirst, bool bIsLast, const string& sName, int nPvId, int nClId) { // copio la curva PtrOwner pCrv( pCrvC->Clone()) ; if ( IsNull( pCrv)) return false ; // verifico che il raggio di ogni arco componente sia superiore al minimo double dMinRad = INFINITO ; for ( const ICurve* pSmpCrv = pCrv->GetFirstCurve() ; pSmpCrv != nullptr ; pSmpCrv = pCrv->GetNextCurve()) { if ( pSmpCrv->GetType() == CRV_ARC) { double dRad = GetCurveArc( pSmpCrv)->GetRadius() ; if ( dRad < dMinRad) dMinRad = dRad ; } } if ( dMinRad < m_pMchMgr->GetCurrMachiningsMgr()->GetExtSawArcMinRad()) { LOG_INFO( GetEMkLogger(), "Warning in Sawing : Radius too small in ExtSawArc") ; return true ; } // se richiesta generazione, verifico limite standard angolo al centro archi if ( nClId != GDB_ID_NULL) VerifyArcs( pCrv) ; // se curva chiusa ne forzo il punto di partenza a Xmax ( per limiti corse assi C Omag) if ( pCrv->IsClosed()) { BBox3d b3Crv ; pCrv->GetLocalBBox( b3Crv) ; Point3d ptTest = 0.5 * ( b3Crv.GetMin() + b3Crv.GetMax()) + Point3d( 100000, 0, 0) ; DistPointCurve dstPtCurve( ptTest, *pCrv) ; double dU ; int nFlag ; if ( dstPtCurve.GetParamAtMinDistPoint( 0, dU, nFlag)) { dU = 0.1 * round( 10 * dU) ; pCrv->ChangeStartPoint( dU) ; pCrvP = pCrv ; pCrvN = pCrv ; } } // correzioni per lato lama, lato mandrino if ( ! AdjustForSide( pCrv)) { m_pMchMgr->SetLastError( 2209, "Error in Sawing : Entity AdjustForSide") ; return false ; } // aggiungo affondamento (sempre in Z globale) pCrv->Translate( - Z_AX * dDepth) ; // calcolo elevazione (sui due bordi della striscia) double dElev = 0 ; for ( const ICurve* pSmpCrv = pCrv->GetFirstCurve() ; pSmpCrv != nullptr ; pSmpCrv = pCrv->GetNextCurve()) { Point3d ptSta, ptMid, ptEnd ; pSmpCrv->GetStartPoint( ptSta) ; pSmpCrv->GetMidPoint( ptMid) ; pSmpCrv->GetEndPoint( ptEnd) ; Vector3d vtStaDir, vtMidDir, vtEndDir ; pSmpCrv->GetStartDir( vtStaDir) ; pSmpCrv->GetMidDir( vtMidDir) ; pSmpCrv->GetEndDir( vtEndDir) ; Vector3d vtStaTool, vtStaCorr, vtMidTool, vtMidCorr, vtEndTool, vtEndCorr ; if ( ! CalculateToolAndCorrVersors( vtStaDir, m_Params.m_nHeadSide, m_Params.m_nWorkSide, m_Params.m_dSideAngle, vtStaTool, vtStaCorr) || ! CalculateToolAndCorrVersors( vtMidDir, m_Params.m_nHeadSide, m_Params.m_nWorkSide, m_Params.m_dSideAngle, vtMidTool, vtMidCorr) || ! CalculateToolAndCorrVersors( vtEndDir, m_Params.m_nHeadSide, m_Params.m_nWorkSide, m_Params.m_dSideAngle, vtEndTool, vtEndCorr) || ! AreSameVectorApprox( vtStaCorr, vtMidCorr) || ! AreSameVectorApprox( vtStaCorr, vtEndCorr)) { m_pMchMgr->SetLastError( 2208, "Error in Sawing : Entity CalculateToolAndCorrVersors") ; return false ; } Vector3d vtStaThick = vtStaTool * m_TParams.m_dThick ; Vector3d vtMidThick = vtMidTool * m_TParams.m_dThick ; Vector3d vtEndThick = vtEndTool * m_TParams.m_dThick ; double dElev1, dElev2 ; if ( ! GetElevation( m_nPhase, ptSta, ptMid, ptEnd, vtStaCorr, dElev1) || ! GetElevation( m_nPhase, ptSta + vtStaThick, ptMid + vtMidThick, ptEnd + vtEndThick, vtStaCorr, dElev2) ) { m_pMchMgr->SetLastError( 2210, "Error in Sawing : Entity GetElevation") ; return false ; } dElev = max( dElev, max( dElev1, dElev2)) ; } // calcolo tipo angolo con precedente bool bExtAngPC = true ; if ( pCrvP != nullptr) { Vector3d vtDirP ; pCrvP->GetEndDir( vtDirP) ; Vector3d vtStaDir ; pCrv->GetStartDir( vtStaDir) ; double dAngPC ; vtDirP.GetAngleXY( vtStaDir, dAngPC) ; if ( ( m_Params.m_nWorkSide == SAW_WS_LEFT && dAngPC > EPS_ANG_SMALL) || ( m_Params.m_nWorkSide == SAW_WS_RIGHT && dAngPC < - EPS_ANG_SMALL)) bExtAngPC = false ; } // calcolo tipo angolo con successivo bool bExtAngCN = true ; if ( pCrvN != nullptr) { Vector3d vtEndDir ; pCrv->GetEndDir( vtEndDir) ; Vector3d vtDirN ; pCrvN->GetStartDir( vtDirN) ; double dAngCN ; vtEndDir.GetAngleXY( vtDirN, dAngCN) ; if ( ( m_Params.m_nWorkSide == SAW_WS_LEFT && dAngCN > EPS_ANG_SMALL) || ( m_Params.m_nWorkSide == SAW_WS_RIGHT && dAngCN < - EPS_ANG_SMALL)) bExtAngCN = false ; } // aggiusto per tipo estremi bool bToSkip = false ; if ( ! AdjustCurveForEdges( pCrv, dElev, 1.0, bIsFirst, bIsLast, bExtAngPC, bExtAngCN, bToSkip)) { m_pMchMgr->SetLastError( 2211, "Error in Sawing : Entity AdjustForEdges") ; return false ; } if ( bToSkip) { LOG_INFO( GetEMkLogger(), "Warning in Sawing : skipped Entity too small") ; return true ; } // Se richiesto Preview if ( nPvId != GDB_ID_NULL) { if ( ! GenerateExtCurvePv( pCrv, dElev, dExtraCut, dRbHeight, sName, nPvId)) return false ; } // Se richiesta geometria di lavorazione if ( nClId != GDB_ID_NULL) { if ( ! GenerateExtCurveCl( pCrv, dElev, dExtraCut, sName, nClId)) return false ; } // incremento numero di tagli ++ m_nCuts ; return true ; } //---------------------------------------------------------------------------- bool Sawing::GenerateExtCurvePv( const ICurveComposite* pCrv, double dElev, double dExtraCut, double dRbHeight, const string& sName, int nPvId) { // creo gruppo per anteprima di lavorazione della curva int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nPvId, Frame3d()) ; if ( nPxId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPxId, sName) ; m_pGeomDB->SetMaterial( nPxId, BLUE) ; // disabilito eventuale registrazione comandi EXE (riabilitazione automatica) CmdLogOff cmdLogOff ; // dimensione da aggiungere alle regioni nelle parti in cui la lama è inclinata double dExtraL = m_pMchMgr->GetCurrMachiningsMgr()->GetExtraLOnCutRegion() ; // lunghezza taglio parziale double dDeltaT = (( dElev < 0.5 * m_TParams.m_dDiam) ? sqrt( dElev * m_TParams.m_dDiam - dElev * dElev) : 0) ; // massima larghezza di taglio double dMaxW = 0 ; // versore correzione sempre come Z+ Vector3d vtCorr = Z_AX ; // ciclo sulle curve int nMaxInd = pCrv->GetCurveCount() - 1 ; for ( int i = 0 ; i <= nMaxInd ; ++ i) { // flag per prima/ultima curva bool bFirst = ( i == 0) ; bool bLast = ( i == nMaxInd) ; // recupero curva, necessariamente linea o arco const ICurveLine* pLine = GetCurveLine( pCrv->GetCurve( i)) ; const ICurveArc* pArc = GetCurveArc( pCrv->GetCurve( i)) ; // se linea if ( pLine != nullptr) { dMaxW = max( dMaxW, m_TParams.m_dThick) ; } // se arco else if ( pArc != nullptr) { // calcolo dei raggi double dIntRad ; double dExtRad ; if ( AreHeadWorkOnSameSide()) { dIntRad = pArc->GetRadius() ; double dRadTot = pArc->GetRadius() + m_TParams.m_dThick ; dExtRad = sqrt( dRadTot * dRadTot + dDeltaT * dDeltaT) ; } else { dIntRad = pArc->GetRadius() - m_TParams.m_dThick ; dExtRad = sqrt( pArc->GetRadius() * pArc->GetRadius() + dDeltaT * dDeltaT) ; } dMaxW = max( dMaxW, dExtRad - dIntRad) ; // contorno per parte di taglio completo PtrOwner pCompo( GenerateExtArcPvTrueCut( pArc, dIntRad, dExtRad, 0)) ; if ( IsNull( pCompo)) return false ; pCompo->Translate( dElev * vtCorr + Vector3d( 0, 0, 0.1)) ; int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPxId, Release( pCompo)) ; m_pGeomDB->SetName( nId, MCH_PV_CUT) ; m_pGeomDB->SetMaterial( nId, LIME) ; // contorno per parte iniziale di taglio PtrOwner pCompo2( GenerateExtArcPvPreCut( pArc, dIntRad, dExtRad, dDeltaT, 0)) ; if ( IsNull( pCompo2)) return false ; pCompo2->Translate( dElev * vtCorr) ; int nId2 = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPxId, Release( pCompo2)) ; m_pGeomDB->SetName( nId2, ( bFirst ? MCH_PV_PRE_CUT : MCH_PV_CUT)) ; m_pGeomDB->SetMaterial( nId2, ( bFirst ? BLUE : LIME)) ; // contorno per parte finale di taglio PtrOwner pCompo3( GenerateExtArcPvPostCut( pArc, dIntRad, dExtRad, dDeltaT, 0)) ; if ( IsNull( pCompo3)) return false ; pCompo3->Translate( dElev * vtCorr) ; int nId3 = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPxId, Release( pCompo3)) ; m_pGeomDB->SetName( nId3, ( bLast ? MCH_PV_POST_CUT : MCH_PV_CUT)) ; m_pGeomDB->SetMaterial( nId3, ( bLast ? BLUE : LIME)) ; // regione ridotta di taglio per nesting (escluse parti iniziali e finali) PtrOwner pCmpRr( GenerateExtArcPvTrueCut( pArc, dIntRad, dExtRad, dExtraL)) ; if ( IsNull( pCmpRr)) return false ; SurfFlatRegionByContours SfrCntrRr ; SfrCntrRr.AddCurve( Release( pCmpRr)) ; ISurfFlatRegion* pSfrRr = SfrCntrRr.GetSurf() ; if ( pSfrRr == nullptr) return false ; pSfrRr->Translate( dElev * vtCorr) ; int nRrId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPxId, pSfrRr) ; m_pGeomDB->SetName( nRrId, MCH_PV_RRCUT) ; m_pGeomDB->SetMaterial( nRrId, INVISIBLE) ; // regione di pre-taglio PtrOwner pCmpRs( GenerateExtArcPvPreCut( pArc, dIntRad, dExtRad, dDeltaT, dExtraL)) ; if ( IsNull( pCmpRs)) return false ; SurfFlatRegionByContours SfrCntrRs ; SfrCntrRs.AddCurve( Release( pCmpRs)) ; ISurfFlatRegion* pSfrRs = SfrCntrRs.GetSurf() ; if ( pSfrRs == nullptr) return false ; pSfrRs->Translate( dElev * vtCorr) ; int nRsId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPxId, pSfrRs) ; m_pGeomDB->SetName( nRsId, ( bFirst ? MCH_PV_RLICUT : MCH_PV_RRCUT)) ; m_pGeomDB->SetMaterial( nRsId, INVISIBLE) ; // regione di post-taglio PtrOwner pCmpRe( GenerateExtArcPvPostCut( pArc, dIntRad, dExtRad, dDeltaT, dExtraL)) ; if ( IsNull( pCmpRe)) return false ; SurfFlatRegionByContours SfrCntrRe ; SfrCntrRe.AddCurve( Release( pCmpRe)) ; ISurfFlatRegion* pSfrRe = SfrCntrRe.GetSurf() ; if ( pSfrRe == nullptr) return false ; pSfrRe->Translate( dElev * vtCorr) ; int nReId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPxId, pSfrRe) ; m_pGeomDB->SetName( nReId, ( bLast ? MCH_PV_RLOCUT : MCH_PV_RRCUT)) ; m_pGeomDB->SetMaterial( nReId, INVISIBLE) ; // regione completa (unione delle tre precedenti) int nRId = m_pGeomDB->Copy( nRrId, GDB_ID_NULL, nRrId, GDB_BEFORE) ; m_pGeomDB->SetName( nRId, MCH_PV_RCUT) ; m_pGeomDB->SetMaterial( nRId, INVISIBLE) ; if ( nRId == GDB_ID_NULL) return false ; if ( ! ExeSurfFrAdd( nRId, nRsId) || ! ExeSurfFrAdd( nRId, nReId)) return false ; } // altrimenti errore else return false ; } // salvo in info gruppo : larghezza XY del taglio, distanza XY tra centro e bordo taglio, extra taglio e quota minima della lama m_pGeomDB->SetInfo( nPxId, MCH_PV_KEY_WT, dMaxW) ; m_pGeomDB->SetInfo( nPxId, MCH_PV_KEY_DT, dDeltaT) ; m_pGeomDB->SetInfo( nPxId, MCH_PV_KEY_EC, dExtraCut) ; m_pGeomDB->SetInfo( nPxId, MCH_PV_KEY_RBH, dRbHeight) ; return true ; } //---------------------------------------------------------------------------- ICurveComposite* Sawing::GenerateExtArcPvTrueCut( const ICurveArc* pArc, double dIntRad, double dExtRad, double dSafety) { // arco interno PtrOwner pIntArc( pArc->Clone()) ; if ( IsNull( pIntArc) || ! pIntArc->ChangeRadius( dIntRad)) return nullptr ; // arco esterno PtrOwner pExtArc( pArc->Clone()) ; if ( IsNull( pExtArc) || ! pExtArc->ChangeRadius( dExtRad + dSafety)) return nullptr ; pExtArc->Invert() ; // linea di raccordo PtrOwner pLine( CreateCurveLine()) ; if ( IsNull( pLine)) return nullptr ; Point3d ptEnd ; pIntArc->GetEndPoint( ptEnd) ; Point3d ptStart ; pExtArc->GetStartPoint( ptStart) ; pLine->Set( ptEnd, ptStart) ; // composizione PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo) || ! pCompo->AddCurve( Release( pIntArc)) || ! pCompo->AddCurve( Release( pLine)) || ! pCompo->AddCurve( Release( pExtArc)) || ! pCompo->Close()) return nullptr ; // impongo senso CCW double dArea ; if ( ! pCompo->GetAreaXY( dArea)) return nullptr ; if ( dArea < 0) pCompo->Invert() ; return Release( pCompo) ; } //---------------------------------------------------------------------------- ICurveComposite* Sawing::GenerateExtArcPvPreCut( const ICurveArc* pArc, double dIntRad, double dExtRad, double dDeltaT, double dSafety) { // direzione iniziale del taglio Vector3d vtStaDir ; pArc->GetStartDir( vtStaDir) ; // direzione radiale iniziale Vector3d vtStaVer = pArc->GetStartVersor() ; // punto iniziale Point3d ptStart ; pArc->GetStartPoint( ptStart) ; if ( ! AreHeadWorkOnSameSide()) ptStart -= vtStaVer * m_TParams.m_dThick ; // punto prima di inizio Point3d ptPre = ptStart - vtStaDir * dDeltaT ; // punto fuori prima di inizio Point3d ptOutPre = ptPre + vtStaVer * m_TParams.m_dThick ; // punto fuori inizio Point3d ptOut = ptStart + vtStaVer * ( dExtRad - dIntRad) ; // linea di spessore lama PtrOwner pLine2( CreateCurveLine()) ; if ( IsNull( pLine2) || ! pLine2->Set( ptPre, ptOutPre)) return nullptr ; // arco PtrOwner pExtArc( CreateCurveArc()) ; if ( IsNull( pExtArc) || ! pExtArc->SetC2P( pArc->GetCenter(), ptOutPre, ptOut)) return nullptr ; PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo) || ! pCompo->AddCurve( Release( pLine2)) || ! pCompo->AddCurve( Release( pExtArc))) return nullptr ; // eventuale offset per sicurezza if ( dSafety > EPS_SMALL) { double dOffs = ( pArc->GetAngCenter() > 0 ? dSafety : - dSafety) ; if ( ! pCompo->SimpleOffset( dOffs, ICurve::OFF_EXTEND)) return nullptr ; } // linea base Point3d ptJoin ; pCompo->GetStartPoint( ptJoin) ; PtrOwner pLine1( CreateCurveLine()) ; if ( IsNull( pLine1) || ! pLine1->Set( ptStart, ptJoin)) return nullptr ; if ( ! pCompo->AddCurve( Release( pLine1), false)) return nullptr ; // chiusura if ( ! pCompo->Close()) return nullptr ; // impongo senso CCW double dArea ; if ( ! pCompo->GetAreaXY( dArea)) return nullptr ; if ( dArea < 0) pCompo->Invert() ; return Release( pCompo) ; } //---------------------------------------------------------------------------- ICurveComposite* Sawing::GenerateExtArcPvPostCut( const ICurveArc* pArc, double dIntRad, double dExtRad, double dDeltaT, double dSafety) { // direzione finale del taglio Vector3d vtEndDir ; pArc->GetEndDir( vtEndDir) ; // punto finale e direzione radiale finale Point3d ptEnd ; pArc->GetEndPoint( ptEnd) ; Vector3d vtEndVer = ptEnd - pArc->GetCenter() ; vtEndVer.Normalize() ; if ( ! AreHeadWorkOnSameSide()) ptEnd -= vtEndVer * m_TParams.m_dThick ; // punto dopo fine Point3d ptPost = ptEnd + vtEndDir * dDeltaT ; // punto fuori dopo fine Point3d ptOutPost = ptPost + vtEndVer * m_TParams.m_dThick ; // punto fuori fine Point3d ptOut = ptEnd + vtEndVer * ( dExtRad - dIntRad) ; // linea di spessore lama PtrOwner pLine2( CreateCurveLine()) ; if ( IsNull( pLine2) || ! pLine2->Set( ptPost, ptOutPost)) return nullptr ; // arco PtrOwner pExtArc( CreateCurveArc()) ; if ( IsNull( pExtArc) || ! pExtArc->SetC2P( pArc->GetCenter(), ptOutPost, ptOut)) return nullptr ; PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo) || ! pCompo->AddCurve( Release( pLine2)) || ! pCompo->AddCurve( Release( pExtArc))) return nullptr ; // eventuale offset per sicurezza if ( dSafety > EPS_SMALL) { double dOffs = ( pArc->GetAngCenter() > 0 ? - dSafety : dSafety) ; if ( ! pCompo->SimpleOffset( dOffs, ICurve::OFF_EXTEND)) return nullptr ; } // linea base Point3d ptJoin ; pCompo->GetStartPoint( ptJoin) ; PtrOwner pLine1( CreateCurveLine()) ; if ( IsNull( pLine1) || ! pLine1->Set( ptEnd, ptJoin)) return nullptr ; if ( ! pCompo->AddCurve( Release( pLine1), false)) return nullptr ; // chiusura if ( ! pCompo->Close()) return nullptr ; // impongo senso CCW double dArea ; if ( ! pCompo->GetAreaXY( dArea)) return nullptr ; if ( dArea < 0) pCompo->Invert() ; return Release( pCompo) ; } //---------------------------------------------------------------------------- bool Sawing::GenerateExtCurveCl( const ICurveComposite* pCrv, double dElev, double dExtraCut, const string& sName, int nClId) { // creo gruppo per geometria di lavorazione della curva int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ; if ( nPxId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPxId, sName) ; m_pGeomDB->SetMaterial( nPxId, BLUE) ; // calcolo dati di inizio Vector3d vtStaDir ; pCrv->GetStartDir( vtStaDir) ; Vector3d vtStaTool, vtStaCorr ; CalculateToolAndCorrVersors( vtStaDir, m_Params.m_nHeadSide, m_Params.m_nWorkSide, m_Params.m_dSideAngle, vtStaTool, vtStaCorr) ; // calcolo dati di fine Vector3d vtEndDir ; pCrv->GetEndDir( vtEndDir) ; Vector3d vtEndTool, vtEndCorr ; CalculateToolAndCorrVersors( vtEndDir, m_Params.m_nHeadSide, m_Params.m_nWorkSide, m_Params.m_dSideAngle, vtEndTool, vtEndCorr) ; // assegno il vettore estrusione al gruppo del percorso m_pGeomDB->SetInfo( nPxId, KEY_EXTR, Z_AX) ; // assegno i punti di inizio e fine al gruppo del percorso Point3d ptStart ; pCrv->GetStartPoint( ptStart) ; m_pGeomDB->SetInfo( nPxId, KEY_START, ptStart) ; Point3d ptEnd ; pCrv->GetEndPoint( ptEnd) ; m_pGeomDB->SetInfo( nPxId, KEY_END, ptEnd) ; // assegno l'elevazione massima m_pGeomDB->SetInfo( nPxId, KEY_ELEV, dElev) ; // Imposto dati comuni SetPathId( nPxId) ; SetCorrAuxDir( vtStaCorr) ; // recupero distanza di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // Se una sola passata if ( m_Params.m_dStepExtArc < EPS_SMALL || ( dElev - dExtraCut) <= m_Params.m_dStepExtArc) { // 1 -> approccio SetToolDir( vtStaTool) ; Point3d ptP1 ; pCrv->GetStartPoint( ptP1) ; if ( ! AddApproach( ptP1, vtStaCorr, dSafeZ, dElev, dAppr)) return false ; // 2 -> movimento in affondo al punto iniziale SetFlag( 0) ; SetFeed( GetTipFeed()) ; Point3d ptP2 ; pCrv->GetStartPoint( ptP2) ; if ( AddLinearMove( ptP2) == GDB_ID_NULL) return false ; // 3 -> movimento di lato al punto finale SetFeed( GetFeed()) ; for ( const ICurve* pSmpCrv = pCrv->GetFirstCurve() ; pSmpCrv != nullptr ; pSmpCrv = pCrv->GetNextCurve()) { Vector3d vtCurrDir ; pSmpCrv->GetEndDir( vtCurrDir) ; Vector3d vtCurrTool, vtCurrCorr ; CalculateToolAndCorrVersors( vtCurrDir, m_Params.m_nHeadSide, m_Params.m_nWorkSide, m_Params.m_dSideAngle, vtCurrTool, vtCurrCorr) ; SetToolDir( vtCurrTool) ; if ( AddCurveMove( pSmpCrv, true) == GDB_ID_NULL) return false ; } // 4 -> retrazione Point3d ptP4 ; pCrv->GetEndPoint( ptP4) ; if ( ! AddRetract( ptP4, vtEndCorr, dSafeZ, dElev, dAppr)) return false ; } // Se step a Zig-Zag o ToAndFrom else if ( m_Params.m_nStepType == SAW_ST_ZIGZAG || m_Params.m_nStepType == SAW_ST_TOANDFROM) { // 1 -> approccio SetToolDir( vtStaTool) ; Point3d ptP1 ; pCrv->GetStartPoint( ptP1) ; if ( ! AddApproach( ptP1, vtStaCorr, dSafeZ, dElev, dAppr)) return false ; // 2-3 -> lavorazione (sempre numero pari di passate) // calcolo numero e valore degli step double dCutH = dElev - dExtraCut ; int nStep = 2 ; if ( m_Params.m_nStepType == SAW_ST_ZIGZAG) { nStep = static_cast( ceil( dCutH / ( m_Params.m_dStepExtArc + EPS_SMALL))) ; if ( ( nStep % 2) == 1) nStep += 1 ; } double dStep = dCutH / nStep ; // esecuzione degli step for ( int i = nStep - 1 ; i >= 0 ; -- i) { // distanza dal fondo double dDelta = ( ( i != 0) ? dExtraCut + i * dStep : 0) ; // estremi del movimento (dispari vanno, pari tornano) Point3d ptP2 ; pCrv->GetStartPoint( ptP2) ; ptP2 += vtStaCorr * dDelta ; Point3d ptP3 ; pCrv->GetEndPoint( ptP3) ; ptP3 += vtStaCorr * dDelta ; if ( ( i % 2) == 0) swap( ptP2, ptP3) ; // movimento in affondo SetToolDir( ( ( i % 2) == 0) ? vtEndTool : vtStaTool) ; SetFlag( 0) ; SetFeed( GetTipFeed()) ; if ( AddLinearMove( ptP2) == GDB_ID_NULL) return false ; // movimento di lato SetFeed( GetFeed()) ; // se andata if ( ( i % 2) != 0) { // ciclo diretto sulle curve semplici componenti for ( const ICurve* pSmpCrv = pCrv->GetFirstCurve() ; pSmpCrv != nullptr ; pSmpCrv = pCrv->GetNextCurve()) { // calcolo direzione utensile Vector3d vtCurrDir ; pSmpCrv->GetEndDir( vtCurrDir) ; Vector3d vtCurrTool, vtCurrCorr ; CalculateToolAndCorrVersors( vtCurrDir, m_Params.m_nHeadSide, m_Params.m_nWorkSide, m_Params.m_dSideAngle, vtCurrTool, vtCurrCorr) ; SetToolDir( vtCurrTool) ; // copia della curva PtrOwner pCopy( pSmpCrv->Clone()) ; if ( IsNull( pCopy)) return false ; // traslazione pCopy->Translate( vtCurrCorr * dDelta) ; // emissione if ( AddCurveMove( pCopy, true) == GDB_ID_NULL) return false ; } } // altrimenti ritorno else { // ciclo inverso sulle curve semplici componenti for ( const ICurve* pSmpCrv = pCrv->GetLastCurve() ; pSmpCrv != nullptr ; pSmpCrv = pCrv->GetPrevCurve()) { // calcolo direzione utensile Vector3d vtCurrDir ; pSmpCrv->GetStartDir( vtCurrDir) ; Vector3d vtCurrTool, vtCurrCorr ; CalculateToolAndCorrVersors( vtCurrDir, m_Params.m_nHeadSide, m_Params.m_nWorkSide, m_Params.m_dSideAngle, vtCurrTool, vtCurrCorr) ; SetToolDir( vtCurrTool) ; // copia della curva PtrOwner pCopy( pSmpCrv->Clone()) ; if ( IsNull( pCopy)) return false ; // traslazione e inversione pCopy->Translate( vtCurrCorr * dDelta) ; pCopy->Invert() ; // emissione if ( AddCurveMove( pCopy, true) == GDB_ID_NULL) return false ; } } } // 4 -> retrazione SetToolDir( vtStaTool) ; Point3d ptP4 ; pCrv->GetStartPoint( ptP4) ; if ( ! AddRetract( ptP4, vtStaCorr, dSafeZ, dElev, dAppr)) return false ; } // Altrimenti step a una via else { // 1 -> approccio SetToolDir( vtStaTool) ; Point3d ptP1 ; pCrv->GetStartPoint( ptP1) ; if ( ! AddApproach( ptP1, vtStaCorr, dSafeZ, dElev, dAppr)) return false ; // 2-3 -> lavorazione // calcolo numero e valore degli step double dCutH = dElev - dExtraCut ; int nStep = static_cast( ceil( dCutH / ( m_Params.m_dStepExtArc + EPS_SMALL))) ; double dStep = dCutH / nStep ; // esecuzione degli step for ( int i = nStep - 1 ; i >= 0 ; -- i) { // distanza dal fondo double dDelta = ( ( i != 0) ? dExtraCut + i * dStep : 0) ; // movimento in affondo al punto iniziale SetToolDir( vtStaTool) ; SetFlag( 0) ; SetFeed( GetTipFeed()) ; Point3d ptP2 ; pCrv->GetStartPoint( ptP2) ; ptP2 += vtStaCorr * dDelta ; if ( AddLinearMove( ptP2) == GDB_ID_NULL) return false ; // movimento di lato al punto finale SetFeed( GetFeed()) ; for ( const ICurve* pSmpCrv = pCrv->GetFirstCurve() ; pSmpCrv != nullptr ; pSmpCrv = pCrv->GetNextCurve()) { Vector3d vtCurrDir ; pSmpCrv->GetEndDir( vtCurrDir) ; Vector3d vtCurrTool, vtCurrCorr ; CalculateToolAndCorrVersors( vtCurrDir, m_Params.m_nHeadSide, m_Params.m_nWorkSide, m_Params.m_dSideAngle, vtCurrTool, vtCurrCorr) ; SetToolDir( vtCurrTool) ; // copia della curva PtrOwner pCopy( pSmpCrv->Clone()) ; if ( IsNull( pCopy)) return false ; // traslazione pCopy->Translate( vtCurrCorr * dDelta) ; // emissione if ( AddCurveMove( pCopy, true) == GDB_ID_NULL) return false ; } // se non è ultimo passo if ( i != 0) { // ricavo punto di risalita e punto iniziale Point3d ptP4 ; pCrv->GetEndPoint( ptP4) ; ptP4 += vtEndCorr * ( dElev + dAppr) ; Point3d ptP5 ; pCrv->GetStartPoint( ptP5) ; ptP5 += vtStaCorr * ( dElev + dAppr) ; // se sono diversi o le direzioni utensile sono diverse if ( ! AreSamePointApprox( ptP4, ptP5) || ! AreSameVectorApprox( vtEndTool, vtStaTool)) { // movimento di risalita sopra il punto finale SetFeed( GetEndFeed()) ; if ( AddLinearMove( ptP4) == GDB_ID_NULL) return false ; // movimento di ritorno sopra il punto iniziale SetToolDir( vtStaTool) ; SetFeed( GetEndFeed()) ; if ( AreSamePointEpsilon( ptP4, ptP5, 10 * EPS_SMALL)) ptP5 -= vtStaCorr * 10 * EPS_SMALL ; if ( AddLinearMove( ptP5) == GDB_ID_NULL) return false ; } } } // 4 -> retrazione Point3d ptP4 ; pCrv->GetEndPoint( ptP4) ; if ( ! AddRetract( ptP4, vtEndCorr, dSafeZ, dElev, dAppr)) return false ; } return true ; } //---------------------------------------------------------------------------- bool Sawing::ProcessIntArc( const ICurve* pCrvP, const ICurveArc* pArcC, const ICurve* pCrvN, double dDepth, double dExtraCut, double dRbHeight, bool bIsFirst, bool bIsLast, const string& sName, int nPvId, int nClId) { // copio la curva PtrOwner pArc( pArcC->Clone()) ; if ( IsNull( pArc)) return false ; // determino l'inclinazione per ottenere il raggio e ne verifico il limite double dMaxSideAng = m_pMchMgr->GetCurrMachiningsMgr()->GetIntSawArcMaxSideAng()+ EPS_ANG_SMALL ; double dSawRad = m_TParams.m_dDiam / 2 ; double dRad = pArc->GetRadius() ; double dSinA = dSawRad / dRad ; if ( dSinA > sin( dMaxSideAng * DEGTORAD)) { LOG_INFO( GetEMkLogger(), "Warning in Sawing : Radius too small in IntSawArc") ; return true ; } double dSideAng = - asin( dSinA) * RADTODEG ; // Verifiche su lato di lavoro e lato testa (si lavora con angolo di sbandamento negativo) int nHeadSide = m_Params.m_nHeadSide ; if ( m_Params.m_nWorkSide == SAW_WS_CENTER) { m_pMchMgr->SetLastError( 2213, "Error in Sawing : Center work not allowed with internal arc") ; return false ; } else if ( m_Params.m_nWorkSide == SAW_WS_LEFT) { if ( m_Params.m_nHeadSide == SAW_HS_LEFT) nHeadSide = SAW_HS_RIGHT ; } else { if ( m_Params.m_nHeadSide == SAW_HS_RIGHT) nHeadSide = SAW_HS_LEFT ; } // Recupero le direzioni iniziale, intermedia e finale dell'arco Vector3d vtStaDirC ; pArc->GetStartDir( vtStaDirC) ; Vector3d vtMidDirC ; pArc->GetMidDir( vtMidDirC) ; Vector3d vtEndDirC ; pArc->GetEndDir( vtEndDirC) ; // calcolo i versori fresa e correzione Vector3d vtStaTool, vtStaCorr, vtMidTool, vtMidCorr, vtEndTool, vtEndCorr ; if ( ! CalculateToolAndCorrVersors( vtStaDirC, nHeadSide, m_Params.m_nWorkSide, dSideAng, vtStaTool, vtStaCorr) || ! CalculateToolAndCorrVersors( vtMidDirC, nHeadSide, m_Params.m_nWorkSide, dSideAng, vtMidTool, vtMidCorr) || ! CalculateToolAndCorrVersors( vtEndDirC, nHeadSide, m_Params.m_nWorkSide, dSideAng, vtEndTool, vtEndCorr)) { m_pMchMgr->SetLastError( 2208, "Error in Sawing : Entity CalculateToolAndCorrVersors") ; return false ; } // correzioni per lato lama, lato mandrino if ( ! AdjustIntArcForSide( pArc, dSideAng)) { m_pMchMgr->SetLastError( 2209, "Error in Sawing : Entity AdjustForSide") ; return false ; } // aggiungo affondamento pArc->Translate( - Z_AX * ( dDepth + dSinA * m_TParams.m_dThick)) ; // calcolo elevazione (sui due bordi della striscia) double dElev, dElev2 ; Point3d ptStart, ptMid, ptEnd ; pArc->GetStartPoint( ptStart) ; pArc->GetMidPoint( ptMid) ; pArc->GetEndPoint( ptEnd) ; Vector3d vtStaThick = vtStaTool * m_TParams.m_dThick ; Vector3d vtMidThick = vtMidTool * m_TParams.m_dThick ; Vector3d vtEndThick = vtEndTool * m_TParams.m_dThick ; if ( ! GetElevation( m_nPhase, ptStart, ptMid, ptEnd, Z_AX, dElev) || ! GetElevation( m_nPhase, ptStart + vtStaThick, ptMid + vtMidThick, ptEnd + vtEndThick, Z_AX, dElev2) ) { m_pMchMgr->SetLastError( 2210, "Error in Sawing : Entity GetElevation") ; return false ; } dElev = max( dElev, dElev2) ; // calcolo tipo angolo con precedente bool bExtAngPC = true ; if ( pCrvP != nullptr) { Vector3d vtDirP ; pCrvP->GetEndDir( vtDirP) ; double dAngPC ; vtDirP.GetAngleXY( vtStaDirC, dAngPC) ; if ( ( m_Params.m_nWorkSide == SAW_WS_LEFT && dAngPC > EPS_ANG_SMALL) || ( m_Params.m_nWorkSide == SAW_WS_RIGHT && dAngPC < - EPS_ANG_SMALL)) bExtAngPC = false ; } // calcolo tipo angolo con successivo bool bExtAngCN = true ; if ( pCrvN != nullptr) { Vector3d vtDirN ; pCrvN->GetStartDir( vtDirN) ; double dAngCN ; vtEndDirC.GetAngleXY( vtDirN, dAngCN) ; if ( ( m_Params.m_nWorkSide == SAW_WS_LEFT && dAngCN > EPS_ANG_SMALL) || ( m_Params.m_nWorkSide == SAW_WS_RIGHT && dAngCN < - EPS_ANG_SMALL)) bExtAngCN = false ; } // aggiusto per tipo estremi double dCosA = vtStaCorr.z ; double dSlantElev = dElev / dCosA ; double dDelta = dElev * dSinA / dCosA + m_TParams.m_dThick * dCosA ; // larghezza impronta double dLenCoeff = ( dRad + 0.8 * dDelta) / dRad ; // coefficiente per riportare lunghezza bool bToSkip = false ; if ( ! AdjustCurveForEdges( pArc, dSlantElev, dLenCoeff, bIsFirst, bIsLast, bExtAngPC, bExtAngCN, bToSkip)) { m_pMchMgr->SetLastError( 2211, "Error in Sawing : Entity AdjustForEdges") ; return false ; } if ( bToSkip) { LOG_INFO( GetEMkLogger(), "Warning in Sawing : skipped Entity too small") ; return true ; } // ricalcolo i versori fresa alle estremità (potrebbero essere cambiate) pArc->GetStartDir( vtStaDirC) ; pArc->GetMidDir( vtMidDirC) ; pArc->GetEndDir( vtEndDirC) ; if ( ! CalculateToolAndCorrVersors( vtStaDirC, nHeadSide, m_Params.m_nWorkSide, dSideAng, vtStaTool, vtStaCorr) || ! CalculateToolAndCorrVersors( vtMidDirC, nHeadSide, m_Params.m_nWorkSide, dSideAng, vtMidTool, vtMidCorr) || ! CalculateToolAndCorrVersors( vtEndDirC, nHeadSide, m_Params.m_nWorkSide, dSideAng, vtEndTool, vtEndCorr)) { m_pMchMgr->SetLastError( 2212, "Error in Sawing : Entity CalculateToolAndCorrVersors 2nd") ; return false ; } // Se richiesto Preview if ( nPvId != GDB_ID_NULL) { if ( ! GenerateIntArcPv( pArc, vtStaTool, vtMidTool, vtEndTool, vtStaCorr, vtMidCorr, vtEndCorr, dElev, dExtraCut, dRbHeight, dLenCoeff, sName, nPvId)) return false ; } // Se richiesta geometria di lavorazione if ( nClId != GDB_ID_NULL) { if ( ! GenerateIntArcCl( pArc, vtStaTool, vtMidTool, vtEndTool, vtStaCorr, vtMidCorr, vtEndCorr, dElev, dExtraCut, sName, nClId)) return false ; } // incremento numero di tagli ++ m_nCuts ; return true ; } //---------------------------------------------------------------------------- bool Sawing::GenerateIntArcPv( const ICurveArc* pArc, const Vector3d& vtStaTool, const Vector3d& vtMidTool, const Vector3d& vtEndTool, const Vector3d& vtStaCorr, const Vector3d& vtMidCorr, const Vector3d& vtEndCorr, double dElev, double dExtraCut, double dRbHeight, double dLenCoeff, const string& sName, int nPvId) { // creo gruppo per anteprima di lavorazione dell'arco int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nPvId, Frame3d()) ; if ( nPxId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPxId, sName) ; m_pGeomDB->SetMaterial( nPxId, BLUE) ; // disabilito eventuale registrazione comandi EXE (riabilitazione automatica) CmdLogOff cmdLogOff ; // seno e coseno dell'angolo di sbandamento double dSinA = sqrt( vtStaCorr.x * vtStaCorr.x + vtStaCorr.y * vtStaCorr.y) ; double dCosA = vtStaCorr.z ; // elevazione inclinata double dSlantElev = dElev / dCosA ; // lunghezza taglio parziale double dDeltaT = (( dSlantElev < 0.5 * m_TParams.m_dDiam) ? sqrt( dSlantElev * m_TParams.m_dDiam - dSlantElev * dSlantElev) : 0) ; // scostamenti da linea di lavoro (testa e lavoro sono da parti opposte) double dDeltaInt = dElev * dSinA / dCosA ; double dDeltaExt = m_TParams.m_dThick * dCosA ; // larghezza inclinata della lama (formula euristica che funziona abbastanza) double dSlantThick = m_TParams.m_dThick * dCosA ; // contorno per parte di taglio completo PtrOwner pCompo( GenerateIntArcPvTrueCut( pArc, dDeltaInt, dDeltaExt, 0)) ; if ( IsNull( pCompo)) return false ; pCompo->Translate( dElev * Z_AX + Vector3d( 0, 0, 0.1)) ; int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPxId, Release( pCompo)) ; m_pGeomDB->SetName( nId, MCH_PV_CUT) ; m_pGeomDB->SetMaterial( nId, LIME) ; // contorno per parte iniziale di taglio PtrOwner pCompo2( GenerateIntArcPvPreCut( pArc, dDeltaInt, dDeltaExt, dSlantThick, dDeltaT, 0)) ; if ( IsNull( pCompo2)) return false ; pCompo2->Translate( dElev * Z_AX) ; int nId2 = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPxId, Release( pCompo2)) ; m_pGeomDB->SetName( nId2, MCH_PV_PRE_CUT) ; m_pGeomDB->SetMaterial( nId2, BLUE) ; // contorno per parte finale di taglio PtrOwner pCompo3( GenerateIntArcPvPostCut( pArc, dDeltaInt, dDeltaExt, dSlantThick, dDeltaT, 0)) ; if ( IsNull( pCompo3)) return false ; pCompo3->Translate( dElev * Z_AX) ; int nId3 = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPxId, Release( pCompo3)) ; m_pGeomDB->SetName( nId3, MCH_PV_POST_CUT) ; m_pGeomDB->SetMaterial( nId3, BLUE) ; // dimensione da aggiungere alle regioni nelle parti in cui la lama è inclinata double dExtraL = m_pMchMgr->GetCurrMachiningsMgr()->GetExtraLOnCutRegion() ; // regione ridotta di taglio per nesting (escluse parti iniziali e finali) PtrOwner pCmpRr( GenerateIntArcPvTrueCut( pArc, dDeltaInt, dDeltaExt, dExtraL)) ; if ( IsNull( pCmpRr)) return false ; SurfFlatRegionByContours SfrCntrRr ; SfrCntrRr.AddCurve( Release( pCmpRr)) ; ISurfFlatRegion* pSfrRr = SfrCntrRr.GetSurf() ; if ( pSfrRr == nullptr) return false ; pSfrRr->Translate( dElev * Z_AX) ; int nRrId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPxId, pSfrRr) ; m_pGeomDB->SetName( nRrId, MCH_PV_RRCUT) ; m_pGeomDB->SetMaterial( nRrId, INVISIBLE) ; // regione di pre-taglio PtrOwner pCmpRs( GenerateIntArcPvPreCut( pArc, dDeltaInt, dDeltaExt, dSlantThick, dDeltaT, dExtraL)) ; if ( IsNull( pCmpRs)) return false ; SurfFlatRegionByContours SfrCntrRs ; SfrCntrRs.AddCurve( Release( pCmpRs)) ; ISurfFlatRegion* pSfrRs = SfrCntrRs.GetSurf() ; if ( pSfrRs == nullptr) return false ; pSfrRs->Translate( dElev * Z_AX) ; int nRsId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPxId, pSfrRs) ; m_pGeomDB->SetName( nRsId, MCH_PV_RLICUT) ; m_pGeomDB->SetMaterial( nRsId, INVISIBLE) ; // regione di post-taglio PtrOwner pCmpRe( GenerateIntArcPvPostCut( pArc, dDeltaInt, dDeltaExt, dSlantThick, dDeltaT, dExtraL)) ; if ( IsNull( pCmpRe)) return false ; SurfFlatRegionByContours SfrCntrRe ; SfrCntrRe.AddCurve( Release( pCmpRe)) ; ISurfFlatRegion* pSfrRe = SfrCntrRe.GetSurf() ; if ( pSfrRe == nullptr) return false ; pSfrRe->Translate( dElev * Z_AX) ; int nReId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPxId, pSfrRe) ; m_pGeomDB->SetName( nReId, MCH_PV_RLOCUT) ; m_pGeomDB->SetMaterial( nReId, INVISIBLE) ; // regione completa (unione delle tre precedenti) int nRId = m_pGeomDB->Copy( nRrId, GDB_ID_NULL, nRrId, GDB_BEFORE) ; m_pGeomDB->SetName( nRId, MCH_PV_RCUT) ; m_pGeomDB->SetMaterial( nRId, INVISIBLE) ; if ( nRId == GDB_ID_NULL) return false ; if ( ! ExeSurfFrAdd( nRId, nRsId) || ! ExeSurfFrAdd( nRId, nReId)) return false ; // salvo in info gruppo : larghezza XY del taglio, distanza XY tra centro e bordo taglio, extra taglio e quota minima della lama m_pGeomDB->SetInfo( nPxId, MCH_PV_KEY_WT, dDeltaInt + dDeltaExt) ; m_pGeomDB->SetInfo( nPxId, MCH_PV_KEY_DT, dDeltaT * dLenCoeff) ; m_pGeomDB->SetInfo( nPxId, MCH_PV_KEY_EC, dExtraCut) ; m_pGeomDB->SetInfo( nPxId, MCH_PV_KEY_RBH, dRbHeight) ; return true ; } //---------------------------------------------------------------------------- ICurveComposite* Sawing::GenerateIntArcPvTrueCut( const ICurveArc* pArc, double dDeltaInt, double dDeltaExt, double dSafety) { // arco interno PtrOwner pIntArc( pArc->Clone()) ; if ( IsNull( pIntArc) || ! pIntArc->ChangeRadius( pArc->GetRadius() - dDeltaInt - dSafety)) return nullptr ; // arco esterno PtrOwner pExtArc( pArc->Clone()) ; if ( IsNull( pExtArc) || ! pExtArc->ChangeRadius( pArc->GetRadius() + dDeltaExt)) return nullptr ; pExtArc->Invert() ; // linea di raccordo PtrOwner pLine( CreateCurveLine()) ; if ( IsNull( pLine)) return nullptr ; Point3d ptEnd ; pIntArc->GetEndPoint( ptEnd) ; Point3d ptStart ; pExtArc->GetStartPoint( ptStart) ; pLine->Set( ptEnd, ptStart) ; // composizione PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo) || ! pCompo->AddCurve( Release( pIntArc)) || ! pCompo->AddCurve( Release( pLine)) || ! pCompo->AddCurve( Release( pExtArc)) || ! pCompo->Close()) return nullptr ; // impongo senso CCW double dArea ; if ( ! pCompo->GetAreaXY( dArea)) return nullptr ; if ( dArea < 0) pCompo->Invert() ; return Release( pCompo) ; } //---------------------------------------------------------------------------- ICurveComposite* Sawing::GenerateIntArcPvPreCut( const ICurveArc* pArc, double dDeltaInt, double dDeltaExt, double dSlantThick, double dDeltaT, double dSafety) { // direzione iniziale del taglio Vector3d vtStaDir ; pArc->GetStartDir( vtStaDir) ; // direzione radiale iniziale Vector3d vtStaVer = pArc->GetStartVersor() ; // punto iniziale Point3d ptStart ; pArc->GetStartPoint( ptStart) ; ptStart -= vtStaVer * dDeltaInt ; // punto prima di inizio Point3d ptPre = ptStart - vtStaDir * dDeltaT ; // punto fuori prima di inizio Point3d ptOutPre = ptPre + vtStaVer * dSlantThick ; // punto fuori inizio Point3d ptOut = ptStart + vtStaVer * ( dDeltaInt + dDeltaExt) ; // linea base PtrOwner pLine1( CreateCurveLine()) ; if ( IsNull( pLine1) || ! pLine1->Set( ptStart, ptPre)) return nullptr ; // linea di spessore lama PtrOwner pLine2( CreateCurveLine()) ; if ( IsNull( pLine2) || ! pLine2->Set( ptPre, ptOutPre)) return nullptr ; // composita delle due linee PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo) || ! pCompo->AddCurve( Release( pLine1)) || ! pCompo->AddCurve( Release( pLine2))) return nullptr ; // eventuale offset per sicurezza if ( dSafety > EPS_SMALL) { double dOffs = ( pArc->GetAngCenter() > 0 ? dSafety : - dSafety) ; if ( ! pCompo->SimpleOffset( dOffs, ICurve::OFF_EXTEND)) return nullptr ; } // arco Point3d ptJoin ; pCompo->GetEndPoint( ptJoin) ; PtrOwner pExtArc( CreateCurveArc()) ; if ( IsNull( pExtArc) || ! pExtArc->Set2PVN( ptOut, ptJoin, - vtStaDir, Z_AX) || ! pExtArc->Invert()) return nullptr ; if ( ! pCompo->AddCurve( Release( pExtArc))) return nullptr ; // chiusura if ( ! pCompo->Close()) return nullptr ; // impongo senso CCW double dArea ; if ( ! pCompo->GetAreaXY( dArea)) return nullptr ; if ( dArea < 0) pCompo->Invert() ; return Release( pCompo) ; } //---------------------------------------------------------------------------- ICurveComposite* Sawing::GenerateIntArcPvPostCut( const ICurveArc* pArc, double dDeltaInt, double dDeltaExt, double dSlantThick, double dDeltaT, double dSafety) { // direzione finale del taglio Vector3d vtEndDir ; pArc->GetEndDir( vtEndDir) ; // punto finale e direzione radiale finale Point3d ptEnd ; pArc->GetEndPoint( ptEnd) ; Vector3d vtEndVer = ptEnd - pArc->GetCenter() ; vtEndVer.Normalize() ; ptEnd -= vtEndVer * dDeltaInt ; // punto dopo fine Point3d ptPost = ptEnd + vtEndDir * dDeltaT ; // punto fuori dopo fine Point3d ptOutPost = ptPost + vtEndVer * dSlantThick ; // punto fuori fine Point3d ptOut = ptEnd + vtEndVer * ( dDeltaInt + dDeltaExt) ; // linea base PtrOwner pLine1( CreateCurveLine()) ; if ( IsNull( pLine1) || ! pLine1->Set( ptEnd, ptPost)) return nullptr ; // linea di spessore lama PtrOwner pLine2( CreateCurveLine()) ; if ( IsNull( pLine2) || ! pLine2->Set( ptPost, ptOutPost)) return nullptr ; PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo) || ! pCompo->AddCurve( Release( pLine1)) || ! pCompo->AddCurve( Release( pLine2))) return nullptr ; // eventuale offset per sicurezza if ( dSafety > EPS_SMALL) { double dOffs = ( pArc->GetAngCenter() > 0 ? - dSafety : dSafety) ; if ( ! pCompo->SimpleOffset( dOffs, ICurve::OFF_EXTEND)) return nullptr ; } // arco Point3d ptJoin ; pCompo->GetEndPoint( ptJoin) ; PtrOwner pExtArc( CreateCurveArc()) ; if ( IsNull( pExtArc) || ! pExtArc->Set2PVN( ptOut, ptJoin, vtEndDir, Z_AX) || ! pExtArc->Invert()) return nullptr ; if ( ! pCompo->AddCurve( Release( pExtArc))) return nullptr ; // chiusura if ( ! pCompo->Close()) return nullptr ; // impongo senso CCW double dArea ; if ( ! pCompo->GetAreaXY( dArea)) return nullptr ; if ( dArea < 0) pCompo->Invert() ; return Release( pCompo) ; } //---------------------------------------------------------------------------- bool Sawing::GenerateIntArcCl( const ICurveArc* pArc, const Vector3d& vtStaTool, const Vector3d& vtMidTool, const Vector3d& vtEndTool, const Vector3d& vtStaCorr, const Vector3d& vtMidCorr, const Vector3d& vtEndCorr, double dElev, double dExtraCut, const string& sName, int nClId) { // creo gruppo per geometria di lavorazione dell'arco int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ; if ( nPxId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPxId, sName) ; m_pGeomDB->SetMaterial( nPxId, BLUE) ; // assegno il vettore estrazione al gruppo del percorso m_pGeomDB->SetInfo( nPxId, KEY_EXTR, Z_AX) ; // assegno i punti di inizio e fine al gruppo del percorso Point3d ptStart ; pArc->GetStartPoint( ptStart) ; m_pGeomDB->SetInfo( nPxId, KEY_START, ptStart) ; Point3d ptEnd ; pArc->GetEndPoint( ptEnd) ; m_pGeomDB->SetInfo( nPxId, KEY_END, ptEnd) ; // assegno l'elevazione massima m_pGeomDB->SetInfo( nPxId, KEY_ELEV, dElev) ; // Imposto dati comuni SetPathId( nPxId) ; // recupero distanza di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // Se una sola passata if ( m_Params.m_dStepIntArc < EPS_SMALL || ( dElev - dExtraCut) <= m_Params.m_dStepIntArc) { // 1 -> approccio SetToolDir( vtStaTool) ; SetCorrAuxDir( vtStaCorr) ; Point3d ptP1 ; pArc->GetStartPoint( ptP1) ; if ( ! AddApproach( ptP1, Z_AX, dSafeZ, dElev, dAppr)) return false ; // 2 -> movimento in affondo al punto iniziale SetFlag( 0) ; SetFeed( GetTipFeed()) ; Point3d ptP2 ; pArc->GetStartPoint( ptP2) ; if ( AddLinearMove( ptP2) == GDB_ID_NULL) return false ; // 3 -> movimento di lato al punto finale SetFeed( GetFeed()) ; Point3d ptCen = pArc->GetCenter() ; double dAngCen = pArc->GetAngCenter() ; Vector3d vtN = pArc->GetNormVersor() ; Point3d ptP3 ; pArc->GetEndPoint( ptP3) ; // se angolo al centro minore del limite, un solo arco if ( abs( pArc->GetAngCenter()) < MAX_ANG_CEN) { SetToolDir( vtEndTool) ; SetCorrAuxDir( vtEndCorr) ; if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) return false ; } // altrimenti due archi else { Point3d ptMid ; pArc->GetMidPoint( ptMid) ; // prima metà arco SetToolDir( vtMidTool) ; SetCorrAuxDir( vtMidCorr) ; if ( AddArcMove( ptMid, ptCen, dAngCen / 2, vtN) == GDB_ID_NULL) return false ; // seconda metà arco SetToolDir( vtEndTool) ; SetCorrAuxDir( vtEndCorr) ; if ( AddArcMove( ptP3, ptCen, dAngCen / 2, vtN) == GDB_ID_NULL) return false ; } // 4 -> retrazione Point3d ptP4 ; pArc->GetEndPoint( ptP4) ; if ( ! AddRetract( ptP4, Z_AX, dSafeZ, dElev, dAppr)) return false ; } // Se step a Zig-Zag o ToAndFrom else if ( m_Params.m_nStepType == SAW_ST_ZIGZAG || m_Params.m_nStepType == SAW_ST_TOANDFROM) { // 1 -> approccio SetToolDir( vtStaTool) ; SetCorrAuxDir( vtStaCorr) ; Point3d ptP1 ; pArc->GetStartPoint( ptP1) ; if ( ! AddApproach( ptP1, Z_AX, dSafeZ, dElev, dAppr)) return false ; // 2-3 -> lavorazione (sempre numero pari di passate) // calcolo numero e valore degli step double dCutH = dElev - dExtraCut ; int nStep = 2 ; if ( m_Params.m_nStepType == SAW_ST_ZIGZAG) { nStep = static_cast( ceil( dCutH / ( m_Params.m_dStepIntArc + EPS_SMALL))) ; if ( ( nStep % 2) == 1) nStep += 1 ; } double dStep = dCutH / nStep ; // esecuzione degli step for ( int i = nStep - 1 ; i >= 0 ; -- i) { // distanza dal fondo double dDelta = ( ( i != 0) ? dExtraCut + i * dStep : 0) ; // estremi del movimento (dispari vanno, pari tornano) Point3d ptP2 ; pArc->GetStartPoint( ptP2) ; ptP2 += Z_AX * dDelta ; Point3d ptP3 ; pArc->GetEndPoint( ptP3) ; ptP3 += Z_AX * dDelta ; if ( ( i % 2) == 0) swap( ptP2, ptP3) ; // versori Vector3d vtTool2 = ( ( i % 2) == 0) ? vtEndTool : vtStaTool ; SetToolDir( vtTool2) ; Vector3d vtCorr2 = ( ( i % 2) == 0) ? vtEndCorr : vtStaCorr ; SetCorrAuxDir( vtCorr2) ; SetFlag( 0) ; // se non primo, movimento laterale sopra if ( i != nStep - 1) { Point3d ptUp = ptP2 + vtCorr2 * ( dElev - dDelta + dAppr) / vtCorr2.z ; SetFeed( GetEndFeed()) ; if ( AddLinearMove( ptUp) == GDB_ID_NULL) return false ; } // movimento in affondo SetFeed( GetTipFeed()) ; if ( AddLinearMove( ptP2) == GDB_ID_NULL) return false ; // movimento di lato SetFeed( GetFeed()) ; Point3d ptCen = pArc->GetCenter() ; double dAngCen = pArc->GetAngCenter() ; Vector3d vtN = pArc->GetNormVersor() ; // se angolo al centro minore del limite, un solo arco if ( abs( dAngCen) < MAX_ANG_CEN) { double dCurrAngCen = dAngCen * ((( i % 2) == 0) ? -1 : 1) ; SetToolDir( ( ( i % 2) == 0) ? vtStaTool : vtEndTool) ; SetCorrAuxDir( ( ( i % 2) == 0) ? vtStaCorr : vtEndCorr) ; if ( AddArcMove( ptP3, ptCen, dCurrAngCen, vtN) == GDB_ID_NULL) return false ; } // altrimenti due archi else { Point3d ptMid ; pArc->GetMidPoint( ptMid) ; ptMid += Z_AX * dDelta ; double dCurrAngCen = dAngCen / 2 * ((( i % 2) == 0) ? -1 : 1) ; // prima metà arco SetToolDir( vtMidTool) ; SetCorrAuxDir( vtMidCorr) ; if ( AddArcMove( ptMid, ptCen, dCurrAngCen, vtN) == GDB_ID_NULL) return false ; // seconda metà arco SetToolDir( ( ( i % 2) == 0) ? vtStaTool : vtEndTool) ; SetCorrAuxDir( ( ( i % 2) == 0) ? vtStaCorr : vtEndCorr) ; if ( AddArcMove( ptP3, ptCen, dCurrAngCen, vtN) == GDB_ID_NULL) return false ; } // se intermedio, risalita inclinata if ( i > 0) { Vector3d vtCorr3 = ( ( i % 2) == 0) ? vtStaCorr : vtEndCorr ; Point3d ptUp = ptP3 + vtCorr3 * ( dElev - dDelta + dAppr) / vtCorr3.z ; SetFeed( GetEndFeed()) ; if ( AddLinearMove( ptUp) == GDB_ID_NULL) return false ; } } // 4 -> retrazione SetToolDir( vtStaTool) ; SetCorrAuxDir( vtStaCorr) ; Point3d ptP4 ; pArc->GetStartPoint( ptP4) ; if ( ! AddRetract( ptP4, Z_AX, dSafeZ, dElev, dAppr)) return false ; } // Altrimenti step a una via else { // 1 -> approccio SetToolDir( vtStaTool) ; SetCorrAuxDir( vtStaCorr) ; Point3d ptP1 ; pArc->GetStartPoint( ptP1) ; if ( ! AddApproach( ptP1, Z_AX, dSafeZ, dElev, dAppr)) return false ; // 2-3 -> lavorazione // calcolo numero e valore degli step double dCutH = dElev - dExtraCut ; int nStep = static_cast( ceil( dCutH / ( m_Params.m_dStepIntArc + EPS_SMALL))) ; double dStep = dCutH / nStep ; // esecuzione degli step for ( int i = nStep - 1 ; i >= 0 ; -- i) { // distanza dal fondo double dDelta = ( ( i != 0) ? dExtraCut + i * dStep : 0) ; // se non primo, movimento laterale sopra if ( i != nStep - 1) { // movimento di ritorno sopra il punto iniziale SetToolDir( vtStaTool) ; SetCorrAuxDir( vtStaCorr) ; SetFeed( GetEndFeed()) ; Point3d ptP5 ; pArc->GetStartPoint( ptP5) ; ptP5 += Z_AX * dDelta + vtStaCorr * ( dElev - dDelta + dAppr) / vtStaCorr.z ; if ( AddLinearMove( ptP5) == GDB_ID_NULL) return false ; } // movimento in affondo al punto iniziale SetToolDir( vtStaTool) ; SetCorrAuxDir( vtStaCorr) ; SetFlag( 0) ; SetFeed( GetTipFeed()) ; Point3d ptP2 ; pArc->GetStartPoint( ptP2) ; ptP2 += Z_AX * dDelta ; if ( AddLinearMove( ptP2) == GDB_ID_NULL) return false ; // movimento di lato al punto finale SetFeed( GetFeed()) ; Point3d ptCen = pArc->GetCenter() ; double dAngCen = pArc->GetAngCenter() ; Vector3d vtN = pArc->GetNormVersor() ; Point3d ptP3 ; pArc->GetEndPoint( ptP3) ; ptP3 += Z_AX * dDelta ; // se angolo al centro minore del limite, un solo arco if ( abs( dAngCen) < MAX_ANG_CEN) { SetToolDir( vtEndTool) ; SetCorrAuxDir( vtEndCorr) ; if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) return false ; } // altrimenti due archi else { Point3d ptMid ; pArc->GetMidPoint( ptMid) ; ptMid += Z_AX * dDelta ; // prima metà arco SetToolDir( vtMidTool) ; SetCorrAuxDir( vtMidCorr) ; if ( AddArcMove( ptMid, ptCen, dAngCen / 2, vtN) == GDB_ID_NULL) return false ; // seconda metà arco SetToolDir( vtEndTool) ; SetCorrAuxDir( vtEndCorr) ; if ( AddArcMove( ptP3, ptCen, dAngCen / 2, vtN) == GDB_ID_NULL) return false ; } // se non è ultimo passo if ( i != 0) { // movimento di risalita sopra il punto finale SetFeed( GetEndFeed()) ; Point3d ptP4 ; pArc->GetEndPoint( ptP4) ; ptP4 += Z_AX * ( dElev + dAppr) ; if ( AddLinearMove( ptP4) == GDB_ID_NULL) return false ; } } // 4 -> retrazione Point3d ptP4 ; pArc->GetEndPoint( ptP4) ; if ( ! AddRetract( ptP4, Z_AX, dSafeZ, dElev, dAppr)) return false ; } return true ; } //---------------------------------------------------------------------------- bool Sawing::AddApproach( const Point3d& ptP, const Vector3d& vtCorr, double dSafeZ, double dElev, double dAppr) { // se distanza di sicurezza minore di distanza di inizio if ( dSafeZ < m_Params.m_dStartPos + 10 * EPS_SMALL) { // 1 -> punto sopra inizio SetFlag( 1) ; Point3d ptP1 = ptP + vtCorr * ( dElev + dAppr) ; if ( AddRapidStart( ptP1) == GDB_ID_NULL) return false ; } else { // 1a -> punto sopra inizio SetFlag( 1) ; Point3d ptP1b = ptP + vtCorr * ( dElev + dAppr) ; Point3d ptP1a = ptP1b + Z_AX * ( dSafeZ - m_Params.m_dStartPos) ; if ( AddRapidStart( ptP1a) == GDB_ID_NULL) return false ; // 1b -> punto appena sopra inizio SetFlag( 0) ; if ( AddRapidMove( ptP1b) == GDB_ID_NULL) return false ; } return true ; } //---------------------------------------------------------------------------- bool Sawing::AddRetract( const Point3d& ptP, const Vector3d& vtCorr, double dSafeZ, double dElev, double dAppr) { if ( dSafeZ < m_Params.m_dStartPos + 10 * EPS_SMALL) { // 4 -> movimento di risalita sopra il punto finale SetFeed( GetEndFeed()) ; Point3d ptP4 = ptP + vtCorr * ( dElev + dAppr) ; if ( AddLinearMove( ptP4) == GDB_ID_NULL) return false ; } else { // 4a -> movimento di risalita appena sopra il punto finale SetFeed( GetEndFeed()) ; Point3d ptP4a = ptP + vtCorr * ( dElev + dAppr) ; if ( AddLinearMove( ptP4a) == GDB_ID_NULL) return false ; // 4b -> movimento di risalita sopra il punto finale Point3d ptP4b = ptP4a + Z_AX * ( dSafeZ - m_Params.m_dStartPos) ; if ( AddRapidMove( ptP4b) == GDB_ID_NULL) return false ; } return true ; } //---------------------------------------------------------------------------- bool Sawing::CalculateToolAndCorrVersors( const Vector3d& vtTang, int nHeadSide, int nWorkSide, double dSideAng, 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, 90) ; else vtTool.Rotate( Z_AX, -90) ; // Versore correzione vtCorr = Z_AX ; // Se lama sbandata if ( fabs( dSideAng) > EPS_ANG_SMALL) { if ( nWorkSide == SAW_WS_RIGHT) { vtTool.Rotate( vtTang, - dSideAng) ; vtCorr.Rotate( vtTang, - dSideAng) ; } else { vtTool.Rotate( vtTang, dSideAng) ; vtCorr.Rotate( vtTang, dSideAng) ; } } return true ; } //---------------------------------------------------------------------------- bool Sawing::AdjustForSide( ICurve* pCurve) { // se lato lavoro e lato mandrino coincidono, non devo fare alcunché if ( ( m_Params.m_nWorkSide == SAW_WS_LEFT && m_Params.m_nHeadSide == SAW_HS_LEFT) || ( m_Params.m_nWorkSide == SAW_WS_RIGHT && m_Params.m_nHeadSide == SAW_HS_RIGHT)) return true ; // calcolo offset curva double dOffs = 0 ; if ( m_Params.m_nWorkSide == SAW_WS_LEFT) dOffs = - m_TParams.m_dThick ; else if ( m_Params.m_nWorkSide == SAW_WS_RIGHT) dOffs = m_TParams.m_dThick ; else if ( m_Params.m_nHeadSide == SAW_HS_LEFT) // lama in centro dOffs = 0.5 * m_TParams.m_dThick ; else // testa a destra e lama in centro dOffs = - 0.5 * m_TParams.m_dThick ; // correzione per angolo di fianco if ( abs( m_Params.m_dSideAngle) > EPS_ANG_SMALL) dOffs /= cos( m_Params.m_dSideAngle * DEGTORAD) ; // eseguo offset curva ( nel piano XY globale) return pCurve->SimpleOffset( dOffs) ; } //---------------------------------------------------------------------------- bool Sawing::AdjustIntArcForSide( ICurve* pCurve, double dSideAng) { // calcolo offset curva double dOffs = 0 ; if ( m_Params.m_nWorkSide == SAW_WS_LEFT) dOffs = - m_TParams.m_dThick ; else dOffs = m_TParams.m_dThick ; // correzione per angolo di fianco if ( fabs( dSideAng) > EPS_ANG_SMALL) dOffs *= cos( dSideAng * DEGTORAD) ; // eseguo offset curva ( nel piano XY globale) return pCurve->SimpleOffset( dOffs) ; } //---------------------------------------------------------------------------- bool Sawing::AdjustLineForEdges( ICurveLine* pLine, double dElev, const Vector3d& vtCorr, const Vector3d& vtThick, bool bIsFirst, bool bIsLast, bool bExtAngPC, bool bExtAngCN, bool& bToSkip, double& dDeltaLiExt, double& dDeltaLoExt) { // distanza XY tra centro e bordo taglio double dDeltaT = (( dElev < 0.5 * m_TParams.m_dDiam) ? sqrt( dElev * m_TParams.m_dDiam - dElev * dElev) : 0) ; // verifiche e aggiustamenti sull'inizio double dDeltaI = 0 ; dDeltaLiExt = 0 ; if ( ! bExtAngPC) dDeltaI = - dDeltaT ; else if ( bIsFirst) { if ( m_Params.m_nLeadInType == SAW_LI_STRICT) // all'interno dDeltaI = - dDeltaT ; else if ( m_Params.m_nLeadInType == SAW_LI_OUT) // all'esterno dDeltaI = dDeltaT ; else if ( m_Params.m_nLeadInType == SAW_LI_EXT_CENT || m_Params.m_nLeadInType == SAW_LI_EXT_OUT) { // porto il centro lama sul bordo del grezzo o all'esterno // calcolo punto di inizio e direzione (sono in globale) Point3d ptP ; pLine->GetStartPoint( ptP) ; Vector3d vtDir ; pLine->GetStartDir( vtDir) ; // determino la distanza dal bordo del grezzo double dDist[4] = {0, 0, 0, 0} ; if ( ! GetDistanceFromRawSide( m_nPhase, ptP, - vtDir, dDist[0]) || ! GetDistanceFromRawSide( m_nPhase, ptP + vtThick, - vtDir, dDist[1]) || ! GetDistanceFromRawSide( m_nPhase, ptP + vtCorr * dElev, - vtDir, dDist[2]) || ! GetDistanceFromRawSide( m_nPhase, ptP + vtCorr * dElev + vtThick, - vtDir, dDist[3])) return false ; dDeltaI = 0 ; for ( int i = 0 ; i < 4 ; ++i) dDeltaI = max( dDeltaI, dDist[i]) ; if ( m_Params.m_nLeadInType == SAW_LI_EXT_OUT) dDeltaI += dDeltaT ; dDeltaLiExt = dDeltaI ; } } else { if ( m_Params.m_nExtLinkType == SAW_EL_EXT_NEXT || m_Params.m_nExtLinkType == SAW_EL_EXT_BOTH) { // estendere al bordo del grezzo // calcolo punto di inizio e direzione (sono in globale) Point3d ptP ; pLine->GetStartPoint( ptP) ; Vector3d vtDir ; pLine->GetStartDir( vtDir) ; // determino la distanza dal bordo del grezzo double dDist[4] = {0, 0, 0, 0} ; if ( ! GetDistanceFromRawSide( m_nPhase, ptP, - vtDir, dDist[0]) || ! GetDistanceFromRawSide( m_nPhase, ptP + vtThick, - vtDir, dDist[1]) || ! GetDistanceFromRawSide( m_nPhase, ptP + vtCorr * dElev, - vtDir, dDist[2]) || ! GetDistanceFromRawSide( m_nPhase, ptP + vtCorr * dElev + vtThick, - vtDir, dDist[3])) return false ; dDeltaI = 0 ; for ( int i = 0 ; i < 4 ; ++i) dDeltaI = max( dDeltaI, dDist[i]) ; if ( m_Params.m_nLeadInType == SAW_LI_EXT_OUT) dDeltaI += dDeltaT ; dDeltaLiExt = dDeltaI ; } } // verifiche e aggiustamenti sulla fine double dDeltaF = 0 ; dDeltaLoExt = 0 ; if ( ! bExtAngCN) dDeltaF = - dDeltaT ; else if ( bIsLast) { if ( m_Params.m_nLeadOutType == SAW_LO_STRICT) // all'interno dDeltaF = - dDeltaT ; else if ( m_Params.m_nLeadOutType == SAW_LO_OUT) // all'esterno dDeltaF = dDeltaT ; else if ( m_Params.m_nLeadOutType == SAW_LO_EXT_CENT || m_Params.m_nLeadOutType == SAW_LO_EXT_OUT) { // estendo al bordo del grezzo o al suo esterno // calcolo punto di fine e direzione (sono in globale) Point3d ptP ; pLine->GetEndPoint( ptP) ; Vector3d vtDir ; pLine->GetEndDir( vtDir) ; // determino la distanza dal bordo del grezzo double dDist[4] = {0, 0, 0, 0} ; if ( ! GetDistanceFromRawSide( m_nPhase, ptP, vtDir, dDist[0]) || ! GetDistanceFromRawSide( m_nPhase, ptP + vtThick, vtDir, dDist[1]) || ! GetDistanceFromRawSide( m_nPhase, ptP + vtCorr * dElev, vtDir, dDist[2]) || ! GetDistanceFromRawSide( m_nPhase, ptP + vtCorr * dElev + vtThick, vtDir, dDist[3])) return false ; dDeltaF = 0 ; for ( int i = 0 ; i < 4 ; ++i) dDeltaF = max( dDeltaF, dDist[i]) ; if ( m_Params.m_nLeadOutType == SAW_LO_EXT_OUT) dDeltaF += dDeltaT ; dDeltaLoExt = dDeltaF ; } } else { if ( m_Params.m_nExtLinkType == SAW_EL_EXT_PREV || m_Params.m_nExtLinkType == SAW_EL_EXT_BOTH) { // estendo al bordo del grezzo // calcolo punto di fine e direzione (sono in globale) Point3d ptP ; pLine->GetEndPoint( ptP) ; Vector3d vtDir ; pLine->GetEndDir( vtDir) ; // determino la distanza dal bordo del grezzo double dDist[4] = {0, 0, 0, 0} ; if ( ! GetDistanceFromRawSide( m_nPhase, ptP, vtDir, dDist[0]) || ! GetDistanceFromRawSide( m_nPhase, ptP + vtThick, vtDir, dDist[1]) || ! GetDistanceFromRawSide( m_nPhase, ptP + vtCorr * dElev, vtDir, dDist[2]) || ! GetDistanceFromRawSide( m_nPhase, ptP + vtCorr * dElev + vtThick, vtDir, dDist[3])) return false ; dDeltaF = 0 ; for ( int i = 0 ; i < 4 ; ++i) dDeltaF = max( dDeltaF, dDist[i]) ; // se LeadOut EXT_OUT vado all'esterno if ( m_Params.m_nLeadOutType == SAW_LO_EXT_OUT) dDeltaF += dDeltaT ; dDeltaLoExt = dDeltaF ; } } // controllo se lunghezza entità accettabile const double MIN_LEN = 1 ; double dLenXY = DistXY( pLine->GetStart(), pLine->GetEnd()) ; if ( dDeltaI + dLenXY + dDeltaF < MIN_LEN) { bToSkip = true ; return true ; } bToSkip = false ; // modifico gli estremi : // eventuali allungamenti if ( dDeltaI > EPS_SMALL) { if ( ! pLine->ExtendStartByLen( dDeltaI)) return false ; dLenXY += dDeltaI ; } if ( dDeltaF > EPS_SMALL) { if ( ! pLine->ExtendEndByLen( dDeltaF)) return false ; dLenXY += dDeltaF ; } // eventuali accorciamenti (da fare dopo tutti gli allungamenti) if ( dDeltaI < - EPS_SMALL) { if ( ! pLine->TrimStartAtLen( - dDeltaI)) return false ; dLenXY += dDeltaI ; } if ( dDeltaF < - EPS_SMALL) { if ( ! pLine->TrimEndAtLen( dLenXY + dDeltaF)) return false ; dLenXY += dDeltaF ; } return true ; } //---------------------------------------------------------------------------- bool Sawing::AdjustCurveForEdges( ICurve* pCrv, double dElev, double dLenCoeff, bool bIsFirst, bool bIsLast, bool bExtAngPC, bool bExtAngCN, bool& bToSkip) { // --- gli archi non vanno estesi al bordo del grezzo --- // distanza XY tra centro e bordo taglio double dDeltaT = (( dElev < 0.5 * m_TParams.m_dDiam) ? sqrt( dElev * m_TParams.m_dDiam - dElev * dElev) : 0) ; // verifiche e aggiustamenti sull'inizio double dDeltaI = 0 ; if ( ! bExtAngPC) dDeltaI = - dDeltaT ; else if ( bIsFirst) { if ( m_Params.m_nLeadInType == SAW_LI_STRICT) // all'interno dDeltaI = - dDeltaT ; else if ( m_Params.m_nLeadInType == SAW_LI_OUT || m_Params.m_nLeadInType == SAW_LI_EXT_OUT) // all'esterno dDeltaI = dDeltaT ; } dDeltaI *= dLenCoeff ; // verifiche e aggiustamenti sulla fine double dDeltaF = 0 ; if ( ! bExtAngCN) dDeltaF = - dDeltaT ; else if ( bIsLast) { if ( m_Params.m_nLeadOutType == SAW_LO_STRICT) // all'interno dDeltaF = - dDeltaT ; else if ( m_Params.m_nLeadOutType == SAW_LO_OUT || m_Params.m_nLeadOutType == SAW_LO_EXT_OUT) // all'esterno dDeltaF = dDeltaT ; } dDeltaF *= dLenCoeff ; // controllo se lunghezza entità accettabile const double MIN_LEN = 1 ; double dLenXY ; pCrv->GetLength( dLenXY) ; if ( dDeltaI + dLenXY + dDeltaF < MIN_LEN) { bToSkip = true ; return true ; } bToSkip = false ; // modifico gli estremi // eventuali allungamenti if ( dDeltaI > EPS_SMALL) { if ( ! pCrv->ExtendStartByLen( dDeltaI)) return false ; dLenXY += dDeltaI ; } if ( dDeltaF > EPS_SMALL) { if ( ! pCrv->ExtendEndByLen( dDeltaF)) return false ; dLenXY += dDeltaF ; } // eventuali accorciamenti (da fare dopo tutti gli allungamenti) if ( dDeltaI < - EPS_SMALL) { if ( ! pCrv->TrimStartAtLen( - dDeltaI)) return false ; dLenXY += dDeltaI ; } if ( dDeltaF < - EPS_SMALL) { if ( ! pCrv->TrimEndAtLen( dLenXY + dDeltaF)) return false ; dLenXY += dDeltaF ; } return true ; } //---------------------------------------------------------------------------- bool Sawing::AreHeadWorkOnSameSide( void) const { return ( ( m_Params.m_nWorkSide == SAW_WS_LEFT && m_Params.m_nHeadSide == SAW_HS_LEFT) || ( m_Params.m_nWorkSide == SAW_WS_RIGHT && m_Params.m_nHeadSide == SAW_HS_RIGHT)) ; }