diff --git a/CAvSilhouetteSurfTm.cpp b/CAvSilhouetteSurfTm.cpp index 7869a39..fa7f19c 100644 --- a/CAvSilhouetteSurfTm.cpp +++ b/CAvSilhouetteSurfTm.cpp @@ -311,7 +311,6 @@ TestEdgesClosedPolyLines( POLYLINEVECTOR& vPL, const CAvToolSurfTm& cavTstm, int const Frame3d& frGrid, double dDimZ, double dLevel, double dStep, double dAngTol, bool bAdvCorners) { - // se non ho polylinee, allora esco if ( vPL.empty()) return true ; @@ -341,10 +340,45 @@ TestEdgesClosedPolyLines( POLYLINEVECTOR& vPL, const CAvToolSurfTm& cavTstm, int if ( ! CalcRegionPolyLines( vPL, vtN, mIndMat, vbInv)) return false ; + #if ENABLE_SHARPED_EDGES_DEBUG + vector> vvpGObj ; vvpGObj.resize( 7) ; + vector> vvCol ; vvCol.resize( 7) ; + // ombra del tool + PtrOwner pCrvToolShape( CreateCurveArc()) ; + pCrvToolShape->Set( ORIG, Z_AX, cavTstm.GetToolRadius()) ; + // 1° gruppo, griglia di punti + for ( int j = 0 ; j <= nStepY ; ++ j) { + for ( int i = 0 ; i <= nStepX ; ++ i) { + Point3d ptP = Point3d( i * dStep, j * dStep, dDimZ) ; + PtrOwner myPtGrid( CreateGeoPoint3d()) ; + myPtGrid->Set( ptP) ; + vvpGObj[0].emplace_back( static_cast( Release( myPtGrid))) ; + vvCol[0].emplace_back( BLUE) ; + } + } + // 2° gruppo, superfici + CISURFTMPVECTOR myStmVector = cavTstm.GetvStm() ; + for ( int i = 0 ; i < int( myStmVector.size()) ; ++ i) { + PtrOwner pMyStm( CloneSurfTriMesh( myStmVector[i])) ; + if ( ! IsNull( pMyStm)) { + pMyStm->ToLoc( frGrid) ; + vvpGObj[1].emplace_back( static_cast( Release( pMyStm))) ; + vvCol[1].emplace_back( Color( 0., 1., 0., .5)) ; + } + } + #endif + + // vettore delle polyline visitate ( viste però come curve composite) + ICRVCOMPOPOVECTOR vPL_AsCompo ; vPL_AsCompo.reserve( vPL.size()) ; + // scorro i Chunk della matrice di interi, quindi le righe for ( int nChunk = 0 ; nChunk < int( mIndMat.size()) ; ++ nChunk) { // scorro le PolyLinee presenti nel Chunk - for ( int nPol = 0 ; nPol < int( vPL.size()) ; ++ nPol) { + for ( int nLoop = 0 ; nLoop < int( mIndMat[nChunk].size()) ; ++ nLoop) { + // recupero l'indice della PolyLine di riferimento + int nPol = mIndMat[nChunk][nLoop] ; + if ( nPol < 0 || nPol >= int( vPL.size())) + return false ; // essendo chiusa, se presenti meno di 4 punti, non faccio nulla int nPts = vPL[nPol].GetPointNbr() ; if ( nPts < 4) @@ -380,33 +414,6 @@ TestEdgesClosedPolyLines( POLYLINEVECTOR& vPL, const CAvToolSurfTm& cavTstm, int vAdvPt.emplace_back( make_pair( myPt, PointType::VALID)) ; #if ENABLE_SHARPED_EDGES_DEBUG - vector> vvpGObj ; vvpGObj.resize( 7) ; - vector> vvCol ; vvCol.resize( 7) ; - // ombra del tool - PtrOwner pCrvToolShape( CreateCurveArc()) ; - pCrvToolShape->Set( ORIG, Z_AX, cavTstm.GetToolRadius()) ; - // 1° gruppo, griglia di punti - for ( int j = 0 ; j <= nStepY ; ++ j) { - for ( int i = 0 ; i <= nStepX ; ++ i) { - Point3d ptP = Point3d( i * dStep, j * dStep, dDimZ) ; - PtrOwner myPtGrid( CreateGeoPoint3d()) ; - myPtGrid->Set( ptP) ; - vvpGObj[0].emplace_back( static_cast( Release( myPtGrid))) ; - vvCol[0].emplace_back( BLUE) ; - break ; - } - break ; - } - // 2° gruppo, superfici - CISURFTMPVECTOR myStmVector = cavTstm.GetvStm() ; - for ( int i = 0 ; i < int( myStmVector.size()) ; ++ i) { - PtrOwner pMyStm( CloneSurfTriMesh( myStmVector[i])) ; - if ( ! IsNull( pMyStm)) { - pMyStm->ToLoc( frGrid) ; - vvpGObj[1].emplace_back( static_cast( Release( pMyStm))) ; - vvCol[1].emplace_back( Color( 0., 1., 0., .5)) ; - } - } // 3° gruppo, punti della PolyLine for ( int i = 0 ; i < int( vAdvPt.size()) ; ++ i) { PtrOwner myPt( CreateGeoPoint3d()) ; @@ -416,23 +423,23 @@ TestEdgesClosedPolyLines( POLYLINEVECTOR& vPL, const CAvToolSurfTm& cavTstm, int } #endif - // modifico la posizione dei punti - if ( ! ModifyPolyLineToSharped( vAdvPt, cavTstm, frGrid, dAngTol, dStep, dSegLen)) - return false ; + // modifico la posizione dei punti + if ( ! ModifyPolyLineToSharped( vAdvPt, cavTstm, frGrid, dAngTol, dStep, dSegLen)) + return false ; - // ricostrusico la polyLine - vPL[nPol].Clear() ; + // ricostrusico la polyLine a partire da una vuota + PolyLine PL_New ; double dPar = -1 ; for ( int j = 0 ; j < int( vAdvPt.size()) ; ++ j) { // se punto valido o sharped di angolo interno, lo aggiungo if ( j == 0 || j == int( vAdvPt.size() - 1) || vAdvPt[j].second == PointType::VALID || vAdvPt[j].second == PointType::SHARPED_INT) - vPL[nPol].AddUPoint( ++ dPar, vAdvPt[j].first) ; + PL_New.AddUPoint( ++ dPar, vAdvPt[j].first) ; // se è un punto sharped di un angolo esterno else if ( vAdvPt[j].second == PointType::SHARPED_EXT) { // se non richiesto il calcolo avanzato del punto a minima distanza dallo spigolo, aggiungo il punto if ( ! bAdvCorners) - vPL[nPol].AddUPoint( ++ dPar, vAdvPt[j].first) ; + PL_New.AddUPoint( ++ dPar, vAdvPt[j].first) ; else { // ricavo il punto a minima distanza dal materiale mediante metodo di bisezione Vector3d vtPrev = ( vAdvPt[j-1].first - vAdvPt[j].first) ; @@ -463,51 +470,29 @@ TestEdgesClosedPolyLines( POLYLINEVECTOR& vPL, const CAvToolSurfTm& cavTstm, int DistPointLine distPtLSucc( ptTest, vAdvPt[j].first, vAdvPt[j+1].first) ; distPtLPrev.GetMinDistPoint( ptMinDistA) ; distPtLSucc.GetMinDistPoint( ptMinDistB) ; - vPL[nPol].AddUPoint( ++ dPar, ptMinDistA) ; - vPL[nPol].AddUPoint( ++ dPar, ptTest) ; - vPL[nPol].AddUPoint( ++ dPar, ptMinDistB) ; - } + PL_New.AddUPoint( ++ dPar, ptMinDistA) ; + PL_New.AddUPoint( ++ dPar, ptTest) ; + PL_New.AddUPoint( ++ dPar, ptMinDistB) ; - #if ENABLE_SHARPED_EDGES_DEBUG - // 5° gruppo, punti minDist A e B e ptMid - /*PtrOwner myPtA( CreateGeoPoint3d()) ; - myPtA->Set( ptMinDistA) ; - vvpGObj[4].emplace_back( static_cast( Release( myPtA))) ; - vvCol[4].emplace_back( BROWN) ; - PtrOwner myPtB( CreateGeoPoint3d()) ; - myPtB->Set( ptMinDistB) ; - vvpGObj[4].emplace_back( static_cast( Release( myPtB))) ; - vvCol[4].emplace_back( BROWN) ; - PtrOwner myPtMid( CreateGeoPoint3d()) ; - myPtMid->Set( ptTest) ; - vvpGObj[4].emplace_back( static_cast( Release( myPtMid))) ; - vvCol[4].emplace_back( BROWN) ;*/ - #endif + #if ENABLE_SHARPED_EDGES_DEBUG + // 5° gruppo, punti minDist A e B e ptMid + PtrOwner myPtA( CreateGeoPoint3d()) ; + myPtA->Set( ptMinDistA) ; + vvpGObj[4].emplace_back( static_cast( Release( myPtA))) ; + vvCol[4].emplace_back( BROWN) ; + PtrOwner myPtB( CreateGeoPoint3d()) ; + myPtB->Set( ptMinDistB) ; + vvpGObj[4].emplace_back( static_cast( Release( myPtB))) ; + vvCol[4].emplace_back( BROWN) ; + PtrOwner myPtMid( CreateGeoPoint3d()) ; + myPtMid->Set( ptTest) ; + vvpGObj[4].emplace_back( static_cast( Release( myPtMid))) ; + vvCol[4].emplace_back( BROWN) ; + #endif + } } } - // riposiziono la polyLine - #if ENABLE_SHARPED_EDGES_DEBUG - // 6° gruppo, curve composita derivante dalla polyline - PtrOwner pCrvCompoPoly( CreateCurveComposite()) ; - pCrvCompoPoly->FromPolyLine( vPL[nPol]) ; - //pCrvCompoPoly->SetExtrusion( frGrid.VersZ()) ; - vvpGObj[5].emplace_back( static_cast( CloneCurveComposite( pCrvCompoPoly))) ; - vvCol[5].emplace_back( RED) ; - // 7° gruppo, controOffset - OffsetCurve offsCrv ; - offsCrv.Make( pCrvCompoPoly, - ( cavTstm.GetToolRadius() - 2 * EPS_SMALL), ICurve::OFF_EXTEND) ; - pCrvCompoPoly.Set( ConvertCurveToComposite( offsCrv.GetLongerCurve())) ; - vvpGObj[6].emplace_back( static_cast( Release( pCrvCompoPoly))) ; - vvCol[6].emplace_back( WHITE) ; - string myName = Sharped_Edges_Debug_File_Name + - to_string( nChunk) + "_" + - to_string( nPol) + "_" + - to_string( dLevel) + "_" + - to_string( dAngTol) + ".nge" ; - SaveGeoObj( vvpGObj, vvCol, myName) ; - #endif - // se la polyLinea si autointerseca, allora non la modifico ( essendo a distanza R dalla // trimesh rischio di evere Chunk distinti uniti in un unico Chunk PtrOwner pCompo( CreateCurveComposite()) ; @@ -515,11 +500,53 @@ TestEdgesClosedPolyLines( POLYLINEVECTOR& vPL, const CAvToolSurfTm& cavTstm, int return false ; pCompo->FromPolyLine( vPL[nPol]) ; SelfIntersCurve SIC( *pCompo) ; - if ( SIC.GetCrossOrOverlapIntersCount() > 0) - continue ; + bool bDiscard = ( SIC.GetCrossOrOverlapIntersCount() > 0) ; + if ( ! bDiscard) { + // se la polyLine interseca una delle PolyLine precedenti, non la modifico + for ( auto& pCompoPL_Prev : vPL_AsCompo) { + IntersCurveCurve ICC( *pCompo, *pCompoPL_Prev) ; + if ( ICC.GetCrossOrOverlapIntersCount() > 0) { + bDiscard = true ; + break ; + } + } + } + + // se nuova approssimazione da conservare, memorizzo i risultati + if ( ! bDiscard) { + vPL[nPol] = PL_New ; + vPL_AsCompo.emplace_back( Release( pCompo)) ; + } } } + #if ENABLE_SHARPED_EDGES_DEBUG + ICURVEPVECTOR vpCrv ; vpCrv.reserve( vPL.size()) ; + for ( const auto& PL : vPL) { + // 6° gruppo, curve composita derivante dalla polyline + PtrOwner pCrvCompoPoly( CreateCurveComposite()) ; + pCrvCompoPoly->FromPolyLine( PL) ; + vvpGObj[5].emplace_back( static_cast( CloneCurveComposite( pCrvCompoPoly))) ; + vvCol[5].emplace_back( RED) ; + vpCrv.emplace_back( Release( pCrvCompoPoly)) ; + } + // 7° gruppo, controOffset + ICURVEPOVECTOR vCrvCompoOffs ; + if ( ! CalcOffsetCurves( vpCrv, vCrvCompoOffs, - ( cavTstm.GetToolRadius() - 2 * EPS_SMALL), ICurve::OFF_EXTEND)) { + for ( auto& pCrv : vpCrv) { delete( pCrv) ; pCrv = nullptr ;} + return false ; + } + for ( auto& pCrv : vpCrv) { delete( pCrv) ; pCrv = nullptr ;} + for ( const auto& pCvrOffs : vCrvCompoOffs) { + vvpGObj[6].emplace_back( static_cast( CloneCurveComposite( pCvrOffs))) ; + vvCol[6].emplace_back( WHITE) ; + } + string myName = Sharped_Edges_Debug_File_Name + + to_string( dLevel) + "_" + + to_string( dAngTol) + ".nge" ; + SaveGeoObj( vvpGObj, vvCol, myName) ; + #endif + return true ; } @@ -785,21 +812,31 @@ MarchingSquares( const DBLVECTOR& vdGrid, int nStepX, int nStepY, double dStep, if ( TestEdgesClosedPolyLines( vPL_Sharped, cavTstm, nStepX, nStepY, frGrid, dDimZ, dLevel, dStep, ANG_TOL_STD_DEG, false)) swap( vPL_Sharped, vPL) ; + // se vettore di PolyLine vuoto, non faccio nulla + if ( vPL.empty()) + return true ; + // se non ho impostato un utensile, devo effettuare un contro-offset if ( ! bTool) { - POLYLINEVECTOR vPL_Offs ; - for ( int i = 0 ; i < int( vPL.size()) ; ++ i) { - CurveComposite crvCompo ; - if ( ! crvCompo.FromPolyLine( vPL[i])) - return false ; - OffsetCurve offsCompo ; - offsCompo.Make( &crvCompo, - ( dRad - 2 * EPS_SMALL), ICurve::OFF_EXTEND) ; - PtrOwner pCrvOffset( offsCompo.GetLongerCurve()) ; - while ( ! IsNull( pCrvOffset)) { + ICURVEPOVECTOR vpOwCrv ; vpOwCrv.reserve( vPL.size()) ; + ICURVEPVECTOR vpCrv ; vpCrv.reserve( vPL.size()) ; + for ( const auto& PL : vPL) { + PtrOwner pCrvCompoPoly( CreateCurveComposite()) ; + pCrvCompoPoly->FromPolyLine( PL) ; + vpOwCrv.emplace_back( Release( pCrvCompoPoly)) ; + vpCrv.emplace_back( vpOwCrv.back()) ; + } + // calcolo l'Offset + ICURVEPOVECTOR vpCrvOffs ; + if ( ! CalcOffsetCurves( vpCrv, vpCrvOffs, - ( dRad - 2 * EPS_SMALL), ICurve::OFF_EXTEND)) + return false ; + // resituisco le PolyLine + POLYLINEVECTOR vPL_Offs ; vPL_Offs.reserve( vpCrvOffs.size()) ; + for ( auto& pCrv : vpCrvOffs) { + if ( pCrv != nullptr && pCrv->IsValid()) { PolyLine myPolyLine ; - pCrvOffset->ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, myPolyLine) ; + pCrv->ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, myPolyLine) ; vPL_Offs.emplace_back( myPolyLine) ; - pCrvOffset.Set( offsCompo.GetLongerCurve()) ; } } swap( vPL_Offs, vPL) ; @@ -976,28 +1013,13 @@ CAvParSilhouettesSurfTm::Prepare( void) return false ; b3All.Add( b3Surf) ; } - - // calcolo dati della griglia - const double EXTRA_XY = ( m_bTool ? m_dRad + 2 : 1.5 * m_dTol) ; + // espansione in Z del Box const double EXTRA_Z = 10 * m_dTol + ( m_dMaxDepth > EPS_SMALL ? max( 0., m_dMaxDepth - b3All.GetDimZ()) : 0) ; - b3All.Expand( EXTRA_XY, EXTRA_XY, EXTRA_Z) ; - m_nStepX = int( ceil( b3All.GetDimX() / m_dTol)) ; - m_nStepY = int( ceil( b3All.GetDimY() / m_dTol)) ; - m_frGrid.ChangeOrig( GetToGlob( b3All.GetMin(), m_frGrid)) ; + b3All.Expand( 0., 0., EXTRA_Z) ; m_dDimZ = b3All.GetDimZ() ; - m_dLevelOffs = - b3All.GetMin().z ; - // calcolo dei punti della griglia (sul top del cilindro) - PNTUVECTOR vPntM( ( m_nStepX + 1) * ( m_nStepY + 1)) ; - for ( int j = 0 ; j <= m_nStepY ; ++ j) { - for ( int i = 0 ; i <= m_nStepX ; ++ i) { - int nInd = i + j * ( m_nStepX + 1) ; - Point3d ptP = GetToGlob( Point3d( i * m_dTol, j * m_dTol, m_dDimZ), m_frGrid) ; - vPntM[nInd] = { ptP, 0.} ; - } - } - - // esecuzione della verifica + // set utensile corrente per calcolo delle collisioni + double dExtraXY = m_dRad ; if ( m_dSideAng < EPS_ANG_SMALL) m_cavTstm.SetStdTool( m_dDimZ + m_dOffsR, m_dRad + m_dOffsR, m_dCornRad + m_dOffsR) ; else { @@ -1015,8 +1037,29 @@ CAvParSilhouettesSurfTm::Prepare( void) double dStemRad = m_dRad + dDeltaRad ; double dTipRad = m_dRad ; + dExtraXY = dStemRad ; m_cavTstm.SetAdvTool( m_dDimZ + m_dOffsR, dStemRad + m_dOffsR, m_dMaxMat, dTipRad + m_dOffsR, m_dCornRad + m_dOffsR) ; } + + // calcolo dati della griglia + const double EXTRA_XY = ( m_bTool ? dExtraXY + 2. : 1.5 * m_dTol) ; + b3All.Expand( EXTRA_XY, EXTRA_XY, 0.) ; + m_frGrid.ChangeOrig( GetToGlob( b3All.GetMin(), m_frGrid)) ; + m_dLevelOffs = - b3All.GetMin().z ; + m_nStepX = int( ceil( b3All.GetDimX() / m_dTol)) ; + m_nStepY = int( ceil( b3All.GetDimY() / m_dTol)) ; + + // calcolo dei punti della griglia (sul top del cilindro) + PNTUVECTOR vPntM( ( m_nStepX + 1) * ( m_nStepY + 1)) ; + for ( int j = 0 ; j <= m_nStepY ; ++ j) { + for ( int i = 0 ; i <= m_nStepX ; ++ i) { + int nInd = i + j * ( m_nStepX + 1) ; + Point3d ptP = GetToGlob( Point3d( i * m_dTol, j * m_dTol, m_dDimZ), m_frGrid) ; + vPntM[nInd] = { ptP, 0.} ; + } + } + + // esecuzione verifica della collisione if ( m_vpStm.empty() || ! m_cavTstm.SetSurfTm( *( m_vpStm[0]))) return false ; for ( int k = 1 ; k < int( m_vpStm.size()) ; ++ k) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index d98d22d..8e0baa2 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -56,6 +56,7 @@ struct PocketParams { double dMaxOptSize = 0. ; // dimensione per ottimizzazione double dAngle = 0. ; // angolo per orientare le passate OneWay e ZigZag double dLiTang = INFINITO ; // valore di LeadIn in ingresso + bool bCalcUnclearedRegs = true ; // flag per calcolare o meno le regioni non svuotate bool bOptOffsets = true ; // flag per evitare Offset non necessari bool bAboveHead = true ; // flag per testa da sopra ( Z+) bool bSmooth = false ; // curve smussate @@ -398,6 +399,16 @@ AssignFeedZigZagOneWay( ICurveComposite* pCompo, const bool bIsLink, const ICURV return true ; } +//---------------------------------------------------------------------------- +static bool +SwapSideBySecondTempParam( ICurveComposite* pCompo) +{ + if ( pCompo == nullptr || ! pCompo->IsValid()) + return false ; + pCompo->SetTempParam( int( pCompo->GetTempParam( 1)) == MDS_LEFT ? MDS_RIGHT : MDS_LEFT, 1) ; + return true ; +} + //---------------------------------------------------------------------------- static bool CheckSimpleOverlap( const ICurve* pCrv, const ICurveComposite* pCrvOri, int& nStat, double dToll) @@ -462,7 +473,7 @@ AssignFeedForOpenEdge( ICurveComposite* pCrv, const ISurfFlatRegion* pSfrOpenEdg pNewCrv->SetTempProp( pCrv->GetTempProp( 0), 0) ; pNewCrv->SetTempProp( pCrv->GetTempProp( 1), 1) ; pNewCrv->SetTempParam( pCrv->GetTempParam( 0), 0) ; - pNewCrv->SetTempParam( pCrv->GetTempParam( 0), 0) ; + pNewCrv->SetTempParam( pCrv->GetTempParam( 1), 1) ; double dThick ; pCrv->GetThickness( dThick) ; pNewCrv->SetThickness( dThick) ; Vector3d vtExtr ; pCrv->GetExtrusion( vtExtr) ; @@ -4784,7 +4795,7 @@ CalcSpecialBoundedSmoothedLink( const Point3d& ptStart, const Vector3d& vtStart, pZigZagLink->AddLine( ptNew) ; } - // questa composita contiene al massimo 5 curve e, in generale, quella una curva molto più lunga + // questa composita contiene al massimo 5 curve e, in generale, una curva molto più lunga // delle altre ( quella che collega le due estensioni calcolate). Spezzo la composita ottenuta in curve // la cui lunghezza massima è circa il raggio utensile PolyLine PL ; @@ -4965,12 +4976,14 @@ CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, const ICRVCOM double dLenS ; pCrvS->GetLength( dLenS) ; double dLenE ; pCrvE->GetLength( dLenE) ; - // se ho una curva di primo Offset allora non devo accorciarla ( sia per bordi esterni che per isole) + // azzero i parametri per curve di primo Offset for ( int i = 0 ; i < int( vFirstOffset.size()) ; ++ i) { if ( vFirstOffset[i]->IsPointOn( ptSS) && vFirstOffset[i]->IsPointOn( ptSE)) dLenPercS = 0. ; - if ( vFirstOffset[i]->IsPointOn( ptES) && vFirstOffset[i]->IsPointOn( ptEE)) - dLenPercE = 0. ; + #if 0 + if ( vFirstOffset[i]->IsPointOn( ptES) && vFirstOffset[i]->IsPointOn( ptEE)) + dLenPercE = 0. ; + #endif } #if 0 // nel caso volessi estendere anche prima del punto finale double dLStepS = ( dLenPercS < EPS_SMALL ? 0. : PockParams.dRad) ; @@ -5025,14 +5038,17 @@ CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, const ICRVCOM //---------------------------------------------------------- static bool -GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, - const ISurfFlatRegion* pSfrOrig, const PocketParams& PockParams, ISurfFlatRegion* pSrfToCut) +GetUnclearedRegionAndSetFeed( const ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, + const ISurfFlatRegion* pSfrOrig, const PocketParams& PockParams, ISurfFlatRegion* pSfrUncleared) { + // se non devo nè calcolare la Feed nè calcolare le regioni svuotate, allora non faccio nulla + if ( ! PockParams.bCalcFeed && ! PockParams.bCalcUnclearedRegs) + return true ; // controllo dei parametri if ( vFirstOffs.empty() || int( vOffs.size()) < int( vFirstOffs.size())) return false ; - pSrfToCut->Clear() ; + pSfrUncleared->Clear() ; // creo la regione esterna ( definita dalle curve di primo Offset) // NB. Questa regione è diversa dalla pSfrOrig : @@ -5053,7 +5069,7 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& } } - // 2) creo la regione che all'esterno contiene i lati aperti + // creo la regione che all'esterno contiene i lati aperti // NB. Prendendo la superficie originale ( con lati Open/Close impostati), se effettuo un // Offset interno dell'estensione degli aperti, tutto ciò che è all'esterno di tale regione è classificato // come lato aperto @@ -5081,6 +5097,9 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& // recupero le proprietà temporanee int nProp0 = vOffs[i]->GetTempProp( 0) ; int nProp1 = vOffs[i]->GetTempProp( 1) ; + // il primo TempParam viene settato in proporzione alla Feed + // il secondo TempParam contiene l'nSide della curva + double dTempPar1 = vOffs[i]->GetTempParam( 1) ; // Feed bool bFirstOffs = false ; @@ -5100,10 +5119,11 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& if ( ! pSfrTool->IsValid() || pSfrTool->GetChunkCount() == 0) pSfrTool.Set( pSrfToolOffs) ; else - pSfrTool->Add( *pSrfToolOffs) ; + pSfrTool->Add( *pSrfToolOffs) ; } vOffs[i]->SetTempProp( nProp0, 0) ; vOffs[i]->SetTempProp( nProp1, 1) ; + vOffs[i]->SetTempParam( dTempPar1, 1) ; // ================= LINK ================================ int nLink_Ind = ( bFollowOrder ? i + 1 : i) ; @@ -5125,7 +5145,7 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& if ( ! IsNull( pSfrToolLink)) { if ( ! pSfrTool->IsValid() || pSfrTool->GetChunkCount() == 0) pSfrTool.Set( pSfrToolLink) ; - else + else pSfrTool->Add( *pSfrToolLink) ; } // risetto il Link come curva composita ... @@ -5136,10 +5156,12 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& } - // 4) Creo la regione contenente tutte le parti non svuotate - pSrfToCut->CopyFrom( pSrfExtern) ; - if ( ! pSrfToCut->Subtract( *pSfrTool)) - return false ; + // se rischiesto, creo la regione contenente tutte le parti non svuotate + if ( PockParams.bCalcUnclearedRegs) { + pSfrUncleared->CopyFrom( pSrfExtern) ; + if ( ! pSfrUncleared->Subtract( *pSfrTool)) + return false ; + } return true ; } @@ -5150,12 +5172,13 @@ ChooseCurveForRemovingUnclearedRegion( const ICRVCOMPOPOVECTOR& vOffs, const ICR const Point3d& ptToGo, const PocketParams& PockParams, int& nInd, Point3d& ptCloser, bool& bFirstOffs) { - /* - E' richiesto che le curve di Offset presentino le seguenti TempProps : - - TempProp0 -> Offset progressivo ricavato ( 0, 1, 2, ... nMaxIter) [per CONFORMAL] - - TempProp1 -> parte esterna della curva ( MDS_LEFT o MDS_LEFT) [per CONFORMAL] - [per SPIRAL le proprietà sono ricavate automaticamente] - */ + // E' richiesto che le curve di Offset presentino le seguenti proprietà : + // - CONFORMAL + // * TempProp0 -> Offset progressivo ricavato ( 0, 1, 2, ... nMaxIter) + // * TempProp1 -> parte esterna della curva ( MDS_LEFT o MDS_RIGHT) + // - SPIRAL + // * vOffsFirstCurve -> per capire se l'Offset corrente è di primo Offset o meno + // * TempParam1 -> parte esterna della curva ( MDS_LEFT o MDS_RIGHT) // controllo dei parametri nInd = -1 ; @@ -5177,10 +5200,8 @@ ChooseCurveForRemovingUnclearedRegion( const ICRVCOMPOPOVECTOR& vOffs, const ICR vOffsPtMinDist[i].nInd = i ; // nel caso di Conformal, escludo le curve di primo Offset dalla ricerca if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG || PockParams.nType == POCKET_CONFORMAL_ONEWAY) { - bool bSkip = false ; - for ( int j = 0 ; j < int( vOffsFirstCurve.size()) && ! bSkip ; ++ j) - bSkip = ( vOffs[i]->GetTempProp( 0) == 0) ; // prima iterazione - if ( bSkip) { + // prima iterazione + if ( vOffs[i]->GetTempProp( 0) == 0) { vOffsPtMinDist[i].bFirstOffs = true ; continue ; } @@ -5190,26 +5211,16 @@ ChooseCurveForRemovingUnclearedRegion( const ICRVCOMPOPOVECTOR& vOffs, const ICR // in questo modo riesco a creare le curve a ricciolo int nSide ; DistPointCurve DistPtCrv( ptToGo, *vOffs[i]) ; - bool bFirstBorderIsland = false ; if ( DistPtCrv.GetSideAtMinDistPoint( EPS_SMALL, Z_AX, nSide)) { // nel caso Spiral if ( PockParams.nType == POCKET_SPIRALIN || PockParams.nType == POCKET_SPIRALOUT) { // InVsOut - vOffsPtMinDist[i].bInVsOut = ( ( ! PockParams.bInvert && nSide == MDS_LEFT) || - ( PockParams.bInvert && nSide == MDS_RIGHT)) ; + vOffsPtMinDist[i].bInVsOut = ( int( vOffs[i]->GetTempParam( 1) != nSide)) ; // controllo se la curva in questione è di primo Offset Point3d ptCheck ; vOffs[i]->GetStartPoint( ptCheck) ; for ( int j = 0 ; j < int( vOffsFirstCurve.size()) ; ++ j) { if ( vOffsFirstCurve[j]->IsPointOn( ptCheck, 100 * EPS_SMALL)) { vOffsPtMinDist[i].bFirstOffs = true ; - // controllo se Isola o di bordo - double dArea = 0. ; - vOffs[i]->GetAreaXY( dArea) ; - bFirstBorderIsland = ( ( ! PockParams.bInvert && dArea < 0.) || - ( PockParams.bInvert && dArea > 0.)) ; - // se isola di primo Offset, InVsOut va invertito - if ( bFirstBorderIsland) - vOffsPtMinDist[i].bInVsOut = ( ! vOffsPtMinDist[i].bInVsOut) ; break ; } } @@ -5228,7 +5239,7 @@ ChooseCurveForRemovingUnclearedRegion( const ICRVCOMPOPOVECTOR& vOffs, const ICR PockParams.dSideStep + PockParams.dSideStep ; } // se curva di bordo esterno, aggiungo un'altra penalità ( euristica) - if ( vOffsPtMinDist[i].bFirstOffs && ! bFirstBorderIsland) + if ( vOffsPtMinDist[i].bFirstOffs) vOffsPtMinDist[i].dSqDist *= 2. ; } } @@ -5249,12 +5260,17 @@ static bool RemoveUnclearedRegions( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs, ICRVCOMPOPOVECTOR& vOffsFirstCurve, const PocketParams& PockParams) { - /* - E' richiesto che le curve di Offset presentino le seguenti TempProps : - - TempProp0 -> Offset progressivo ricavato ( 0, 1, 2, ... nMaxIter) [per CONFORMAL] - - TempProp1 -> parte esterna della curva ( MDS_LEFT o MDS_LEFT) [per CONFORMAL] - [per SPIRAL le proprietà sono ricavate automaticamente] - */ + // se non devo calcolare le regioni non svuotate, esco subito + if ( ! PockParams.bCalcUnclearedRegs) + return true ; + + // E' richiesto che le curve di Offset presentino le seguenti proprietà : + // - CONFORMAL + // * TempProp0 -> Offset progressivo ricavato ( 0, 1, 2, ... nMaxIter) + // * TempProp1 -> parte esterna della curva ( MDS_LEFT o MDS_RIGHT) + // - SPIRAL + // * vOffsFirstCurve -> per capire se l'Offset corrente è di primo Offset o meno + // * TempParam1 -> parte esterna della curva ( MDS_LEFT o MDS_RIGHT) // se non ho nessuna superficie valida da svuotare, allora esco if ( pSfrUncleared == nullptr) @@ -5267,17 +5283,15 @@ RemoveUnclearedRegions( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& for ( int nC = 0 ; nC < pSfrUncleared->GetChunkCount() ; ++ nC) { // recupero il centroide del Chunk da rimuovere Point3d ptCentroid ; pSfrUncleared->GetChunkCentroid( nC, ptCentroid) ; - /* - Tra tutte le curve di Offset escludo le curve che : - - Sono di primo Offset - - Non contengono il centroide ( condizione già verificata per quelle di primo Offset) - ... cerco la più vicina tra le rimanenti - */ + // Tra tutte le curve di Offset escludo le curve che : + // - Sono di primo Offset + // - Non contengono il centroide ( condizione già verificata per quelle di primo Offset) + // ... cerco la più vicina tra le rimanenti // recupero la curva migliore int nInd = -1 ; Point3d ptCloser ; bool bFirstOffs = false ; - if ( ! ChooseCurveForRemovingUnclearedRegion( vOffs, vOffsFirstCurve, ptCentroid, PockParams, + if ( ! ChooseCurveForRemovingUnclearedRegion( vOffs, vOffsFirstCurve, ptCentroid, PockParams, nInd, ptCloser, bFirstOffs)) return false ; // se nessun indice trovato, salto il chunk @@ -5570,6 +5584,9 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con vLinks.clear() ; vLinks.resize( int( vOffs.size())) ; + // NB. Dato che le curve di Offset sono invertite a seconda di dove si trova il materiale, + // Utilizzo il secondo TempParam per evere l'nSide + // scorro tutte le curva di Offset for ( int i = 0 ; i < int( vOffs.size()) - 1 ; ++ i) { @@ -5577,6 +5594,7 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con Point3d ptS ; if ( ! vOffs[i]->GetStartPoint( ptS)) return false ; + // tra le curve successive cerco la curva interna e più vicina ad essa int nNextInd = -1 ; // indice della curva successiva double dMinDist = INFINITO ; // distanza tra questa curva e la successiva @@ -5588,8 +5606,8 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con // se interna if ( IntCC.GetCurveClassification( 1, EPS_SMALL, ccClass) && int( ccClass.size()) == 1 && - ( ( ! PockParams.bInvert && ccClass[0].nClass == CRVC_IN) || - ( PockParams.bInvert && ccClass[0].nClass == CRVC_OUT))) { + ( ( ccClass[0].nClass == CRVC_IN && int( vOffs[i]->GetTempParam( 1)) == MDS_RIGHT) || + ( ccClass[0].nClass == CRVC_OUT && int( vOffs[i]->GetTempParam( 1)) == MDS_LEFT))) { // calcolo la distanza minima tra essa int nFlag ; double dPar = 0. ; @@ -5649,13 +5667,14 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con // scambio la curva i+1 esima con la j-esima ( se non sono già in ordine) if ( nNextInd != i + 1) swap( vOffs[nNextInd], vOffs[i+1]) ; + // cambio il suo punto iniziale nel punto più vicino tovato double dUS ; if ( ! vOffs[i+1]->GetParamAtPoint( ptStartNext, dUS, EPS_SMALL)) return false ; vOffs[i+1]->ChangeStartPoint( dUS) ; - // accorcio la curva per raccordarmi in tangenza con la successiva + // se ho più di una curva di Offset if ( int( vOffs.size()) > 1) { // clono le curve i ed i+1 esime ( nel caso non riuscissi ad accorciarle o raccordarle ) PtrOwner pCrv_i( vOffs[i]->Clone()) ; @@ -5666,15 +5685,14 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con PtrOwner pCrvLink( CreateCurveComposite()) ; if ( IsNull( pCrvLink)) return false ; - // NB. Le curve di Offset da tagliare non devono essere quelle di primo Offset double dLenPercS = ( i == 0 ? 0. : 10 * EPS_SMALL) ; double dLenPercE = ( bMinDistAtSmooth ? 0. : 10 * EPS_SMALL) ; if ( ! CutCurveToConnect( vOffs[i], vOffs[i+1], vOffsFirstCurve, PockParams, dLenPercS, dLenPercE, pCrvLink) || ! pCrvLink->IsValid()) { // se non sono riuscito, cerco una strada più semplice ripristinando le curve pCrvLink->Clear() ; - vOffs[i].Set( pCrv_i) ; // chiuso - vOffs[i+1].Set( pCrv_ii) ; // chiuso + vOffs[i].Set( pCrv_i) ; + vOffs[i+1].Set( pCrv_ii) ; // recupero i vettori tangenti iniziali ( le curve sono chiuse ) Vector3d vtS, vtE ; if ( ! vOffs[i]->GetStartDir( vtS) || ! vOffs[i+1]->GetStartDir( vtE)) @@ -5728,6 +5746,10 @@ CheckIfOffsetIsNecessary( const ISurfFlatRegion* pSfrAct, const ICurveComposite* if ( ! PockParams.bOptOffsets) return true ; + // se spiral out non vanno eliminati parti di percorso + if ( PockParams.nType == POCKET_SPIRALOUT) + return true ; + if ( nIter != 0) { // controllo se sono almeno al secondo offset... // per ogni curva controllo se il suo Offset massimo non genera alcuna regione double dMaxOffs ; @@ -5819,6 +5841,55 @@ IsCompoMadeBy2DifferentHomogeneousParts( const ICurveComposite* pCompo, const Po return true ; } +//---------------------------------------------------------------------------- +static int +CalcInversionForSpiralOffset( const ISurfFlatRegion* pSfrChunk) +{ + // controllo validità della regione + if ( pSfrChunk == nullptr || ! pSfrChunk->IsValid()) + return -1 ; + + // Caso 0 : Non esistono isole + // Caso 1 : Loop Esterno Chiuso e, se esiste, Isola Chiusa + // Caso 2 : Loop Esterno Chiuso e, se esiste, Isola Aperta + // Caso 3 : Loop Esterno Aperto e, se esiste, Isola Chiusa + // Caso 4 : Loop Esterno Aperto e, se esiste, Isola Aperta + + // se non esistono isole, allora Caso 0 + if ( pSfrChunk->GetLoopCount( 0) == 1) + return 0 ; + + // Il Loop esterno è considerato chiuso <=> esiste almeno una curva chiusa + bool bExtClosed = false ; + for ( int nU = 0 ; nU < pSfrChunk->GetLoopCurveCount( 0, 0) && ! bExtClosed ; ++ nU) { + int nTempProp = TEMP_PROP_INVALID ; + bExtClosed = ( pSfrChunk->GetCurveTempProp( 0, 0, nU, nTempProp) && + nTempProp == TEMP_PROP_CLOSE_EDGE) ; + } + + // Le isole vengono classificate come tutte chiuse <=> esiste almeno un isola chiusa + bool bIntClosed = false ; + for ( int nLoop = 1 ; nLoop < pSfrChunk->GetLoopCount( 0) && ! bIntClosed ; ++ nLoop) { + for ( int nU = 0 ; nU < pSfrChunk->GetLoopCurveCount( 0, nLoop) && ! bIntClosed ; ++ nU) { + int nTempProp = TEMP_PROP_INVALID ; + bIntClosed = ( pSfrChunk->GetCurveTempProp( 0, nLoop, nU, nTempProp) && + nTempProp == TEMP_PROP_CLOSE_EDGE) ; + } + } + + // restituisco il caso corrente + if ( bExtClosed && bIntClosed) + return 1 ; + if ( bExtClosed && ! bIntClosed) + return 2 ; + if ( ! bExtClosed && bIntClosed) + return 3 ; + if ( ! bExtClosed && ! bIntClosed) + return 4 ; + + return -1 ; +} + //---------------------------------------------------------------------------- static bool CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, const PocketParams& PockParams, int& nReg, Point3d& ptStart, @@ -5833,14 +5904,19 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co // ciclo di offset verso l'interno const int MAX_ITER = 1000 ; int nIter = 0 ; - ICRVCOMPOPOVECTOR vOffs ; // vettore delle curve di offset - ICRVCOMPOPOVECTOR vOffsFirstCurve ; // curve di primo offset + ICRVCOMPOPOVECTOR vOffs ; // vettore delle curve di offset + ICRVCOMPOPOVECTOR vOffsFirstCurve ; // curve di primo offset // tengo una copia della regione corrente da svuotare PtrOwner pSrfAct( CloneSurfFlatRegion( pSfrPock)) ; if ( IsNull( pSrfAct) || pSrfAct->GetChunkCount() == 0) return false ; + // ricavo il tipo di relazione descritta tra Open/Close di bordo esterno e/o isole + int nCase = CalcInversionForSpiralOffset( pSrfAct) ; + if ( nCase == -1) + return false ; + // ricavo le regioni progressive double dOffsPrec = 0. ; int nCrvFirstOffs = 0 ; @@ -5858,12 +5934,15 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co // se primo Offset if ( nIter == 0) { + // aggiorno il nuovo valore delle regioni totali di primo Offset int my_nReg = nReg ; - nReg = pSfrOffsVR->GetChunkCount() ; // aggiorno il nuovo valore delle regioni totali di primo Offset + nReg = pSfrOffsVR->GetChunkCount() ; // gli Offset progressivi appartengono al Chunk nReg-esimo pSrfAct.Set( pSfrOffsVR->CloneChunk( my_nReg)) ; - if ( IsNull( pSrfAct)) // se supero i chunk ottenuti + // se supero i chunk ottenuti + if ( IsNull( pSrfAct)) return true ; + // imposto la regione id svuotatura corrente pSfrOffsVR.Set( pSrfAct->Clone()) ; } @@ -5873,24 +5952,28 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co for ( int i = 0 ; i < nChunks ; ++ i) { // per ogni chunk... int nLoops = pSfrOffsVR->GetLoopCount( i) ; - for ( int j = 0 ; j < nLoops ; ++ j) { + for ( int j = 0 ; j < nLoops ; ++ j) { // per ogni loop... PtrOwner pCrvCompoBorder( ConvertCurveToComposite( pSfrOffsVR->GetLoop( i, j))) ; if ( IsNull( pCrvCompoBorder) || ! pCrvCompoBorder->IsValid()) return false ; - /* - Il materiale deve sempre trovarsi alla destra ( se bInvert -> alla sinistra) del tool - soltanto sul primo bordo; Nel caso di isole aperte o nelle passate di Offset intermedio - l'orientamente non ha importanza. - */ - if ( nIter != 0 && j > 0) // inverto l'orientamento delle curve interne ( offset delle isole trovate) - pCrvCompoBorder->Invert() ; // controllo quali regioni di Offset possono essere sostituite bool bInsert = true ; if ( ! CheckIfOffsetIsNecessary( pSrfAct, pCrvCompoBorder, dOffs, dOffsPrec, nIter, PockParams, bInsert)) return false ; - if ( bInsert) + if ( bInsert) { + // imposto come secondo TempParam il Side di classificazione + pCrvCompoBorder->SetTempParam( j == 0 ? MDS_RIGHT : MDS_LEFT, 1) ; + // stabilisco l'orientamento della curva + if ( ( nCase == 1 && nIter != 0 && j > 0) || + ( nCase == 2 && j > 0) || + ( nCase == 3 && j == 0) || + ( nCase == 4 && j > 0)) { + pCrvCompoBorder->Invert() ; + SwapSideBySecondTempParam( pCrvCompoBorder) ; + } vOffs.emplace_back( Release( pCrvCompoBorder)) ; + } if ( nIter == 0) { // salvo il bordo per i link ( non invertiti, devo sapere IN/OUT) PtrOwner pCrvCompoExtBorder( ConvertCurveToComposite( pSfrOffsVR->GetLoop( i, j))) ; vOffsFirstCurve.emplace_back( Release( pCrvCompoExtBorder)) ; @@ -5917,9 +6000,12 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co dOffs = PockParams.dSideStep ; } } - // se devo usare un Offset più piccolo... - else if ( ! bSmallRad) + // se non ho Chunks e devo usare un Offset più piccolo... + else if ( ! bSmallRad) { + if ( PockParams.dRad < EPS_SMALL) + break ; dOffs = dOffsPrec + ( nIter == 0 ? PockParams.dRad + PockParams.dRadialOffset : PockParams.dRad) ; + } // altrimenti ho finito la regione da svuotare... else break ; @@ -5936,11 +6022,12 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co Point3d ptNewStart ; // Se ho come lavorazione uno SpiralIn posso poter entrare dalle isole aperte... - int nIndexSwap = 0 ; // indice del vettore di curve per identificare la curva su cui entrare + int nIndexSwap = 0 ; if ( PockParams.nType == POCKET_SPIRALIN) { if ( SetAdvancedPtStartForPath( vOffsFirstCurve, PockParams, pSfrPock, ptRef, ptStart, - vtMidOut, bMidOut, nIndexSwap, vCrvOrigChunkLoops)) + vtMidOut, bMidOut, nIndexSwap, vCrvOrigChunkLoops)) { vOffsFirstCurve[nIndexSwap]->GetStartPoint( ptNewStart) ; + } else return false ; } @@ -5954,8 +6041,10 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co // se richiesta inversione if ( PockParams.bInvert) { - for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) + for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) { vOffs[i]->Invert() ; + SwapSideBySecondTempParam( vOffs[i]) ; + } } // smusso le curve di offset ( ad eccezione di quelle di primo Offset) @@ -5975,10 +6064,6 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co vOffs[0]->SetTempParam( 0., 0) ; // prima iterazione // riordino le curve e creo i collegamenti - /* - Se richiesto parametro di smusso, tutti gli Offset ( ad eccezione di quelli generati alla - prima iterazione vengono tagliati, quindi diventano aperti - */ ICURVEPOVECTOR vLinks( vOffs.size()) ; if ( ! CreateSpiralPocketingPath( vOffs, vLinks, PockParams, vOffsFirstCurve)) return false ; @@ -5996,9 +6081,8 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co // se collegamento da aggiungere if ( ! IsNull( vLinks[i])) { // accodo nel percorso di lavorazione - if ( ! pMCrv->AddCurve( Release( vLinks[i]))) { + if ( ! pMCrv->AddCurve( Release( vLinks[i]))) return false ; - } } pMCrv->AddCurve( Release( vOffs[i])) ; } @@ -7063,8 +7147,8 @@ AddOneWay( ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, PocketPar //---------------------------------------------------------------------------- static bool -SmoothLinkByOffs( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, ICurveComposite* pCrvLink, - const PocketParams& PockParams, bool bFirstOffs0, bool bFirstOffs1, double dSmoothPar, double dTol) +SmoothLinkByOffs( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, ICurveComposite* pCrvLink, + const PocketParams& PockParams, bool bFirstOffs0, bool bFirstOffs1, double dSmoothPar, double dTol) { // controllo dei parametri @@ -7073,53 +7157,79 @@ SmoothLinkByOffs( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, ICurve pCrvLink == nullptr || ! pCrvLink->IsValid()) return false ; - // curva precedente + // definisco la lunghezza del segmento iniziale e finale sulle due curve di Offset + double dRefLenSeg = 2. * dSmoothPar ; + + // --- Curva precedente --- + // recupero la lunghezza e il dominio del primo Offset + double dLen ; + pCrvOffs0->GetLength( dLen) ; + double dUStart, dUEnd ; + pCrvOffs0->GetDomain( dUStart, dUEnd) ; + // inizializzo la curva PtrOwner pCrvBef( CreateCurveComposite()) ; if ( IsNull( pCrvBef)) return false ; + // se primo Offset di bordo o chiuso... if ( bFirstOffs0 && pCrvOffs0->IsClosed()) { - const ICurve* pCrvFirst = pCrvOffs0->GetFirstCurve() ; - if ( pCrvFirst == nullptr || ! pCrvFirst->IsValid()) - return false ; - PtrOwner pMyCrv( pCrvFirst->Clone()) ; + double dU = dUEnd ; + if ( dLen > dRefLenSeg - EPS_SMALL) + pCrvOffs0->GetParamAtLength( dRefLenSeg, dU) ; + PtrOwner pMyCrv( pCrvOffs0->CopyParamRange( dUStart, dU)) ; if ( IsNull( pMyCrv) || ! pMyCrv->IsValid()) return false ; pCrvBef->AddCurve( Release( pMyCrv)) ; } + // altrimenti... else { - const ICurve* pCrvLast = pCrvOffs0->GetLastCurve() ; - if ( pCrvLast == nullptr || ! pCrvLast->IsValid()) - return false ; - PtrOwner pMyCrv( pCrvLast->Clone()) ; + double dU = dUStart ; + if ( dLen > dRefLenSeg) + pCrvOffs0->GetParamAtLength( dLen - dRefLenSeg, dU) ; + PtrOwner pMyCrv( pCrvOffs0->CopyParamRange( dU, dUEnd)) ; if ( IsNull( pMyCrv) || ! pMyCrv->IsValid()) return false ; pCrvBef->AddCurve( Release( pMyCrv)) ; } + // se non valida, errore + if ( ! pCrvBef->IsValid()) + return false ; - // curva successiva + // --- Curva successiva --- + // recupero la lunghezza e il dominio del primo Offset + pCrvOffs1->GetLength( dLen) ; + pCrvOffs1->GetDomain( dUStart, dUEnd) ; + // inizializzo la curva PtrOwner pCrvAft( CreateCurveComposite()) ; if ( IsNull( pCrvAft)) return false ; - const ICurve* pCrvFirst = pCrvOffs1->GetFirstCurve() ; - if ( pCrvFirst == nullptr || ! pCrvFirst->IsValid()) - return false ; - PtrOwner pMyCrv( pCrvFirst->Clone()) ; + // calcolo il parametro di taglio + double dU = dUEnd ; + if ( dLen > dRefLenSeg - EPS_SMALL) + pCrvOffs1->GetParamAtLength( dRefLenSeg, dU) ; + PtrOwner pMyCrv( pCrvOffs1->CopyParamRange( dUStart, dU)) ; if ( IsNull( pMyCrv) || ! pMyCrv->IsValid()) return false ; pCrvAft->AddCurve( Release( pMyCrv)) ; + // se non valida, errore + if ( ! pCrvAft->IsValid()) + return false ; - // controllo la validità delle curve precedenti e successive ricavate - if ( IsNull( pCrvBef) || IsNull( pCrvAft) || ! pCrvBef->IsValid() || ! pCrvAft->IsValid()) - return false ; - // estendo il Link + // estendo il Link ( linea di ingresso, segmento Link, linea d'uscita) pCrvLink->AddCurve( Release( pCrvBef), false, dTol) ; pCrvLink->AddCurve( Release( pCrvAft), true, dTol) ; - // smusso + + // miglioro la curva + pCrvLink->MergeCurves( 100 * EPS_SMALL, ANG_TOL_STD_DEG) ; + + // smusso la curva ModifyCurveToSmoothed( pCrvLink, PockParams, dSmoothPar, dSmoothPar, false) ; - // toglo gli estremi + + // toglo gli estremi, il Link è in tangenza e le linee di ingresso e d'uscita sono più + // estese dell'arco di smusso creato delete( pCrvLink->RemoveFirstOrLastCurve( false)) ; delete( pCrvLink->RemoveFirstOrLastCurve( true)) ; - // modifico Offset0 per raccordarlo al nuovo Link + + // modifico il primo Offset per raccordarlo al nuovo Link if ( bFirstOffs0 && pCrvOffs0->IsClosed()) { const ICurve* pCrvFirst = pCrvLink->GetFirstCurve() ; if ( pCrvFirst == nullptr || ! pCrvFirst->IsValid()) @@ -7135,7 +7245,8 @@ SmoothLinkByOffs( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, ICurve double dUE ; pCrvOffs0->GetParamAtPoint( ptS, dUE, dTol) ; pCrvOffs0->TrimEndAtParam( dUE) ; } - // modifico Offset1 per raccordarlo al nuovo Link + + // modifico il secondo Offset per raccordarlo al nuovo Link Point3d ptE ; pCrvLink->GetEndPoint( ptE) ; double dUS ; pCrvOffs1->GetParamAtPoint( ptE, dUS, dTol) ; if ( bFirstOffs1 && pCrvOffs1->IsClosed()) @@ -7195,8 +7306,8 @@ GetConformalLinkForOpenCrv( const ICurveComposite* pCrvOffs0, const ICurveCompos //---------------------------------------------------------------------------- static bool -GetConformalLink( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, PocketParams& PockParams, - const ICRVCOMPOPOVECTOR& vCrvClassBorder, ICurveComposite* pCrvLink) +CalcConformalLink( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, PocketParams& PockParams, + const ICRVCOMPOPOVECTOR& vCrvClassBorder, ICurveComposite* pCrvLink) { // controllo validità delle due curve di Offset if ( pCrvOffs0 == nullptr || ! pCrvOffs0->IsValid() || @@ -7248,10 +7359,16 @@ GetConformalLink( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, Pocket ICRVCOMPOPOVECTOR vCrvChunk ; for ( int i = 0 ; i < int( vIndOffs0.size()) ; ++ i) vCrvChunk.emplace_back( vCrvClassBorder[vIndOffs0[i]]->Clone()) ; + // se la curva successiva è chiusa, aggiorno il suo punto iniziale a quello a minima distanza + if ( ! bOpen1) { + Point3d ptS ; pCrvOffs0->GetStartPoint( ptS) ; + double dPar ; + int nFlag ; + if ( DistPointCurve( ptS, *pCrvOffs1).GetParamAtMinDistPoint( 0., dPar, nFlag)) + pCrvOffs1->ChangeStartPoint( dPar) ; + } if ( ! CutCurveToConnect( pCrvOffs0, pCrvOffs1, vCrvChunk, PockParams, - ( ( bOpen0 || bFirstIterOffs0) ? 0. : 10 * EPS_SMALL), - ( ( bOpen1 || bFirstIterOffs1) ? 0. : 10 * EPS_SMALL), - pCrvLink) || + bOpen0 ? 0. : 10 * EPS_SMALL, bOpen1 ? 0. : 10 * EPS_SMALL, pCrvLink) || ! pCrvLink->IsValid()) { // se curva di Link non valida, cerco una strada più semplice pCrvLink->Clear() ; @@ -7778,7 +7895,7 @@ CalcConformalOffsAndLinks( VICRVCOMPOPOVECTOR& vvCrvOffs, const ISurfFlatRegion* if ( IsNull( pCrvLink)) return false ; // se non calcolabile, allora retroazione, altrimenti lo memorizzo - if ( ! GetConformalLink( vCrvOffs[i], vCrvOffs[i+1], PockParams, vCrvSfrClass, pCrvLink) || + if ( ! CalcConformalLink( vCrvOffs[i], vCrvOffs[i+1], PockParams, vCrvSfrClass, pCrvLink) || IsNull( pCrvLink) || ! pCrvLink->IsValid() || pCrvLink->GetCurveCount() == 0) vCrvLink.resize( int( vCrvLink.size()) + 1) ; else @@ -8808,7 +8925,7 @@ SmoothExtensionLinesByIntersection( ICRVCOMPOPOVECTOR& vCrvPaths, const PocketPa //---------------------------------------------------------------------------- bool CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double dStep, double dAngle, - double dOpenMinSafe, int nType, bool bSmooth, bool bInvert, bool bAvoidOpt, bool bAllowZigZagOneWayBorders, + double dOpenMinSafe, int nType, bool bSmooth, bool bCalcUnclReg, bool bInvert, bool bAvoidOpt, bool bAllowZigZagOneWayBorders, bool bCalcFeed, const Point3d& ptEndPrec, const ISurfFlatRegion* pSfrLimit, bool bAllOffs, double dMaxOptSize, double dLiTang, int nLiType, ICRVCOMPOPOVECTOR& vCrvCompoRes) { @@ -8831,6 +8948,7 @@ CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double myParams.dAngle = dAngle ; myParams.dSideStep = dStep ; myParams.dOpenMinSafe = dOpenMinSafe ; + myParams.bCalcUnclearedRegs = bCalcUnclReg ; myParams.bInvert = bInvert ; myParams.bAvoidOpt = bAvoidOpt ; myParams.bCalcFeed = bCalcFeed ; diff --git a/CurveAux.cpp b/CurveAux.cpp index a47fb8e..78f5258 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -2087,6 +2087,51 @@ CalcCurveSingleCurvesOffset( const ICurve& crvC, ICURVEPOVECTOR& vCrvs, double d return pVoronoiObj->CalcSingleCurvesOffset( vCrvs, dOffs) ; } +//---------------------------------------------------------------------------- +bool CalcOffsetCurves( const ICURVEPVECTOR& vpCrvs, ICURVEPOVECTOR& vCrvs, double dOffs, int nType) +{ + // creo oggetto Voronoi con le curve passate + PtrOwner pVoronoiObj( new( std::nothrow) Voronoi()) ; + if ( pVoronoiObj == nullptr) + return false ; + for ( int i = 0 ; i < int( vpCrvs.size()) ; i ++) { + if ( ! pVoronoiObj->AddCurve( vpCrvs[i])) + return false ; + } + + return pVoronoiObj->CalcOffset( vCrvs, dOffs, nType) ; +} + +//---------------------------------------------------------------------------- +bool CalcFatOffsetCurves( const ICURVEPVECTOR& vpCrvs, ICURVEPOVECTOR& vCrvs, double dOffs, + bool bSquareEnds, bool bSquareMids, bool bMergeOnlySameProps) +{ + // controllo validità delle curve + for ( auto& pCrv : vpCrvs) { + if ( pCrv == nullptr) + return false ; + } + // se offset nullo restituisco direttamente le curve + if ( abs( dOffs) < EPS_SMALL) { + for ( auto& pCrv : vpCrvs) { + if ( ! vCrvs.emplace_back( pCrv->Clone())) + return false ; + } + return true ; + } + + // creo oggetto Voronoi con le curve passate + PtrOwner pVoronoiObj( new( std::nothrow) Voronoi()) ; + if ( pVoronoiObj == nullptr) + return false ; + for ( int i = 0 ; i < int( vpCrvs.size()) ; i ++) { + if ( ! pVoronoiObj->AddCurve( vpCrvs[i])) + return false ; + } + + return pVoronoiObj->CalcFatCurve( vCrvs, dOffs, bSquareEnds, bSquareMids, bMergeOnlySameProps) ; +} + //---------------------------------------------------------------------------- void ResetCurveVoronoi( const ICurve& crvC) diff --git a/CurveComposite.cpp b/CurveComposite.cpp index fa9f197..a364a5f 100644 --- a/CurveComposite.cpp +++ b/CurveComposite.cpp @@ -224,8 +224,11 @@ CurveComposite::AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart, double dLinT // lunghezza della curva originale double dOldLen ; pCrv->GetLength( dOldLen) ; // eseguo modifica - if ( ! pCrv->ModifyStart( ptEnd)) - return false ; + if ( ! pCrv->ModifyStart( ptEnd)) { + CurveLine crvLine ; + if ( ! crvLine.Set( ptEnd, ptCrvEnd) || ! pCrv.Set( crvLine.Clone())) + return false ; + } // verifico che la lunghezza non sia variata troppo double dNewLen ; pCrv->GetLength( dNewLen) ; if ( abs( dNewLen - dOldLen) > 10 * dLinTol) @@ -246,8 +249,11 @@ CurveComposite::AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart, double dLinT // lunghezza della curva originale double dOldLen ; pCrv->GetLength( dOldLen) ; // eseguo modifica - if ( ! pCrv->ModifyEnd( ptStart)) - return false ; + if ( ! pCrv->ModifyEnd( ptStart)) { + CurveLine crvLine ; + if ( ! crvLine.Set( ptCrvStart, ptStart) || ! pCrv.Set( crvLine.Clone())) + return false ; + } // verifico che la lunghezza non sia variata troppo double dNewLen ; pCrv->GetLength( dNewLen) ; if ( abs( dNewLen - dOldLen) > 10 * dLinTol) diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index bfc6520..8574b8e 100644 Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index b8b6bc4..b9099fc 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -345,6 +345,7 @@ copy $(TargetPath) \EgtProg\Dll64 + diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index 6120010..68e0c44 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -550,7 +550,7 @@ File di origine\Geo - File di origine\Geo + File di origine\GeoOffset @@ -1232,6 +1232,9 @@ File di intestazione + + File di intestazione\Include + diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index 0461250..725eb83 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -234,12 +234,12 @@ SurfTriMesh::AddTriangle( const int nIdVert[3], int nTFlag) m_vPart.clear() ; m_OGrMgr.Reset() ; ResetHashGrids3d() ; + if ( ! vtN.Normalize( EPS_ZERO)) + return SVT_DEL ; // inserisco il triangolo try { m_vTria.emplace_back( nIdVert, nTFlag) ;} catch(...) { return SVT_NULL ;} // aggiorno la sua normale - if ( ! vtN.Normalize( EPS_ZERO)) - return false ; m_vTria.back().vtN = vtN ; // aggiorno massimo TFlag m_nMaxTFlag = max( m_nMaxTFlag, nTFlag) ; @@ -4029,6 +4029,56 @@ SurfTriMesh::CloneShell( int nShell) const return Release( pSurfTM) ; } +//---------------------------------------------------------------------------- +bool +SurfTriMesh::GetPartLocalBBox( int nP, BBox3d& b3Loc) const +{ + // verifico esistenza della parte + if ( nP < 0 || nP >= GetPartCount()) + return false ; + + // assegno il box in locale + b3Loc.Reset() ; + for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) { + // recupero il vettore delle Shell della parte corrente + const auto& vShell = m_vPart[nP].vShell ; + // scorro i triangoli validi contenuti nella Shell + if ( m_vTria[i].nIdVert[0] != SVT_DEL && + find( vShell.begin(), vShell.end(), m_vTria[i].nShell) != vShell.end()) { + // ciclo sui tre vertici + for ( int j = 0 ; j < 3 ; ++ j) + b3Loc.Add( m_vVert[m_vTria[i].nIdVert[j]].ptP) ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::GetPartBBox( int nP, const Frame3d& frRef, BBox3d& b3Ref) const +{ + // verifico esistenza della parte + if ( nP < 0 || nP >= GetPartCount()) + return false ; + + // assegno il box in locale + b3Ref.Reset() ; + for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) { + // recupero il vettore delle Shell della parte corrente + const auto& vShell = m_vPart[nP].vShell ; + // scorro i triangoli validi contenuti nella Shell + if ( m_vTria[i].nIdVert[0] != SVT_DEL && + find( vShell.begin(), vShell.end(), m_vTria[i].nShell) != vShell.end()) { + // ciclo sui tre vertici + for ( int j = 0 ; j < 3 ; ++ j) + b3Ref.Add( GetToGlob( m_vVert[m_vTria[i].nIdVert[j]].ptP, frRef)) ; + } + } + + return true ; +} + //---------------------------------------------------------------------------- int SurfTriMesh::GetPartCount( void) const diff --git a/SurfTriMesh.h b/SurfTriMesh.h index 36cc13a..8c5a650 100644 --- a/SurfTriMesh.h +++ b/SurfTriMesh.h @@ -337,6 +337,8 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW bool GetShellArea( int nShell, double& dArea) const override ; bool RemoveShell( int nShell) override ; SurfTriMesh* CloneShell( int nShell) const override ; + bool GetPartLocalBBox( int nP, BBox3d& b3Loc) const override ; + bool GetPartBBox( int nP, const Frame3d& frRef, BBox3d& b3Ref) const override ; int GetPartCount( void) const override ; bool RemovePart( int nPart) override ; bool GetPartArea( int nPart, double& dArea) const override ; diff --git a/SurfTriMeshOffset.cpp b/SurfTriMeshOffset.cpp index 666e863..dba93f3 100644 --- a/SurfTriMeshOffset.cpp +++ b/SurfTriMeshOffset.cpp @@ -1,19 +1,21 @@ //---------------------------------------------------------------------------- -// EgalTech 2014-2022 +// EgalTech 2025 //---------------------------------------------------------------------------- -// File : SurfTriMeshOffset.cpp Data : 10.06.25 Versione : 2.7e4 +// File : SurfTriMeshOffset.cpp Data : 07.07.25 Versione : 2.7g1 // Contenuto : Implementazione funzione per Offset di Superfici TriMesh. // // // // Modifiche : 10.06.25 RE Creazione modulo. +// 10.06.25 RE Offset di superfici chiuse. +// 04.07.25 RE Thickening Offset di superfici generiche. // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" -#include "SurfTriMesh.h" #include "VolZmap.h" +#include "\EgtDev\Include\EGkSurfTriMeshAux.h" using namespace std ; @@ -44,32 +46,71 @@ SumStm( const CISURFTMPVECTOR& vStm) } //---------------------------------------------------------------------------- -/* Funzione che crea l'Offset di una superficie TriMesh chiusa */ +// Funzione che crea l'Offset di una superficie TriMesh +//---------------------------------------------------------------------------- ISurfTriMesh* -CreateSurfTriMeshOffset( const ISurfTriMesh* pStm, double dOffs, double dLinTol) +CreateSurfTriMeshOffset( const ISurfTriMesh* pStm, double dOffs, double dPrec, int nType) { - return CreateSurfTriMeshesOffset( { pStm}, dOffs, dLinTol) ; + return ( CreateSurfTriMeshesOffset( { pStm}, dOffs, dPrec, nType)) ; } //---------------------------------------------------------------------------- -/* Funzione che crea l'Offset di un insieme di superfici */ +// Funzione che crea il Fat Offset di una superficie TriMesh +//---------------------------------------------------------------------------- ISurfTriMesh* -CreateSurfTriMeshesOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dLinTol) +CreateSurfTriMeshThickeningOffset( const ISurfTriMesh* pStm, double dOffs, double dPrec, int nType) +{ + return ( CreateSurfTriMeshesThickeningOffset( { pStm}, dOffs, dPrec, nType)) ; +} + +//---------------------------------------------------------------------------- +// Funzione che crea l'Offset di un insieme di superfici +//---------------------------------------------------------------------------- +ISurfTriMesh* +CreateSurfTriMeshesOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dPrec, int nType) { // se vettore delle superfici vuoto, non faccio nulla if ( vStm.empty()) return nullptr ; // controllo sul valore di tolleranza lineare - double dMyLinTol = max( dLinTol, 10 * EPS_SMALL) ; + double dMyPrec = max( dPrec, 100 * EPS_SMALL) ; // --- NB. ( Il valore di Offset deve essere maggiore di 10 * EPS_SMALL in valore assoluto) // Nel caso sia minore, restituisco semplicemente la somma delle superfici // ( questo valore serve per rimanere coerente con l'Offset delle curve) if ( abs( dOffs) < 10 * EPS_SMALL) return SumStm( vStm) ; - // --- NB. Per la creazione dello Zmap è necessario che le superfici siano chiuse + + // creo lo Zmap associato alle superfici TriMesh PtrOwner pVolZmap( CreateVolZmap()) ; - if ( IsNull( pVolZmap) || ! pVolZmap->CreateFromTriMeshOffset( vStm, dOffs, dMyLinTol)) + if ( IsNull( pVolZmap) || ! pVolZmap->CreateFromTriMeshOffset( vStm, dOffs, dMyPrec, nType)) return nullptr ; + // restituisco la superficie TriMesh return ( pVolZmap->GetSurfTriMesh()) ; -} \ No newline at end of file +} + +//---------------------------------------------------------------------------- +//* Funzione che crea il Fat Offset di un insieme di superfici +//---------------------------------------------------------------------------- +ISurfTriMesh* +CreateSurfTriMeshesThickeningOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dPrec, int nType) +{ + // se vettore delle superfici vuoto, non faccio nulla + if ( vStm.empty()) + return nullptr ; + // controllo sul valore di tolleranza lineare + double dMyPrec = max( dPrec, 100 * EPS_SMALL) ; + // --- NB. ( Il valore di Offset deve essere maggiore di 10 * EPS_SMALL in valore assoluto) + // Nel caso sia minore, restituisco semplicemente la somma delle superfici + // ( questo valore serve per rimanere coerente con l'Offset delle curve) + if ( abs( dOffs) < 10 * EPS_SMALL) + return SumStm( vStm) ; + + // creo lo Zmap associato alle superfici TriMesh + PtrOwner pVolZmap( CreateVolZmap()) ; + if ( IsNull( pVolZmap) || ! pVolZmap->CreateFromTriMeshThickeningOffset( vStm, dOffs, dMyPrec, nType)) + return nullptr ; + + // restituisco la superficie TriMesh + return ( pVolZmap->GetSurfTriMesh()) ; +} diff --git a/VolZmap.h b/VolZmap.h index 825acb9..30a27e0 100644 --- a/VolZmap.h +++ b/VolZmap.h @@ -85,8 +85,9 @@ class VolZmap : public IVolZmap, public IGeoObjRW bool Create( const Point3d& ptO, double dDimX, double dDimY, double dDimZ, double dStep, bool bTriDex) override ; bool CreateEmpty( const Point3d& ptO, double dDimX, double dDimY, double dDimZ, double dStep, bool bTriDex) override ; bool CreateFromFlatRegion( const ISurfFlatRegion& Surf, double dDimZ, double dStep, bool bTriDex) override ; - bool CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex, double dExtraBox = 100 * EPS_SMALL) override ; - bool CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) override ; + bool CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex, double dExtraBox = 0.) override ; + bool CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol, int nType = STMOFF_FILLET) override ; + bool CreateFromTriMeshThickeningOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol, int nType = STMOFF_FILLET) override ; int GetBlockCount( void) const override ; int GetBlockUpdatingCounter( int nBlock) const override ; bool GetBlockTriangles( int nBlock, TRIA3DEXVECTOR& vTria) const override ; @@ -461,8 +462,13 @@ class VolZmap : public IVolZmap, public IGeoObjRW bool SubtractMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig, const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ; // Funzioni per Offset di superfici - bool CreateOffsSphereOnVertex( const Point3d& ptV, double dOffs, int nGrid) ; - bool CreateOffsCylinderOnEdge( const Point3d& ptP1, const Point3d& ptP2, double dOffs, int nGrid) ; + bool InitVolZMapOffs( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) ; + bool InitVolZMapThickeningOffs( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) ; + bool UpdateVolZMapByOpenSurfFilletOffset( const ISurfTriMesh* Surf, double dOffs, double dTol) ; + bool UpdateVolZMapByClosedSurfFilletOffset( const ISurfTriMesh* Surf, double dOffs, double dTol) ; + bool UpdateVolZMapBySurfThickeningFilletOffset( const ISurfTriMesh* Surf, double dOffs, double dTol) ; + bool CreateOffsSphereOnVertex( const Point3d& ptV, double dOffs, int nGrid, int nVertexType = 0) ; + bool CreateOffsCylinderOnEdge( const Point3d& ptP1, const Point3d& ptP2, double dOffs, int nGrid, int nVertexType = 0) ; bool SubtractIntervalsForOffset( int nGrid, int nI, int nJ, double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax, int nToolNum, bool bSkipSwap = false) ; diff --git a/VolZmapCreation.cpp b/VolZmapCreation.cpp index fef6eae..f1a7a80 100644 --- a/VolZmapCreation.cpp +++ b/VolZmapCreation.cpp @@ -802,7 +802,8 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex // Il dexel se parte da un triangolo della trimesh può non trovare l'intersezione, // quindi espandiamo il bounding box per ovviare al problema. - SurfBBox.Expand( dExtraBox) ; + if ( dExtraBox > EPS_ZERO) + SurfBBox.Expand( dExtraBox) ; // Determino i punti estremi del bounding box Point3d ptMapOrig, ptMapEnd ; @@ -920,7 +921,7 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex m_dMaxZ[2] = ( bTriDex ? vtLen.y : 0) ; // Tipologia - m_nShape = ( IsBox() ? BOX : GENERIC) ; + m_nShape = ( dExtraBox > EPS_ZERO && IsBox() ? BOX : GENERIC) ; // Aggiornamento dello stato m_nStatus = OK ; diff --git a/VolZmapOffset.cpp b/VolZmapOffset.cpp index 1812b0a..3907beb 100644 --- a/VolZmapOffset.cpp +++ b/VolZmapOffset.cpp @@ -23,36 +23,36 @@ using namespace std ; - //---------------------------------------------------------------------------- -/* Funzione per aggiungere intervalli lungo un Dexel per l'offset di una superficie TriMesh */ +// Funzione per sottrarre intervalli lungo un Dexel per l'offset di una superficie TriMesh +//---------------------------------------------------------------------------- bool VolZmap::SubtractIntervalsForOffset( int nGrid, int nI, int nJ, double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax, int nToolNum, bool bSkipSwap) { - // per ora la funzione è la stessa della differenza in generale // TODO -- Aggiustare eventuali tolleranze return SubtractIntervals( nGrid, nI, nJ, dMin, dMax, vtNMin, vtNMax, nToolNum, bSkipSwap) ; } //---------------------------------------------------------------------------- -/* Funzione per aggiungere intervalli lungo un Dexel per l'offset di una superficie TriMesh */ +// Funzione per aggiungere intervalli lungo un Dexel per l'offset di una superficie TriMesh +//---------------------------------------------------------------------------- bool VolZmap::AddIntervalsForOffset( int nGrid, int nI, int nJ, double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax, int nToolNum, bool bSkipSwap) { - // per ora la funzione è la stessa della somma generale // TODO -- Aggiustare eventuali tolleranze return AddIntervals( nGrid, nI, nJ, dMin, dMax, vtNMin, vtNMax, nToolNum, bSkipSwap) ; } //---------------------------------------------------------------------------- -/* Funzione per la creazione di una sfera di Offset centrata sul vertice di una TriMesh con cui - aggiungere o sottrarre intervalli lungo i Dexel coinvolti */ +// Funzione per la creazione di una sfera di Offset centrata sul vertice di una TriMesh con cui +// aggiungere o sottrarre intervalli lungo i Dexel coinvolti +//---------------------------------------------------------------------------- bool -VolZmap::CreateOffsSphereOnVertex( const Point3d& ptV, double dOffs, int nGrid) +VolZmap::CreateOffsSphereOnVertex( const Point3d& ptV, double dOffs, int nGrid, int nTool) { // determino il Box della sfera posizionata su tale vertice BBox3d BBoxSphere( ptV - dOffs * Vector3d( 1., 1., 1.), @@ -78,9 +78,9 @@ VolZmap::CreateOffsSphereOnVertex( const Point3d& ptV, double dOffs, int nGrid) Vector3d vtNmax = Point3d( dX, dY, dMax) - ptV ; vtNmax.Normalize() ; if ( dOffs > 0.) - AddIntervalsForOffset( nGrid, i, j, dMin, dMax, vtNmin, vtNmax, 0) ; + AddIntervalsForOffset( nGrid, i, j, dMin, dMax, vtNmin, vtNmax, nTool) ; else - SubtractIntervalsForOffset( nGrid, i, j, dMin, dMax, -vtNmin, -vtNmax, 0) ; + SubtractIntervalsForOffset( nGrid, i, j, dMin, dMax, -vtNmin, -vtNmax, nTool) ; } } } @@ -89,10 +89,12 @@ VolZmap::CreateOffsSphereOnVertex( const Point3d& ptV, double dOffs, int nGrid) } //---------------------------------------------------------------------------- -/* Funzione per la creazione di un cilindro di Offset sul vertice di una TriMesh con cui - aggiungere o sottrarre intervalli lungo i Dexel coinvolti */ +// Funzione per la creazione di un cilindro di Offset sul vertice di una TriMesh con cui +// aggiungere o sottrarre intervalli lungo i Dexel coinvolti. +//---------------------------------------------------------------------------- bool -VolZmap::CreateOffsCylinderOnEdge( const Point3d& ptP1, const Point3d& ptP2, double dOffs, int nGrid) +VolZmap::CreateOffsCylinderOnEdge( const Point3d& ptP1, const Point3d& ptP2, double dOffs, int nGrid, + int nTool) { // determino la lunghezza dello spigolo corrente double dH = Dist( ptP1, ptP2) ; @@ -131,9 +133,9 @@ VolZmap::CreateOffsCylinderOnEdge( const Point3d& ptP1, const Point3d& ptP2, dou if ( IntersLineCylinder( ptC, Z_AX, CylFrame, dH, abs( dOffs), true, true, ptInt1, vtN1, ptInt2, vtN2)) { if ( dOffs > 0.) - AddIntervalsForOffset( nGrid, i, j, ptInt1.z, ptInt2.z, -vtN1, -vtN2, 0) ; + AddIntervalsForOffset( nGrid, i, j, ptInt1.z, ptInt2.z, -vtN1, -vtN2, nTool) ; else - SubtractIntervalsForOffset( nGrid, i, j, ptInt1.z, ptInt2.z, vtN1, vtN2, 0) ; + SubtractIntervalsForOffset( nGrid, i, j, ptInt1.z, ptInt2.z, vtN1, vtN2, nTool) ; } } } @@ -142,10 +144,351 @@ VolZmap::CreateOffsCylinderOnEdge( const Point3d& ptP1, const Point3d& ptP2, dou } //---------------------------------------------------------------------------- -/* Funzione per la creazine di uno Zmap di Offset (positivo o negativo) a partire da una - superficie TriMesh */ +// Funzione per inizializzare lo ZMap a partire da un vettore di superfici TriMesh +// L'idea è quella di creare uno ZMap a partire dal Box complessivo delle superfici TriMesh : +// - le superfici chiuse possono già inserire i rispettivi spilloni +// - le superfici aperte non danno contributo +//---------------------------------------------------------------------------- bool -VolZmap::CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) +VolZmap::InitVolZMapOffs( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) +{ + // se non ho superfici, non faccio nulla + if ( vSurf.empty()) + return true ; + // controllo delle superfici + for ( const ISurfTriMesh* Surf : vSurf) { + if ( Surf == nullptr) + return false ; + } + + // definisco la tolleranza di espansione del Box per la creazione dellop ZMap + double dBoxExpansion = ( abs( dOffs) + 1.5 * dTol) + 10 * EPS_SMALL ; + + // --- se una sola superficie + if ( int( vSurf.size()) == 1) { + // controllo la validità della superficie + if ( ! vSurf[0]->IsValid() || vSurf[0]->GetTriangleCount() == 0) + return true ; + // --- se superficie chiusa posso direttamente creare lo Zmap iniziale + if ( vSurf[0]->IsClosed()) { + // definisco lo Zamp a partire dall'espansione del Box della superficie + if ( ! CreateFromTriMesh( *vSurf[0], dTol, true, dBoxExpansion)) + return false ; + } + // --- se superficie aperta, lo creo inizialmente vuoto a partire dal suo Box + BBox3d BBoxSurf ; + vSurf[0]->GetLocalBBox( BBoxSurf) ; + BBoxSurf.Expand( dBoxExpansion) ; + if ( ! CreateEmpty( BBoxSurf.GetMin(), BBoxSurf.GetDimX(), BBoxSurf.GetDimY(), BBoxSurf.GetDimZ(), dTol, true)) + return false ; + } + // --- se più superfici + else { + // calcolo il Box complessivo + BBox3d BBoxGlob ; + for ( const ISurfTriMesh* Surf : vSurf) { + // controllo la validità della superficie + if ( ! Surf->IsValid() || Surf->GetTriangleCount() == 0) + continue ; + // calcolo il Box della superficie + BBox3d BBoxSurf ; Surf->GetLocalBBox( BBoxSurf) ; + // aggiungo il Box a quello complessivo + BBoxGlob.Add( BBoxSurf) ; + } + // definisco uno Zmap vuoto a partire dal Box + BBoxGlob.Expand( dBoxExpansion) ; + if ( ! CreateEmpty( BBoxGlob.GetMin(), BBoxGlob.GetDimX(), BBoxGlob.GetDimY(), BBoxGlob.GetDimZ(), dTol, true)) + return false ; + // aggiungo tutte le superfici chiuse + for ( const ISurfTriMesh* Surf : vSurf) { + if ( ! Surf->IsValid() || Surf->GetTriangleCount() == 0 || ! Surf->IsClosed()) + continue ; + if ( ! AddSurfTm( Surf)) + return false ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +// Funzione per inizializzare lo ZMap a partire da un vettore di superfici TriMesh +// L'idea è quella di creare uno ZMap vuoto a partire dal Box complessivo delle superfici TriMesh +//---------------------------------------------------------------------------- +bool +VolZmap::InitVolZMapThickeningOffs( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) +{ + // se non ho superfici, non faccio nulla + if ( vSurf.empty()) + return true ; + // controllo delle superfici + for ( const ISurfTriMesh* Surf : vSurf) { + if ( Surf == nullptr) + return false ; + } + + // definisco la tolleranza di espansione del Box per la creazione dellop ZMap + double dBoxExpansion = ( abs( dOffs) + 1.5 * dTol) + 10 * EPS_SMALL ; + + // calcolo il Box complessivo + BBox3d BBoxGlob ; + for ( const ISurfTriMesh* Surf : vSurf) { + // controllo la validità della superficie + if ( ! Surf->IsValid() || Surf->GetTriangleCount() == 0) + continue ; + // calcolo il Box della superficie + BBox3d BBoxSurf ; Surf->GetLocalBBox( BBoxSurf) ; + // aggiungo il Box a quello complessivo + BBoxGlob.Add( BBoxSurf) ; + } + // definisco uno Zmap vuoto a partire dal Box + BBoxGlob.Expand( dBoxExpansion) ; + return ( CreateEmpty( BBoxGlob.GetMin(), BBoxGlob.GetDimX(), BBoxGlob.GetDimY(), BBoxGlob.GetDimZ(), dTol, true)) ; +} + +//---------------------------------------------------------------------------- +// [Fillet] Funzione per aggiornare mediante Sfere, Cilindri e Facce di estrusione lo ZMap corrente +// mediante una superficie aperta +//---------------------------------------------------------------------------- +bool +VolZmap::UpdateVolZMapByOpenSurfFilletOffset( const ISurfTriMesh* Surf, double dOffs, double dTol) +{ + // da studiare... + return false ; +} + +//---------------------------------------------------------------------------- +// [Fillet] Funzione per aggiornare mediante Sfere, Cilindri e Facce di estrusione lo ZMap corrente +// mediante una superficie chiusa +//---------------------------------------------------------------------------- +bool +VolZmap::UpdateVolZMapByClosedSurfFilletOffset( const ISurfTriMesh* Surf, double dOffs, double dTol) +{ + // controlli sulla superficie + if ( Surf == nullptr || ! Surf->IsClosed()) + return false ; + if ( ! Surf->IsValid() || Surf->GetTriangleCount() == 0) + return true ; + + // Assunzioni : + // - Idea Generale di Offset + // - Su ogni vertice viene definita una sfera ( con raggio pari al valore di Offset e + // centro il vertice corrente) + // - Su ogni lato viene definito un cilindro ( con raggio di base pari al valore di Offset + // e asse definito dall'edge stesso) + // - Su ogni faccia viene definita una superficie di estrusione ( dove le due basi sono + // definite dalla traslazione sia in positivo che in negativo della faccia lungo la sua normale) + // + // - Segno dell'Offset : + // - Positivo ( si sommano gli intervalli corrisipondenti alle entità create) + // - Negativo ( si sottraggono gli intervalli corrispondenti alle enetità create) + // + // - Semplificazione entità : + // La creazione di Sfere e Cilindri potrebbe essere resa più "corretta" definitendo solo + // "spicchi 3d" di sfera e "spicchi 3d" di cilindri. Dato che le operazioni di somma, sottrazioni e + // calcolo delle normali per gli spilloni sono elementari su queste figure, si rischia di appesantire + // troppo i conti introducendo variabili angolari che non sommando tutte le parti. + // + + // definisco vettore di frame Locali alle 3 griglie + FRAME3DVECTOR vFrGrid( 4) ; + vFrGrid[0].Set( ORIG, X_AX, Y_AX, Z_AX) ; + vFrGrid[1].Set( m_MapFrame.Orig(), m_MapFrame.VersX(), m_MapFrame.VersY(), m_MapFrame.VersZ()) ; + vFrGrid[2].Set( m_MapFrame.Orig(), m_MapFrame.VersY(), m_MapFrame.VersZ(), m_MapFrame.VersX()) ; + vFrGrid[3].Set( m_MapFrame.Orig(), m_MapFrame.VersZ(), m_MapFrame.VersX(), m_MapFrame.VersY()) ; + + // definisco una mappa dei vertici, in modo da sapere su quali sono state già create le sfere + BOOLVECTOR vbVert( Surf->GetVertexCount(), false) ; + // ----------------------- Cilindri e Sfere ----------------------- + // scorro gli Edge della superficie + for ( int nE = 0 ; nE < Surf->GetEdgeCount() ; ++ nE) { + // recupero lo spigolo + int nV1, nV2, nF1, nF2 ; double dAng ; + Surf->GetEdge( nE, nV1, nV2, nF1, nF2, dAng) ; + // controllo se il cilindro serve + // NB. la mancata creazione del cilindro comporta la mancata creazione delle sfere sui suoi vertici + // durante questa iterazione; non significa che questa sfera non verrà mai creata... + // Non esiste la sfera sul vertive V <=> non esiste alcun cilindro su tutti gli edge concorrenti + if ( dAng * dOffs < 0) + continue ; + // recupero le coordinate dei vertici + Point3d ptP1 ; Surf->GetVertex( nV1, ptP1) ; + Point3d ptP2 ; Surf->GetVertex( nV2, ptP2) ; + // ciclo sulle griglie + for ( int nGrid = 0 ; nGrid < 3 ; ++ nGrid) { + // esprimo gli estremi nel riferimento della griglia + ptP1.LocToLoc( vFrGrid[nGrid], vFrGrid[nGrid + 1]) ; + ptP2.LocToLoc( vFrGrid[nGrid], vFrGrid[nGrid + 1]) ; + // aggiungo/sottraggo gli intervalli definiti dal cilindro + if ( ! CreateOffsCylinderOnEdge( ptP1, ptP2, dOffs, nGrid)) + return false ; + // aggiungo/sottraggo gli intervalli definiti dalla sfera + if ( ! vbVert[nV1]) { + if ( ! CreateOffsSphereOnVertex( ptP1, dOffs, nGrid)) + return false ; + } + if ( ! vbVert[nV2]) { + if ( ! CreateOffsSphereOnVertex( ptP2, dOffs, nGrid)) + return false ; + } + } + vbVert[nV1] = true ; + vbVert[nV2] = true ; + } + // ----------------------- Facce ----------------------- + // scorro tutte le facce definendo una superficie di estrusione + for ( int nF = 0 ; nF < Surf->GetFacetCount() ; ++ nF) { + // recupero lo faccia + POLYLINEVECTOR vPL ; Surf->GetFacetLoops( nF, vPL) ; + // recupero la normale della faccia + Vector3d vtN ; Surf->GetFacetNormal( nF, vtN) ; + // definisco la superficie di estrusione + CICURVEPVECTOR vpCrvs ; vpCrvs.reserve( vPL.size()) ; + for ( int i = 0 ; i < int( vPL.size()) ; ++ i) { + vPL[i].Translate( - abs( dOffs) * vtN) ; + PtrOwner pCrvCompo( CreateCurveComposite()) ; + if ( IsNull( pCrvCompo) || ! pCrvCompo->FromPolyLine( vPL[i])) { + // dealloco le curve + for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { + delete ( vpCrvs[i]) ; + vpCrvs[i] = nullptr ; + } + return false ; + } + vpCrvs.emplace_back( Release( pCrvCompo)) ; + } + // recupero la TriMesh di estrusione + PtrOwner pStmExtr( GetSurfTriMeshByRegionExtrusion( vpCrvs, 2 * abs( dOffs) * vtN)) ; + if ( IsNull( pStmExtr) || ! pStmExtr->IsValid() || pStmExtr->GetTriangleCount() == 0) { + // dealloco le curve + for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { + delete ( vpCrvs[i]) ; + vpCrvs[i] = nullptr ; + } + return false ; + } + // aggiorno gli spilloni + if ( dOffs > 0.) + AddSurfTm( pStmExtr) ; + else + SubtractSurfTm( pStmExtr) ; + // dealloco le curve + for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { + delete ( vpCrvs[i]) ; + vpCrvs[i] = nullptr ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +// [Fillet Thickening] Funzione per aggiornare mediante Sfere, Cilindri e Facce di estrusione lo ZMap corrente +// mediante una superficie generica (aperta o chiusa) +//---------------------------------------------------------------------------- +bool +VolZmap::UpdateVolZMapBySurfThickeningFilletOffset( const ISurfTriMesh* Surf, double dOffs, double dTol) +{ + // controlli sulla superficie + if ( Surf == nullptr) + return false ; + if ( ! Surf->IsValid() || Surf->GetTriangleCount() == 0) + return true ; + + // non inizializzo lo Zmap, semplicemente lavoro con facce, spigoli e vertici + + // definisco vettore di frame Locali alle 3 griglie + FRAME3DVECTOR vFrGrid( 4) ; + vFrGrid[0].Set( ORIG, X_AX, Y_AX, Z_AX) ; + vFrGrid[1].Set( m_MapFrame.Orig(), m_MapFrame.VersX(), m_MapFrame.VersY(), m_MapFrame.VersZ()) ; + vFrGrid[2].Set( m_MapFrame.Orig(), m_MapFrame.VersY(), m_MapFrame.VersZ(), m_MapFrame.VersX()) ; + vFrGrid[3].Set( m_MapFrame.Orig(), m_MapFrame.VersZ(), m_MapFrame.VersX(), m_MapFrame.VersY()) ; + + // definisco una mappa dei vertici, in modo da sapere su quali sono state già create le sfere + BOOLVECTOR vbVert( Surf->GetVertexCount(), false) ; + // ----------------------- Cilindri e Sfere ----------------------- + // scorro gli Edge della superficie + for ( int nE = 0 ; nE < Surf->GetEdgeCount() ; ++ nE) { + // recupero lo spigolo + int nV1, nV2, nF1, nF2 ; double dAng ; + Surf->GetEdge( nE, nV1, nV2, nF1, nF2, dAng) ; + // recupero le coordinate dei vertici + Point3d ptP1 ; Surf->GetVertex( nV1, ptP1) ; + Point3d ptP2 ; Surf->GetVertex( nV2, ptP2) ; + // ciclo sulle griglie + for ( int nGrid = 0 ; nGrid < 3 ; ++ nGrid) { + // esprimo gli estremi nel riferimento della griglia + ptP1.LocToLoc( vFrGrid[nGrid], vFrGrid[nGrid + 1]) ; + ptP2.LocToLoc( vFrGrid[nGrid], vFrGrid[nGrid + 1]) ; + // aggiungo/sottraggo gli intervalli definiti dal cilindro + if ( ! CreateOffsCylinderOnEdge( ptP1, ptP2, abs( dOffs), nGrid)) + return false ; + // aggiungo/sottraggo gli intervalli definiti dalla sfera + if ( ! vbVert[nV1]) { + if ( ! CreateOffsSphereOnVertex( ptP1, abs( dOffs), nGrid)) + return false ; + } + if ( ! vbVert[nV2]) { + if ( ! CreateOffsSphereOnVertex( ptP2, abs( dOffs), nGrid)) + return false ; + } + } + vbVert[nV1] = true ; + vbVert[nV2] = true ; + } + // ----------------------- Facce ----------------------- + // scorro tutte le facce definendo una superficie di estrusione + for ( int nF = 0 ; nF < Surf->GetFacetCount() ; ++ nF) { + // recupero lo faccia + POLYLINEVECTOR vPL ; Surf->GetFacetLoops( nF, vPL) ; + // recupero la normale della faccia + Vector3d vtN ; Surf->GetFacetNormal( nF, vtN) ; + // definisco la superficie di estrusione + CICURVEPVECTOR vpCrvs ; vpCrvs.reserve( vPL.size()) ; + for ( int i = 0 ; i < int( vPL.size()) ; ++ i) { + vPL[i].Translate( - abs( dOffs) * vtN) ; + PtrOwner pCrvCompo( CreateCurveComposite()) ; + if ( IsNull( pCrvCompo) || ! pCrvCompo->FromPolyLine( vPL[i])) { + // dealloco le curve + for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { + delete ( vpCrvs[i]) ; + vpCrvs[i] = nullptr ; + } + return false ; + } + vpCrvs.emplace_back( Release( pCrvCompo)) ; + } + // recupero la TriMesh di estrusione + PtrOwner pStmExtr( GetSurfTriMeshByRegionExtrusion( vpCrvs, 2 * abs( dOffs) * vtN)) ; + if ( IsNull( pStmExtr) || ! pStmExtr->IsValid() || pStmExtr->GetTriangleCount() == 0) { + // dealloco le curve + for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { + delete ( vpCrvs[i]) ; + vpCrvs[i] = nullptr ; + } + return false ; + } + // aggiorno gli spilloni + AddSurfTm( pStmExtr) ; + // dealloco le curve + for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { + delete ( vpCrvs[i]) ; + vpCrvs[i] = nullptr ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +// Funzione per la creazine di uno Zmap di Offset (positivo o negativo) a partire da un +// vettore di superfici TriMesh (aperte o chiuse). +// Definizione : +// - Lo Zmap di Offset ( positivo o negativo) di una superficie chiusa è automaticamente l'Offset stesso +// - Lo Zmap di Offset ( positivo o negativo) di una superficie aperta è ????? ( da capire...) +//---------------------------------------------------------------------------- +bool +VolZmap::CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol, int nType) { // controllo delle superfici for ( const ISurfTriMesh* Surf : vSurf) { @@ -159,142 +502,67 @@ VolZmap::CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, do if ( vSurf.empty()) return true ; - // definisco lo Zmap di partenza a partire dalle superfici - // se una sola superficie - double dBoxExpansion = ( abs( dOffs) + 1.5 * dTol) + 10 * EPS_SMALL ; - if ( int( vSurf.size()) == 1) { - // controllo la validità della superficie - if ( ! vSurf[0]->IsValid() || vSurf[0]->GetTriangleCount() == 0) - return true ; - // definisco lo Zamp a partire dall'espansione del Box della superficie - if ( ! CreateFromTriMesh( *vSurf[0], dTol, true, dBoxExpansion)) - return false ; - } - // se più superfici - else { - // calcolo il Box complessivo delle superfici TriMesh - BBox3d BBoxGlob ; - for ( int i = 0 ; i < int( vSurf.size()) ; ++ i) { - // controllo la validità della superficie - if ( ! vSurf[i]->IsValid() || vSurf[i]->GetTriangleCount() == 0) - continue ; - // calcolo il Box della superficie - BBox3d BBoxSurf ; vSurf[i]->GetLocalBBox( BBoxSurf) ; - // aggiungo il Box a quello complessivo - BBoxGlob.Add( BBoxSurf) ; - } - // definisco uno Zmap vuoto a partire dal Box - BBoxGlob.Expand( dBoxExpansion) ; - if ( ! CreateEmpty( BBoxGlob.GetMin(), BBoxGlob.GetDimX(), BBoxGlob.GetDimY(), BBoxGlob.GetDimZ(), dTol, true)) - return false ; - for ( const ISurfTriMesh* Surf : vSurf) { - if ( ! AddSurfTm( Surf)) - return false ; - } - } - - /* Assunzioni : - - Idea Generale di Offset - - Su ogni vertice viene definita una sfera ( con raggio pari al valore di Offset e - centro il vertice corrente) - - Su ogni lato viene definito un cilindro ( con raggio di pase pari al valore di Offset - e asse definito dall'edge stesso) - - Su ogni faccia viene definita una superficie di estrusione ( dove le due basi sono - definite dalla traslazione sia in positivo che in negativo della faccia lungo la sua normale) - - - Segno dell'Offset : - - Positivo ( si sommano gli intervalli corrisipondenti alle entità create) - - Negativo ( si sottraggono gli intervalli corrispondenti alle enetità create) - - - Semplificazione entità : - La creazione di Sfere e Cilindri potrebbe essere resa più "corretta" definitendo solo - "spicchi 3d" di sfera e "spicchi 3d" di cilindri. Dato che le operazioni di somma, sottrazioni e - calcolo delle normali per gli spilloni sono elementari su queste figure, si rischia di appesantire - troppo i conti introducendo variabili angolari che non sommando tutte le parti. - */ - - // definisco vettore di frame Locali alle 3 griglie - FRAME3DVECTOR vFrGrid( 4) ; - vFrGrid[0].Set( ORIG, X_AX, Y_AX, Z_AX) ; - vFrGrid[1].Set( m_MapFrame.Orig(), m_MapFrame.VersX(), m_MapFrame.VersY(), m_MapFrame.VersZ()) ; - vFrGrid[2].Set( m_MapFrame.Orig(), m_MapFrame.VersY(), m_MapFrame.VersZ(), m_MapFrame.VersX()) ; - vFrGrid[3].Set( m_MapFrame.Orig(), m_MapFrame.VersZ(), m_MapFrame.VersX(), m_MapFrame.VersY()) ; - + // inizializzo lo Zmap di Offset a partire dalle superfici + if ( ! InitVolZMapOffs( vSurf, dOffs, dTol)) + return false ; // scorro le superfici for ( const ISurfTriMesh* Surf : vSurf) { // se superficie non valida, passo alla successiva if ( ! Surf->IsValid() || Surf->GetTriangleCount() == 0) continue ; - // definisco una mappa dei vertici, in modo da sapere su quali sono state già create le sfere - BOOLVECTOR vbVert( Surf->GetVertexCount(), false) ; - // ----------------------- Cilindri e Sfere ----------------------- - // scorro gli Edge della superficie - for ( int nE = 0 ; nE < Surf->GetEdgeCount() ; ++ nE) { - // recupero lo spigolo - int nV1, nV2, nF1, nF2 ; double dAng ; - Surf->GetEdge( nE, nV1, nV2, nF1, nF2, dAng) ; - // controllo se il cilindro serve - // NB. la mancata creazione del cilindro comporta la mancata creazione delle sfere sui suoi vertici - // durante questa iterazione; non significa che questa sfera non verrà mai creata... - // Non esiste la sfera sul vertive V <=> non esiste alcun cilindro su tutti gli edge concorrenti - if ( dAng * dOffs < 0) - continue ; - // recupero le coordinate dei vertici - Point3d ptP1 ; Surf->GetVertex( nV1, ptP1) ; - Point3d ptP2 ; Surf->GetVertex( nV2, ptP2) ; - // ciclo sulle griglie - for ( int nGrid = 0 ; nGrid < 3 ; ++ nGrid) { - // esprimo gli estremi nel riferimento della griglia - ptP1.LocToLoc( vFrGrid[nGrid], vFrGrid[nGrid + 1]) ; - ptP2.LocToLoc( vFrGrid[nGrid], vFrGrid[nGrid + 1]) ; - // aggiungo/sottraggo gli intervalli definiti dal cilindro - if ( ! CreateOffsCylinderOnEdge( ptP1, ptP2, dOffs, nGrid)) + // aggiorno lo ZMap + if ( Surf->IsClosed()) { + if ( nType == STMOFF_FILLET) { + if ( ! UpdateVolZMapByClosedSurfFilletOffset( Surf, dOffs, dTol)) return false ; - // aggiungo/sottraggo gli intervalli definiti dalla sfera - if ( ! vbVert[nV1]) { - vbVert[nV1] = ( nGrid == 2) ; - if ( ! CreateOffsSphereOnVertex( ptP1, dOffs, nGrid)) - return false ; - } - if ( ! vbVert[nV2]) { - vbVert[nV2] = ( nGrid == 2) ; - if ( ! CreateOffsSphereOnVertex( ptP2, dOffs, nGrid)) - return false ; - } } } - // ----------------------- Facce ----------------------- - // scorro tutte le facce definendo una superficie di estrusione - for ( int nF = 0 ; nF < Surf->GetFacetCount() ; ++ nF) { - // recupero lo faccia - POLYLINEVECTOR vPL ; Surf->GetFacetLoops( nF, vPL) ; - // recupero la normale della faccia - Vector3d vtN ; Surf->GetFacetNormal( nF, vtN) ; - // definisco la superficie di estrusione - CICURVEPVECTOR vpCrvs ; vpCrvs.reserve( vPL.size()) ; - for ( int i = 0 ; i < int( vPL.size()) ; ++ i) { - vPL[i].Translate( - abs( dOffs) * vtN) ; - PtrOwner pCrvCompo( CreateCurveComposite()) ; - if ( IsNull( pCrvCompo) || ! pCrvCompo->FromPolyLine( vPL[i])) - return false ; - vpCrvs.emplace_back( Release( pCrvCompo)) ; - } - // recupero la TriMesh di estrusione - PtrOwner pStmExtr( GetSurfTriMeshByRegionExtrusion( vpCrvs, 2 * abs( dOffs) * vtN)) ; - if ( IsNull( pStmExtr) || ! pStmExtr->IsValid() || pStmExtr->GetTriangleCount() == 0) - return false ; - // aggiorno gli spilloni - if ( dOffs > 0.) - AddSurfTm( pStmExtr) ; - else - SubtractSurfTm( pStmExtr) ; + else { + // --- LE SUPERFICI APERTE SONO PER ORA DISABILITATE --- } } - m_nShape = OFFSET ; // OFFSET (?) ... per ora va bene così + m_nShape = OFFSET ; return true ; } +//---------------------------------------------------------------------------- +// Funzione per la creazine di uno Zmap di Fat Offset a partire da un +// vettore di superfici TriMesh (aperte o chiuse). +//---------------------------------------------------------------------------- +bool +VolZmap::CreateFromTriMeshThickeningOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol, int nType) +{ + // controllo delle superfici + for ( const ISurfTriMesh* Surf : vSurf) { + if ( Surf == nullptr) + return false ; + } + // verifica sul parametro di Offset ( coerente con Curve e FlatRegion) + if ( abs( dOffs) < 10 * EPS_SMALL) + return true ; + // se non ho superfici, non faccio nulla + if ( vSurf.empty()) + return true ; + // inizializzo lo Zmap di Offset a partire dalle superfici + if ( ! InitVolZMapThickeningOffs( vSurf, dOffs, dTol)) + return false ; + // scorro le superfici + for ( const ISurfTriMesh* Surf : vSurf) { + // se superficie non valida, passo alla successiva + if ( ! Surf->IsValid() || Surf->GetTriangleCount() == 0) + continue ; + + // aggiorno lo Zmap + if ( nType == STMOFF_FILLET) { + if ( ! UpdateVolZMapBySurfThickeningFilletOffset( Surf, dOffs, dTol)) + return false ; + } + } + + m_nShape = OFFSET ; + return true ; +} diff --git a/Voronoi.cpp b/Voronoi.cpp index 4feb971..0146793 100644 --- a/Voronoi.cpp +++ b/Voronoi.cpp @@ -25,7 +25,7 @@ using namespace std ; //---------------------------------------------------------------------------- -Voronoi::Voronoi( const ICurve* pCrv, bool bAllowAdd) +Voronoi::Voronoi( const ICurve* pCrv, bool bAllowAdd) : m_vroni( nullptr), m_nBound( VORONOI_STD_BOUND), m_bVDComputed( false), m_bAllowAdd( true) { // tento di aggiungere la curva @@ -35,7 +35,7 @@ Voronoi::Voronoi( const ICurve* pCrv, bool bAllowAdd) } //---------------------------------------------------------------------------- -Voronoi::Voronoi( const ISurfFlatRegion* pSfr, bool bAllowAdd) +Voronoi::Voronoi( const ISurfFlatRegion* pSfr, bool bAllowAdd) : m_vroni( nullptr), m_nBound( VORONOI_STD_BOUND), m_bVDComputed( false), m_bAllowAdd( true) { // tento di aggiungere la superficie @@ -45,16 +45,16 @@ Voronoi::Voronoi( const ISurfFlatRegion* pSfr, bool bAllowAdd) } //---------------------------------------------------------------------------- -Voronoi::~Voronoi( void) +Voronoi::~Voronoi( void) { Clear() ; } //---------------------------------------------------------------------------- bool -Voronoi::Clear( void) +Voronoi::Clear( void) { - // pulizia oggetto vroni + // pulizia oggetto vroni if ( m_vroni != nullptr) delete m_vroni ; m_vroni = nullptr ; @@ -72,7 +72,7 @@ Voronoi::Clear( void) //---------------------------------------------------------------------------- bool -Voronoi::AddCurve( const ICurve* pCrv) +Voronoi::AddCurve( const ICurve* pCrv) { if ( ! m_bAllowAdd) return false ; @@ -99,21 +99,21 @@ Voronoi::AddCurve( const ICurve* pCrv) if ( ! vtExtr.IsSmall()) plPlane.Set( ptS, vtExtr) ; else - plPlane.Set( ptS, Z_AX) ; + plPlane.Set( ptS, Z_AX) ; } else { if ( ! pCrv->IsFlat( plPlane, false, 10 * EPS_SMALL)) - return false ; - } - + return false ; + } + if ( m_vpCrvs.empty()) { // se prima curva considerata assegno il frame al Voronoi - m_Frame.Set( plPlane.GetPoint(), plPlane.GetVersN()) ; + m_Frame.Set( plPlane.GetPoint(), plPlane.GetVersN()) ; } else { // altrimenti verifico sia complanare ad eventuali curve già presenti if ( ! AreSameOrOppositeVectorApprox( m_Frame.VersZ(), plPlane.GetVersN()) || ! PointInPlaneApprox( m_Frame.Orig(), plPlane)) - return false ; + return false ; } // creo una copia della curva e la porto in locale @@ -128,8 +128,8 @@ Voronoi::AddCurve( const ICurve* pCrv) m_vroni = new( nothrow) vroniObject() ; if ( m_vroni == nullptr) return false ; - m_vroni->apiInitializeProgram() ; - } + m_vroni->apiInitializeProgram() ; + } // aggiungo la curva in locale all'oggetto vroni if ( ! AddCurveToVroni( pCrvLoc)) @@ -144,61 +144,61 @@ Voronoi::AddCurve( const ICurve* pCrv) BBox3d bBox ; pCrvLoc->GetLocalBBox( bBox) ; m_bBox.Add( bBox) ; - + return true ; } //---------------------------------------------------------------------------- bool -Voronoi::AddSurfFlatRegion( const ISurfFlatRegion* pSfr) +Voronoi::AddSurfFlatRegion( const ISurfFlatRegion* pSfr) { if ( ! m_bAllowAdd) return false ; if ( pSfr == nullptr) return false ; - + // recupero il piano Point3d ptCen ; pSfr->GetCentroid( ptCen) ; - Vector3d vtN = pSfr->GetNormVersor() ; + Vector3d vtN = pSfr->GetNormVersor() ; if ( m_vpCrvs.empty()) { // assegno il frame al Voronoi - m_Frame.Set( ptCen, vtN) ; + m_Frame.Set( ptCen, vtN) ; } else { // verifico sia complanare ad eventuali curve già presenti Plane3d plPlane ; plPlane.Set( ptCen, pSfr->GetNormVersor()) ; if ( ! AreSameOrOppositeVectorApprox( m_Frame.VersZ(), pSfr->GetNormVersor()) || ! PointInPlaneApprox( m_Frame.Orig(), plPlane)) - return false ; + return false ; } - + try { // verifico se oggetto vroni è stato inizializzato if ( m_vroni == nullptr) { m_vroni = new( nothrow) vroniObject() ; if ( m_vroni == nullptr) return false ; - m_vroni->apiInitializeProgram() ; + m_vroni->apiInitializeProgram() ; } - + // aggiungo le curve di loop for ( int i = 0 ; i < pSfr->GetChunkCount() ; i ++) { for ( int j = 0 ; j < pSfr->GetLoopCount( i) ; j ++) { PtrOwner pCrvLoc( pSfr->GetLoop( i, j)) ; if ( IsNull( pCrvLoc)) return false ; - pCrvLoc->ToLoc( m_Frame) ; + pCrvLoc->ToLoc( m_Frame) ; if ( ! AddCurveToVroni( pCrvLoc)) return false ; - } + } } } catch (...) { LOG_ERROR( GetEGkLogger(), m_vroni->GetExceptionMessage()) return false ; } - + // aggiorno il box complessivo BBox3d bBox ; Frame3d frSrf = m_Frame ; @@ -211,16 +211,16 @@ Voronoi::AddSurfFlatRegion( const ISurfFlatRegion* pSfr) //---------------------------------------------------------------------------- bool -Voronoi::AddCurveToVroni( const ICurve* pCrv) +Voronoi::AddCurveToVroni( const ICurve* pCrv) { int nLoopId = m_vpCrvs.size() ; // aggiungo il punto iniziale - Point3d ptStart ; + Point3d ptStart ; if ( ! pCrv->GetStartPoint( ptStart)) return false ; int nCrv = m_vroni->HandlePnt( ptStart.x, ptStart.y, {nLoopId, 0}) ; - + // aggiungo la parte rimanente della curva switch ( pCrv->GetType()) { case CRV_LINE : @@ -229,7 +229,7 @@ Voronoi::AddCurveToVroni( const ICurve* pCrv) case CRV_ARC : m_vpCrvs.emplace_back( pCrv->Clone()) ; return AddArcToVroni( GetCurveArc( pCrv), nCrv, nLoopId) ; - case CRV_COMPO : + case CRV_COMPO : return AddCompoToVroni( GetCurveComposite( pCrv), nCrv, nLoopId) ; case CRV_BEZIER : return AddBezierToVroni( GetCurveBezier( pCrv), nCrv, nLoopId) ; @@ -242,7 +242,7 @@ Voronoi::AddCurveToVroni( const ICurve* pCrv) //---------------------------------------------------------------------------- bool -Voronoi::AddLineToVroni( const ICurveLine* pLine, int& nVroniCrv, int nLoopId, int nCrvId, Point3d ptEnd) +Voronoi::AddLineToVroni( const ICurveLine* pLine, int& nVroniCrv, int nLoopId, int nCrvId, Point3d ptEnd) { if ( pLine == nullptr) return false ; @@ -250,7 +250,7 @@ Voronoi::AddLineToVroni( const ICurveLine* pLine, int& nVroniCrv, int nLoopId, i // verifico se il punto finale viene forzato oppure deve essere ricavato dalla pLine if ( ! ptEnd.IsValid()) { if ( ! pLine->GetEndPoint( ptEnd)) - return false ; + return false ; } m_vroni->AddSeg( &nVroniCrv, ptEnd.x, ptEnd.y, {nLoopId, nCrvId}) ; @@ -259,7 +259,7 @@ Voronoi::AddLineToVroni( const ICurveLine* pLine, int& nVroniCrv, int nLoopId, i //---------------------------------------------------------------------------- bool -Voronoi::AddArcToVroni( const ICurveArc* pArc, int& nVroniCrv, int nLoopId, int nCrvId, Point3d ptEnd) +Voronoi::AddArcToVroni( const ICurveArc* pArc, int& nVroniCrv, int nLoopId, int nCrvId, Point3d ptEnd) { if ( pArc == nullptr) return false ; @@ -285,7 +285,7 @@ Voronoi::AddArcToVroni( const ICurveArc* pArc, int& nVroniCrv, int nLoopId, int // verifico se il punto finale viene forzato oppure deve essere ricavato dal pArc if ( ! ptEnd.IsValid()) { if ( ! pArc->GetEndPoint( ptEnd)) - return false ; + return false ; } m_vroni->AddArc( &nVroniCrv, ptEnd.x, ptEnd.y, ptCen.x, ptCen.y, nArcSiteType, {nLoopId, nCrvId}) ; } @@ -295,7 +295,7 @@ Voronoi::AddArcToVroni( const ICurveArc* pArc, int& nVroniCrv, int nLoopId, int //---------------------------------------------------------------------------- bool -Voronoi::AddCompoToVroni( const ICurveComposite* pCompo, int& nVroniCrv, int nLoopId) +Voronoi::AddCompoToVroni( const ICurveComposite* pCompo, int& nVroniCrv, int nLoopId) { if ( pCompo == nullptr) return false ; @@ -315,18 +315,18 @@ Voronoi::AddCompoToVroni( const ICurveComposite* pCompo, int& nVroniCrv, int nLo bool bClosed = pCopy->IsClosed() ; for ( int i = 0 ; i < pCopy->GetCurveCount() ; i++) { Point3d ptForcedEnd = P_INVALID ; - + // se curva è chiusa, forzo l'end point a coincidere con lo start ( per le tolleranze di vroni) if ( i == pCopy->GetCurveCount() - 1 && bClosed) pCompo->GetStartPoint( ptForcedEnd) ; - + // aggiungo const ICurve* pCrv = pCopy->GetCurve( i) ; int nType = pCrv->GetType() ; if ( nType == CRV_LINE) AddLineToVroni( GetCurveLine( pCrv), nVroniCrv, nLoopId, i, ptForcedEnd) ; else if ( nType == CRV_ARC) - AddArcToVroni( GetCurveArc( pCrv), nVroniCrv, nLoopId, i, ptForcedEnd) ; + AddArcToVroni( GetCurveArc( pCrv), nVroniCrv, nLoopId, i, ptForcedEnd) ; } // aggiungo al vettore di curve @@ -341,7 +341,7 @@ Voronoi::AddBezierToVroni( const ICurveBezier* pBezier, int& nVroniCrv, int nLoo { if ( pBezier == nullptr) return false ; - + // riconduco al caso di curva composita PtrOwner pCompo( CreateBasicCurveComposite()) ; if ( IsNull( pCompo)) @@ -352,28 +352,28 @@ Voronoi::AddBezierToVroni( const ICurveBezier* pBezier, int& nVroniCrv, int nLoo Vector3d vtExtr ; pBezier->GetExtrusion( vtExtr) ; pCompo->SetExtrusion( vtExtr) ; - + return AddCompoToVroni( pCompo, nVroniCrv, nLoopId) ; } //---------------------------------------------------------------------------- -ICurve* +ICurve* Voronoi::GetCurve( int nId) const { // verifico validità indice if ( nId < 0 || nId > ( int)m_vpCrvs.size() - 1) - return nullptr ; + return nullptr ; // ne faccio una copia ICurve* pCrv = m_vpCrvs[nId]->Clone() ; if ( pCrv == nullptr) - return nullptr ; + return nullptr ; // la porto nel riferimento globale pCrv->ToGlob( m_Frame) ; return pCrv ; } //---------------------------------------------------------------------------- -bool +bool Voronoi::GetVroniPlane( Plane3d& plPlane) const { if ( ! IsValid()) @@ -383,13 +383,13 @@ Voronoi::GetVroniPlane( Plane3d& plPlane) const } //---------------------------------------------------------------------------- -bool +bool Voronoi::CalcVoronoi( int nBound) -{ +{ // se già stato calcolato con lo stesso bound non devo fare nulla if ( m_bVDComputed && nBound == m_nBound) return true ; - + // se già stato calcolato reset dei dati if ( m_bVDComputed) m_vroni->ResetVoronoiDiagram() ; @@ -398,9 +398,9 @@ Voronoi::CalcVoronoi( int nBound) m_nBound = max( nBound, VORONOI_STD_BOUND) ; // calcolo - m_bVDComputed = true ; + m_bVDComputed = true ; string sTmp = "" ; - m_vroni->apiComputeVD( false, true, false, m_nBound, 0, 0, &sTmp[0], false, false, false, &sTmp[0], true) ; + m_vroni->apiComputeVD( false, true, false, m_nBound, 0, 0, &sTmp[0], false, false, false, &sTmp[0], true) ; return true ; } @@ -416,7 +416,7 @@ Voronoi::GetBisectorCurve( int i) int nType = m_vroni->GetBisectorType( i) ; // linea - if ( nType == BisectorType::LINE) { + if ( nType == BisectorType::LINE) { // recupero i dati del bisettore da vroni Point3d ptS, ptE ; double dParS, dParE ; @@ -434,7 +434,7 @@ Voronoi::GetBisectorCurve( int i) pLine->SetTempParam( dParS, 0) ; pLine->SetTempParam( dParE, 1) ; pLine->ToGlob( m_Frame) ; - return pLine ; + return pLine ; } // degenerate hyperellipse ( arco) @@ -454,20 +454,20 @@ Voronoi::GetBisectorCurve( int i) pArc->SetTempParam( dParS, 0) ; pArc->SetTempParam( dParS, 1) ; // dParE = dParS pArc->ToGlob( m_Frame) ; - return pArc ; + return pArc ; } - + // bisettore generico else if ( nType != BisectorType::NONE) { // approssimo linearmente il bisettore int nPoints = m_vroni->GetApproxedBisectorPointsNbr( i) ; if ( nPoints < 2) return nullptr ; - + CurveComposite* pCompo = CreateBasicCurveComposite() ; if ( pCompo == nullptr) return nullptr ; - + // verifico se devo leggere i punti del bisettore al contrario per averlo orientato dal parametro minore al maggiore bool bInvert = false ; double dPar1, dPar2 ; @@ -481,13 +481,13 @@ Voronoi::GetBisectorCurve( int i) m_vroni->GetApproxedBisectorPoint( i, bInvert ? nPoints - 1 : 0, pt.v, dParS) ; pCompo->AddPoint( pt) ; int nCrvCount = 0 ; - + double dParPrev = dParS ; int j = bInvert ? nPoints - 2 : 1 ; while ( ( bInvert && j >= 0) || ( ! bInvert && j < nPoints)) { double dPar ; m_vroni->GetApproxedBisectorPoint( i, j, pt.v, dPar) ; - if ( pCompo->AddLine( pt)) { + if ( pCompo->AddLine( pt)) { // setto i parametri sulla sottocurva pCompo->SetCurveTempParam( nCrvCount, dParPrev, 0) ; pCompo->SetCurveTempParam( nCrvCount, dPar, 1) ; @@ -501,7 +501,7 @@ Voronoi::GetBisectorCurve( int i) else j ++ ; } - + // setto parametri sulla curva pCompo->SetTempParam( dParS, 0) ; pCompo->SetTempParam( dParPrev, 1) ; @@ -521,12 +521,12 @@ Voronoi::CalcVoronoiDiagram( ICURVEPOVECTOR& vCrvs, int nBound) if ( ! IsValid()) return false ; - + try { // verifico se necessario calcolo Voronoi if ( ! m_bVDComputed || nBound != m_nBound) CalcVoronoi( nBound) ; - + for ( int i = 4 ; i < m_vroni->GetNumberOfEdges() ; i ++) { // recupero la curva del bisettore PtrOwner pCrv( GetBisectorCurve( i)) ; @@ -546,7 +546,7 @@ Voronoi::CalcVoronoiDiagram( ICURVEPOVECTOR& vCrvs, int nBound) } //---------------------------------------------------------------------------- -bool +bool Voronoi::CalcMedialAxis( ICURVEPOVECTOR& vCrvs, int nSide) { vCrvs.clear() ; @@ -561,21 +561,21 @@ Voronoi::CalcMedialAxis( ICURVEPOVECTOR& vCrvs, int nSide) bRight = false ; else if ( nSide == WMAT_RIGHT) bLeft = false ; - - try { + + try { if ( ! m_bVDComputed) CalcVoronoi() ; // calcolo medial axis m_vroni->apiComputeWMAT( false, 0.0, 0.0, false, bLeft, bRight) ; - + for ( int i = 4 ; i < m_vroni->GetNumberOfEdges() ; i ++) { // verifico se il lato appartiene al medial axis if ( m_vroni->IsWMATEdge( i)) { PtrOwner pCrv( GetBisectorCurve( i)) ; - if ( ! IsNull( pCrv) && pCrv->IsValid()) - vCrvs.emplace_back( Release( pCrv)) ; - } + if ( ! IsNull( pCrv) && pCrv->IsValid()) + vCrvs.emplace_back( Release( pCrv)) ; + } } // libero la memoria di vroni utilizzata per calcolare bisettore @@ -590,7 +590,7 @@ Voronoi::CalcMedialAxis( ICURVEPOVECTOR& vCrvs, int nSide) } //---------------------------------------------------------------------------- -bool +bool Voronoi::CalcOffset( ICURVEPOVECTOR& vOffs, double dOffs, int nType) { vOffs.clear() ; @@ -603,29 +603,29 @@ Voronoi::CalcOffset( ICURVEPOVECTOR& vOffs, double dOffs, int nType) for ( auto pCrv : m_vpCrvs) vOffs.emplace_back( pCrv->Clone()) ; } - + // calcolo offset ICRVCOMPOPLIST OffsList ; if ( ! CalcVroniOffset( OffsList, abs( dOffs))) - return false ; - + return false ; + // sistemo le curve di offset calcolate con vroni for ( auto pCrv : OffsList) { // seleziono le porzioni dell'offset che si trovano dal lato richiesto ICRVCOMPOPOVECTOR vResult = AdjustOffsetCurves( pCrv, dOffs) ; - - for ( int i = 0 ; i < int( vResult.size()) ; ++ i) { - + + for ( int i = 0 ; i < int( vResult.size()) ; ++ i) { + // eventuale inversione if ( dOffs > EPS_SMALL) vResult[i]->Invert() ; - + // sistemo il punto di inizio - if ( vResult[i]->IsClosed()) + if ( vResult[i]->IsClosed()) AdjustOffsetStart( vResult[i]) ; - - // identifico i raccordi + + // identifico i raccordi if ( ( nType & ICurve::OFF_CHAMFER) != 0 || ( nType & ICurve::OFF_EXTEND) != 0) IdentifyFillets( vResult[i], dOffs) ; @@ -643,17 +643,17 @@ Voronoi::CalcOffset( ICURVEPOVECTOR& vOffs, double dOffs, int nType) if ( ! AdjustCurveFillets( vOffs, dOffs, nType)) { vOffs.clear() ; return false ; - } + } // porto nel frame globale for ( int i = 0 ; i < int( vOffs.size()) ; i++) - vOffs[i]->ToGlob( m_Frame) ; + vOffs[i]->ToGlob( m_Frame) ; return true ; } //---------------------------------------------------------------------------- -bool +bool Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) { // calcola, se possibile, le curve di offset del valore richiesto come curve singole, andando a recuperare i tratti del @@ -667,22 +667,22 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) if ( ! IsValid()) return false ; - try { + try { if ( ! m_bVDComputed) CalcVoronoi() ; - // individuo il lato richiesto + // individuo il lato richiesto bool bLeft = ( dOffs < 0) ; - bool bRight = ! bLeft ; + bool bRight = ! bLeft ; for ( int i = 0 ; i < int( m_vpCrvs.size()) ; i++) { if ( ! m_vpCrvs[i]->IsClosed()) { // se è presente una curva aperta il medial axis deve essere fatto sia a destra sia a sinistra bLeft = true ; bRight = true ; - break ; + break ; } } - int nSideRef = ( dOffs < 0 ? MDS_LEFT : MDS_RIGHT) ; + int nSideRef = ( dOffs < 0 ? MDS_LEFT : MDS_RIGHT) ; // seleziono le curve del medial axis aventi parametro costante pari all'offset richiesto m_vroni->apiComputeWMAT( false, 0.0, 0.0, false, bLeft, bRight) ; @@ -695,7 +695,7 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) m_vroni->GetBisectorParams( i, dParS, dParE) ; if ( abs( dParS - abs( dOffs)) < EPS_SMALL && abs( dParE - abs( dOffs)) < EPS_SMALL) { PtrOwner pCrv( GetBisectorCurve( i)) ; - if ( ! IsNull( pCrv) && pCrv->IsValid()) { + if ( ! IsNull( pCrv) && pCrv->IsValid()) { // se necessario verifico se dal lato corretto rispetto ai siti di riferimento if ( bLeft && bRight) { // recupero i siti di riferimento @@ -707,7 +707,7 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) pCrv->SetTempProp( nOrigCrv1, 1) ; int nSide = GetOffsetCurveSide( pCrv) ; if ( nSide != nSideRef) - continue ; + continue ; } if ( nOrigCrv2 != -1) { // verifico il lato rispetto al secondo sito @@ -716,18 +716,18 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) int nSide = GetOffsetCurveSide( pCrv) ; if ( nSide != nSideRef) continue ; - } + } } - vCrvs.emplace_back( Release( pCrv)) ; - } - } - } + vCrvs.emplace_back( Release( pCrv)) ; + } + } + } } // concateno le curve ottenute if ( vCrvs.size() == 1) vOffs.emplace_back( Release( vCrvs[0])) ; - else if ( ! vCrvs.empty()) { + else if ( ! vCrvs.empty()) { ChainCurves chainC ; chainC.Init( true, 10 * EPS_SMALL, int( vCrvs.size())) ; for ( int i = 0 ; i < int( vCrvs.size()) ; ++ i) { @@ -754,14 +754,14 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) vCrvs[nInd]->Invert() ; // aggiungo alla composita if ( ! pCrvCompo->AddCurve( Release( vCrvs[nInd]))) - return false ; + return false ; } if ( pCrvCompo->IsValid()) { pCrvCompo->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG) ; vOffs.emplace_back( Release( pCrvCompo)) ; - } + } } - } + } // libero la memoria di vroni utilizzata per calcolare bisettore m_vroni->apiFreeBisectorBuffer() ; @@ -775,11 +775,11 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) } //---------------------------------------------------------------------------- -bool +bool Voronoi::CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs) { // calcola i punti e le tangenti sui bisettori del medial axis in corrispondenza del valore di offset richiesto - + vResult.clear() ; if ( abs( dOffs) < EPS_SMALL) @@ -792,12 +792,12 @@ Voronoi::CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs) // verifico se necessario ricalcolo Voronoi UpdateVoronoi( dOffs) ; - // indivudio lato medial axis per curve chiuse ( suppongo di chiamare la funzione dalla singola curva, quindi vale controllare + // indivudio lato medial axis per curve chiuse ( suppongo di chiamare la funzione dalla singola curva, quindi vale controllare // la chiusura solo sulla prima curva. Eventualmente da estendere) bool bLeft = true, bRight = true ; if ( m_vpCrvs[0]->IsClosed()) { bLeft = dOffs < 0 ; - bRight = ! bLeft ; + bRight = ! bLeft ; } // calcolo medial axis @@ -826,12 +826,12 @@ Voronoi::CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs) double dPar ; Point3d ptTemp ; Vector3d vtDir ; - if ( ! pCrv->GetParamAtPoint( pt, dPar, 100 * EPS_SMALL) || ! pCrv->GetPointD1D2( dPar, ICurve::FROM_MINUS, ptTemp, &vtDir)) + if ( ! pCrv->GetParamAtPoint( pt, dPar, 100 * EPS_SMALL) || ! pCrv->GetPointD1D2( dPar, ICurve::FROM_MINUS, ptTemp, &vtDir)) return false ; vtDir.Normalize() ; vResult.emplace_back( pt, vtDir) ; - } + } } // libero la memoria di vroni utilizzata per calcolare bisettori @@ -846,23 +846,23 @@ Voronoi::CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs) } //---------------------------------------------------------------------------- -bool +bool Voronoi::CalcFatCurve( ICURVEPOVECTOR& vCrvs, double dOffs, bool bSquareEnds, bool bSquareMids, bool bMergeOnlySameProps) { vCrvs.clear() ; - + if ( ! IsValid()) return false ; - + // se offset nullo errore if ( abs( dOffs) < EPS_SMALL) return false ; - + ICRVCOMPOPLIST OffsList ; if ( ! CalcVroniOffset( OffsList, abs( dOffs))) return false ; - + // sistemo le curve di offset calcolate con vroni bool bClosed = m_vpCrvs[0]->IsClosed() ; for ( auto pCrvOffs : OffsList) { @@ -910,7 +910,7 @@ Voronoi::CalcFatCurve( ICURVEPOVECTOR& vCrvs, double dOffs, bool bSquareEnds, bo } //---------------------------------------------------------------------------- -bool +bool Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs) { OffsList.clear() ; @@ -931,21 +931,21 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs) m_vroni->apiComputeOff( false, &sTmp[0], false, false, dOffs, 0.0, false, true, true) ; // recupero le curve di offset da vroni - int nOffsCnt = m_vroni->GetOffsetCount() ; + int nOffsCnt = m_vroni->GetOffsetCount() ; for ( int i = 0 ; i < nOffsCnt ; i++) { Point3d ptSChain = P_INVALID ; PtrOwner pCrvOffs ( CreateBasicCurveComposite()) ; int nCrvCnt = m_vroni->GetOffsetCurveCount( i) ; // numero di sottocurve for ( int j = 0 ; j < nCrvCnt ; j ++) { - // recupero la sottocurva da vroni + // recupero la sottocurva da vroni Point3d ptS, ptE, ptC ; int nType ; int nOrigCrv, nOrigLoop, nOrigPnt ; // sito m_vroni->GetOffsetCurve( i, j, nType, ptS.v, ptE.v, ptC.v, nOrigLoop, nOrigCrv, nOrigPnt) ; if ( j == 0) - pCrvOffs->AddPoint( ptS) ; + pCrvOffs->AddPoint( ptS) ; // se estremi coincidenti la curva va ignorata ( da vroni non possono arrivare circonferenze) // ma controllo se appartiene ad una catena di tratti infinitesimi @@ -954,7 +954,7 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs) if ( ! AreSamePointApprox( ptSChain, ptE)) { if ( ! pCrvOffs->AddLine( ptE)) return false ; - ptSChain = P_INVALID ; + ptSChain = P_INVALID ; } } else { @@ -970,16 +970,16 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs) if ( ! pCrvOffs->AddLine( ptE)) return false ; } - else { + else { PtrOwner pArc( CreateBasicCurveArc()) ; if ( ! pArc->SetC2P( ptC, ptS, ptE)) { // se raggio minore di EPS_SMALL approssimo con linea if ( AreSamePointApprox( ptC, ptS)) { if ( ! pCrvOffs->AddLine( ptE)) - return false ; + return false ; } else - return false ; + return false ; } else { // verifico orientamento @@ -988,25 +988,25 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs) pArc->ToExplementary() ; // aggiungo alla composita if ( ! pCrvOffs->AddCurve( Release( pArc))) - return false ; - } + return false ; + } } // setto come info la sottocurva da cui si è generata int nCurrCrvId = pCrvOffs->GetCurveCount() - 1 ; pCrvOffs->SetCurveTempProp( nCurrCrvId, nOrigCrv + 1, 0) ; pCrvOffs->SetCurveTempProp( nCurrCrvId, nOrigLoop, 1) ; - // verifico se è una giunzione, ovvero un raccordo relativo agli estremi di una curva ( con distinzione fra curva + // verifico se è una giunzione, ovvero un raccordo relativo agli estremi di una curva ( con distinzione fra curva // aperta e chiusa) if ( nOrigCrv == -1) { int nOrigCrvCnt = 1 ; if ( m_vpCrvs[nOrigLoop]->GetType() == CRV_COMPO) nOrigCrvCnt = GetBasicCurveComposite( m_vpCrvs[nOrigLoop])->GetCurveCount() ; if ( nOrigPnt == 0 || nOrigPnt == nOrigCrvCnt) { - double dParam = m_vpCrvs[nOrigLoop]->IsClosed() ? VRONI_JUNCTION_CLOSED : VRONI_JUNCTION_OPEN ; + double dParam = m_vpCrvs[nOrigLoop]->IsClosed() ? VRONI_JUNCTION_CLOSED : VRONI_JUNCTION_OPEN ; pCrvOffs->SetCurveTempParam( nCurrCrvId, dParam, 0) ; } - } + } } // rimuovo tratti di lunghezza inferiore a 5 * EPS_SMALL @@ -1014,8 +1014,8 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs) // aggiungo la curva alla lista degli offset if ( ! IsNull( pCrvOffs) && pCrvOffs->IsValid() && pCrvOffs->GetCurveCount() > 0) - OffsList.push_back( Release( pCrvOffs)) ; - } + OffsList.push_back( Release( pCrvOffs)) ; + } // libero la memoria di vroni dedicata agli offset m_vroni->apiFreeOffsetData() ; @@ -1029,11 +1029,11 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs) } //---------------------------------------------------------------------------- -bool +bool Voronoi::UpdateVoronoi( double dOffs) { // calcolo il bound necessario per l'offset desiderato - double dNeededBound = abs( dOffs) / 0.49 / sqrt( m_bBox.GetDimX() * m_bBox.GetDimX() + m_bBox.GetDimY() * m_bBox.GetDimY()) ; + double dNeededBound = abs( dOffs) / 0.49 / sqrt( m_bBox.GetDimX() * m_bBox.GetDimX() + m_bBox.GetDimY() * m_bBox.GetDimY()) ; if ( ! m_bVDComputed || dNeededBound > m_nBound) { // aggiorno il valore del bound int nBound = ( int)( ceil( dNeededBound) + 0.5) ; @@ -1045,9 +1045,9 @@ Voronoi::UpdateVoronoi( double dOffs) } //---------------------------------------------------------------------------- -ICRVCOMPOPOVECTOR -Voronoi::AdjustOffsetCurves( const ICurveComposite* pCompo, double dOffs) const -{ +ICRVCOMPOPOVECTOR +Voronoi::AdjustOffsetCurves( const ICurveComposite* pCompo, double dOffs) const +{ ICRVCOMPOPOVECTOR vResult ; int nSideRef = dOffs < EPS_SMALL ? MDS_LEFT : MDS_RIGHT ; @@ -1065,13 +1065,13 @@ Voronoi::AdjustOffsetCurves( const ICurveComposite* pCompo, double dOffs) const // controllo la curva complessiva int nSide = GetOffsetCurveSide( pCompo->GetCurve( 0)) ; if ( nSide == nSideRef) - vResult.emplace_back( pCompo->Clone()) ; + vResult.emplace_back( pCompo->Clone()) ; } - else { + else { // scorro la curva eliminando le giunzioni relative a curve aperte e le sottocurve che si trovano dal lato sbagliato PtrOwner pCompoCurr( CreateBasicCurveComposite()) ; for ( int i = 0 ; i < pCompo->GetCurveCount() ; i ++) { - bool bKeep = true ; + bool bKeep = true ; double dParTmp ; pCompo->GetCurveTempParam( i, dParTmp) ; if ( abs( dParTmp - VRONI_JUNCTION_OPEN) < EPS_SMALL) bKeep = false ; @@ -1087,8 +1087,8 @@ Voronoi::AdjustOffsetCurves( const ICurveComposite* pCompo, double dOffs) const if ( pCompoCurr->IsValid()) { vResult.emplace_back( Release( pCompoCurr)) ; pCompoCurr.Set( CreateBasicCurveComposite()) ; - } - } + } + } } // salvo eventuale ultima curva if ( pCompoCurr->IsValid()) @@ -1102,17 +1102,17 @@ Voronoi::AdjustOffsetCurves( const ICurveComposite* pCompo, double dOffs) const vResult.pop_back() ; } } - + return vResult ; } //--------------------------------------------------------------------------- -int -Voronoi::GetOffsetCurveSide( const ICurve* pCrv) const -{ +int +Voronoi::GetOffsetCurveSide( const ICurve* pCrv) const +{ if ( pCrv == nullptr) return -1 ; - + Point3d ptM ; pCrv->GetMidPoint( ptM) ; // recupero curva e sottocurva di riferimento dalle temp prop @@ -1121,8 +1121,8 @@ Voronoi::GetOffsetCurveSide( const ICurve* pCrv) const const ICurve* pCrvRef = m_vpCrvs[nOrigCrv] ; if ( nOrigSubCrv != 0 && m_vpCrvs[nOrigCrv]->GetType() == CRV_COMPO) { const CurveComposite* pCompoOrig = GetBasicCurveComposite( m_vpCrvs[nOrigCrv]) ; - if ( pCompoOrig != nullptr) - pCrvRef = pCompoOrig->GetCurve( nOrigSubCrv - 1) ; + if ( pCompoOrig != nullptr) + pCrvRef = pCompoOrig->GetCurve( nOrigSubCrv - 1) ; } DistPointCurve distPC( ptM, *pCrvRef) ; @@ -1132,9 +1132,9 @@ Voronoi::GetOffsetCurveSide( const ICurve* pCrv) const } //--------------------------------------------------------------------------- -bool -Voronoi::AdjustOffsetStart( ICurveComposite* pCrv) const -{ +bool +Voronoi::AdjustOffsetStart( ICurveComposite* pCrv) const +{ for ( int i = 0 ; i < pCrv->GetCurveCount() ; i++) { // cerco il tratto associato alla prima sottocurva originale int nOrigCrv ; pCrv->GetCurveTempProp( i, nOrigCrv) ; @@ -1154,15 +1154,15 @@ Voronoi::AdjustOffsetStart( ICurveComposite* pCrv) const //--------------------------------------------------------------------------- bool -Voronoi::Translate( const Vector3d & vtMove) -{ +Voronoi::Translate( const Vector3d & vtMove) +{ if ( ! IsValid()) return false ; return m_Frame.Translate( vtMove) ; } //--------------------------------------------------------------------------- -bool +bool Voronoi::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dAngDeg) { if ( ! IsValid()) @@ -1171,7 +1171,7 @@ Voronoi::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dAngDeg) } //--------------------------------------------------------------------------- -bool +bool Voronoi::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, double dSinAng) { if ( ! IsValid()) @@ -1180,7 +1180,7 @@ Voronoi::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, doub } //--------------------------------------------------------------------------- -bool +bool Voronoi::ToGlob( const Frame3d& frRef) { if ( ! IsValid()) @@ -1189,7 +1189,7 @@ Voronoi::ToGlob( const Frame3d& frRef) } //--------------------------------------------------------------------------- -bool +bool Voronoi::ToLoc( const Frame3d& frRef) { if ( ! IsValid()) @@ -1198,7 +1198,7 @@ Voronoi::ToLoc( const Frame3d& frRef) } //--------------------------------------------------------------------------- -bool +bool Voronoi::LocToLoc( const Frame3d& frOri, const Frame3d& frDest) { if ( ! IsValid()) @@ -1207,7 +1207,7 @@ Voronoi::LocToLoc( const Frame3d& frOri, const Frame3d& frDest) } //--------------------------------------------------------------------------- -bool +bool Voronoi::CalcLimitOffset( int nCrv, bool bLeft, double& dOffs) { if ( nCrv < 0 || nCrv > int( m_vpCrvs.size()) - 1) @@ -1221,14 +1221,14 @@ Voronoi::CalcLimitOffset( int nCrv, bool bLeft, double& dOffs) // verifico se necessario calcolo Voronoi if ( ! m_bVDComputed) CalcVoronoi() ; - + for ( int i = 4 ; i < m_vroni->GetNumberOfEdges() ; i ++) { // verifico se è un bisettore relativo alla curva richiesta e dal lato opportuno if ( m_vroni->IsRelatedEdge( i, nCrv, bLeft)) { // calcolo i parametri del bisettore double dParS, dParE ; m_vroni->GetBisectorParams( i, dParS, dParE) ; - dOffs = max( { dParS, dParE, dOffs}) ; + dOffs = max( { dParS, dParE, dOffs}) ; } }