diff --git a/CurveComposite.cpp b/CurveComposite.cpp index 544ab31..21b9b2c 100644 --- a/CurveComposite.cpp +++ b/CurveComposite.cpp @@ -2622,54 +2622,34 @@ CurveComposite::ArcsBezierCurvesToArcsPerpExtr( double dLinTol, double dAngTolDe } //---------------------------------------------------------------------------- -bool -CurveComposite::MergeCurves( double dLinTol, double dAngTolDeg, bool bStartEnd, bool bNeedSameProp) +static int +MergeTwoCurves( ICurve* pCrvP, ICurve* pCrvC, double& dCurrLinTol, double dCosAngTol, bool bNeedSameProp) { - // se non ci sono almeno 2 curve, esco subito - if ( m_CrvSmplS.size() < 2) - return true ; - // controllo sui limiti di tolleranza - dLinTol = max( dLinTol, EPS_SMALL) ; - dAngTolDeg = max( dAngTolDeg, EPS_ANG_SMALL) ; - // tolleranza lineare corrente - double dCurrLinTol = dLinTol ; - // devo verificare coppie di curve - auto iterP = m_CrvSmplS.begin() ; - auto iterC = next( iterP) ; - // mentre esiste la coppia - while ( iterC != m_CrvSmplS.end()) { - // se curve unite - if ( MergeTwoCurves( *iterP, *iterC, dCurrLinTol, dAngTolDeg, bNeedSameProp)) { - // cancello l'entità precedente e la tolgo dalla lista - delete (*iterP) ; - iterC = m_CrvSmplS.erase( iterP) ; - } - // altrimenti ripristino la tolleranza - else - dCurrLinTol = dLinTol ; - // avanzo - iterP = iterC ; - iterC = next( iterC) ; - } - // se richiesto e curva chiusa devo confrontare anche ultima e prima curva - if ( bStartEnd && IsClosed()) { - if ( MergeTwoCurves( *iterP, *(m_CrvSmplS.begin()), dCurrLinTol, dAngTolDeg, bNeedSameProp)) { - // cancello l'entità precedente e la tolgo dalla lista - delete (*iterP) ; - iterC = m_CrvSmplS.erase( iterP) ; + // se precedente molto corta + double dLenP ; + if ( pCrvP->GetLength( dLenP) && dLenP < dCurrLinTol) { + // se abbastanza allineata alla successiva + Vector3d vtDirP, vtDirC ; + if ( pCrvP->GetEndDir( vtDirP) && pCrvC->GetStartDir( vtDirC) && ( vtDirP * vtDirC) >= dCosAngTol) { + Point3d ptStart ; + return ( pCrvP->GetStartPoint( ptStart) && pCrvC->ModifyStart( ptStart) ? -1 : 0) ; } } - - // imposto ricalcolo della grafica - m_OGrMgr.Reset() ; - - return true ; -} - -//---------------------------------------------------------------------------- -bool -CurveComposite::MergeTwoCurves( ICurve* pCrvP, ICurve* pCrvC, double& dCurrLinTol, double dAngTolDeg, bool bNeedSameProp) -{ + // se corrente molto corta + double dLenC ; + if ( pCrvC->GetLength( dLenC) && dLenC < dCurrLinTol) { + // se abbastanza allineata alla precedente + Vector3d vtDirP, vtDirC ; + if ( pCrvP->GetEndDir( vtDirP) && pCrvC->GetStartDir( vtDirC) && ( vtDirP * vtDirC) >= dCosAngTol) { + Point3d ptEnd ; + return ( pCrvC->GetEndPoint( ptEnd) && pCrvP->ModifyEnd( ptEnd) ? 1 : 0) ; + } + } + // verifico compatibilità delle proprietà + int nTprP = pCrvP->GetTempProp() ; + int nTprC = pCrvC->GetTempProp() ; + if ( bNeedSameProp && nTprP != nTprC) + return 0 ; // coefficiente deduzione tolleranza const double COEFF_TOL = 0.7 ; // se entrambe rette @@ -2680,26 +2660,20 @@ CurveComposite::MergeTwoCurves( ICurve* pCrvP, ICurve* pCrvC, double& dCurrLinTo Vector3d vtDirP, vtDirC ; if ( pLineP != nullptr && pLineP->GetStartDir( vtDirP) && pLineC != nullptr && pLineC->GetStartDir( vtDirC) && - ( vtDirP * vtDirC) >= cos( dAngTolDeg * DEGTORAD)) { - // recupero le proprietà - int nTprP = pLineP->GetTempProp() ; - int nTprC = pLineC->GetTempProp() ; + ( vtDirP * vtDirC) >= dCosAngTol) { // verifico se il punto di giunzione sia eliminabile DistPointLine dPL( pLineP->GetEnd(), pLineP->GetStart(), pLineC->GetEnd()) ; double dSqDist ; - if ( dPL.GetSqDist( dSqDist) && dSqDist < dCurrLinTol * dCurrLinTol && - ( ! bNeedSameProp || nTprP == nTprC)) { - // se calcolo nuova linea ok, procedo con l'unione - CurveLine NewLine ; - if ( NewLine.Set( pLineP->GetStart(), pLineC->GetEnd())) { + if ( dPL.GetSqDist( dSqDist) && dSqDist < dCurrLinTol * dCurrLinTol) { + // se modifica linea corrente ok, procedo con l'unione + if ( pLineC->ModifyStart( pLineP->GetStart())) { // diminuisco la tolleranza corrente dell'errore attuale dCurrLinTol -= COEFF_TOL * sqrt( dSqDist) ; - // se curve originali con la stessa proprietà, la riporto - if ( nTprP == nTprC) - NewLine.SetTempProp( nTprC) ; - // aggiorno la linea corrente e torno flag modifica - *pLineC = NewLine ; - return true ; + // se curve originali con proprietà diversa, la cancello + if ( nTprP != nTprC) + pLineC->SetTempProp( 0) ; + // torno flag modifica + return -1 ; } } } @@ -2714,20 +2688,20 @@ CurveComposite::MergeTwoCurves( ICurve* pCrvP, ICurve* pCrvC, double& dCurrLinTo Point3d ptC2Ini = pArcC->GetCenter() ; // verifico la coincidenza dei centri if ( ! AreSamePointEpsilon( ptC1Fin, ptC2Ini, dCurrLinTol)) - return false ; + return 0 ; // verifico la coincidenza dei raggi if ( abs( pArcP->GetRadius() - pArcC->GetRadius()) > dCurrLinTol) - return false ; + return 0 ; // verifico la collinearità delle normali (tenendo conto del raggio) if ( ! (( pArcP->GetNormVersor() - pArcC->GetNormVersor()) * pArcP->GetRadius()).IsSmall() && ! (( pArcP->GetNormVersor() + pArcC->GetNormVersor()) * pArcP->GetRadius()).IsSmall()) - return false ; + return 0 ; // verifico la coincidenza del senso di rotazione (verso delle normali e segno angoli al centro) if ( pArcP->GetNormVersor() * pArcC->GetNormVersor() * pArcP->GetAngCenter() * pArcC->GetAngCenter() < 0) - return false ; + return 0 ; // verifico di non superare l'angolo giro al centro if ( abs( pArcP->GetAngCenter() + pArcC->GetAngCenter()) > ANG_FULL + EPS_ANG_SMALL) - return false ; + return 0 ; // se archi piatti if ( pArcP->IsPlane() && pArcC->IsPlane()) { // se calcolo nuovo arco ok, procedo con l'unione @@ -2747,16 +2721,14 @@ CurveComposite::MergeTwoCurves( ICurve* pCrvP, ICurve* pCrvC, double& dCurrLinTo if ( NewArc.GetNormVersor() * pArcC->GetNormVersor() < 0) NewArc.InvertN() ; // se curve originali con la stessa proprietà, la riporto - int nTprP = pArcP->GetTempProp() ; - int nTprC = pArcC->GetTempProp() ; if ( nTprP == nTprC) NewArc.SetTempProp( nTprC) ; // aggiorno l'arco corrente e torno flag modifica *pArcC = NewArc ; - return true ; + return -1 ; } else - return false ; + return 0 ; } // verifico coincidenza pendenza sulla normale double dN = pArcP->GetNormVersor() * pArcC->GetNormVersor() ; @@ -2772,24 +2744,81 @@ CurveComposite::MergeTwoCurves( ICurve* pCrvP, ICurve* pCrvC, double& dCurrLinTo CurveArc NewArc ; if ( NewArc.Set2PVN( ptP1, ptP3, vtDir1, pArcC->GetNormVersor())) { // se curve originali con la stessa proprietà, la riporto - int nTprP = pArcP->GetTempProp() ; - int nTprC = pArcC->GetTempProp() ; if ( nTprP == nTprC) NewArc.SetTempProp( nTprC) ; // aggiorno l'arco corrente e torno flag modifica *pArcC = NewArc ; - return true ; + return -1 ; } else - return false ; + return 0 ; } } + // nessuna fusione - return false ; + return 0 ; } //---------------------------------------------------------------------------- bool +CurveComposite::MergeCurves( double dLinTol, double dAngTolDeg, bool bStartEnd, bool bNeedSameProp) +{ + // se non ci sono almeno 2 curve, esco subito + if ( m_CrvSmplS.size() < 2) + return true ; + // controllo sui limiti di tolleranza + dLinTol = max( dLinTol, EPS_SMALL) ; + dAngTolDeg = max( dAngTolDeg, EPS_ANG_SMALL) ; + double dCosAngTol = cos( dAngTolDeg * DEGTORAD) ; + // tolleranza lineare corrente + double dCurrLinTol = dLinTol ; + // devo verificare coppie di curve + auto iterP = m_CrvSmplS.begin() ; + auto iterC = next( iterP) ; + // mentre esiste la coppia + while ( iterC != m_CrvSmplS.end()) { + // se curve unite + switch ( MergeTwoCurves( *iterP, *iterC, dCurrLinTol, dCosAngTol, bNeedSameProp)) { + case -1 : // cancello l'entità precedente e la tolgo dalla lista + delete (*iterP) ; + iterC = m_CrvSmplS.erase( iterP) ; + break ; + case 1 : // cancello l'entità corrente e la tolgo dalla lista + delete (*iterC) ; + iterC = m_CrvSmplS.erase( iterC) ; + iterC = prev( iterC) ; + break ; + default : // ripristino la tolleranza + dCurrLinTol = dLinTol ; + break ; + } + // avanzo + iterP = iterC ; + iterC = next( iterC) ; + } + // se richiesto e curva chiusa devo confrontare anche ultima e prima curva + if ( bStartEnd && m_CrvSmplS.size() >= 2 && IsClosed()) { + iterC = m_CrvSmplS.begin() ; + switch ( MergeTwoCurves( *iterP, *iterC, dCurrLinTol, dCosAngTol, bNeedSameProp)) { + case -1 : // cancello l'entità precedente e la tolgo dalla lista + delete (*iterP) ; + m_CrvSmplS.erase( iterP) ; + break ; + case 1 : // cancello l'entità corrente e la tolgo dalla lista + delete (*iterC) ; + m_CrvSmplS.erase( iterC) ; + break ; + } + } + + // imposto ricalcolo della grafica + m_OGrMgr.Reset() ; + + return true ; +} + +//---------------------------------------------------------------------------- +static bool SplitTopBottomArcs( CurveComposite& cCompo) { int i = 0 ; diff --git a/CurveComposite.h b/CurveComposite.h index 4cb240c..9cc7acb 100644 --- a/CurveComposite.h +++ b/CurveComposite.h @@ -181,7 +181,6 @@ class CurveComposite : public ICurveComposite, public IGeoObjRW bool AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart = true, double dLinTol = EPS_SMALL) ; bool GetIndSCurveAndLocPar( double dU, Side nS, int& nSCrv, double& dLocU) const ; bool SimpleOffsetXY( double dDist, int nType = OFF_FILLET) ; - bool MergeTwoCurves( ICurve* pCrvP, ICurve* pCrvC, double& dCurrLinTol, double dAngTolDeg, bool bNeedSameProp) ; bool IsOneCircle( Point3d& ptCen, Vector3d& vtN, double& dRad, bool& bCCW) const ; private : diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 775aa5b..1445527 100644 Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ diff --git a/OffsetCurve.cpp b/OffsetCurve.cpp index 79845ab..69ed9e1 100644 --- a/OffsetCurve.cpp +++ b/OffsetCurve.cpp @@ -1,13 +1,14 @@ //---------------------------------------------------------------------------- -// EgalTech 2015-2019 +// EgalTech 2015-2020 //---------------------------------------------------------------------------- -// File : OffsetCurve.cpp Data : 24.06.19 Versione : 2.1f2 +// File : OffsetCurve.cpp Data : 10.10.20 Versione : 2.2j2 // Contenuto : Classe per offset avanzato di Curve. // // // // Modifiche : 23.09.15 DS Creazione modulo. // 24.06.19 DS Agg. GetShorterCurve. +// 10.10.20 DS Migliorata gestione angoli interni. // //---------------------------------------------------------------------------- @@ -32,8 +33,8 @@ static bool PreviousIsLonger( int nInd1, const DBLVECTOR& vLens, bool bClosed) ; static bool NextIsLine( ICURVEPLIST::const_iterator iIter, const ICURVEPLIST& CrvLst, bool bClosed) ; static bool NextIsLonger( int nInd1, const DBLVECTOR& vLens, bool bClosed) ; static bool CalcAngle( const ICurve* pCrv1, const ICurve* pCrv2, double& dAngDeg) ; -static bool VerifyAndAdjustSamePoint( ICurve* pCrv1, ICurve* pCrv2) ; -static bool VerifyAndAdjustInternalAngle( ICurve* pCrv1, ICurve* pCrv2) ; +static bool VerifyAndAdjustSamePoint( ICurve* pCrv1, ICurve* pCrv2, int& nRes) ; +static bool VerifyAndAdjustInternalAngle( ICurve* pCrv1, ICurve* pCrv2, int& nRes) ; static bool VerifyAndAdjustExternalAngle( ICurve* pCrv1, ICurve* pCrv2, double dAngDeg, double dDist, int nType, CurveComposite& ccAux) ; static double GetMinDist( double dCoeff, ICurve* pCrv1, ICurve* pCrv2) ; @@ -283,8 +284,27 @@ OffsetCurve::Make( const ICurve* pCrv, double dDist, int nType) ICurve* pCrv = *iIter ; // gestione e verifica di estremi quasi coincidenti ed angoli interni if ( pPrev != nullptr) { - if ( ! VerifyAndAdjustSamePoint( pPrev, pCrv)) - VerifyAndAdjustInternalAngle( pPrev, pCrv) ; + int nRes ; + if ( VerifyAndAdjustSamePoint( pPrev, pCrv, nRes)) { + if ( nRes == 4) + VerifyAndAdjustInternalAngle( pPrev, pCrv, nRes) ; + // precedente da cancellare + if ( ( nRes & 1) != 0) { + auto iErase = prev( iIter != m_CrvLst.begin() ? iIter : m_CrvLst.end()) ; + delete pPrev ; + m_CrvLst.erase( iErase) ; + auto iPrev = prev( iIter != m_CrvLst.begin() ? iIter : m_CrvLst.end()) ; + pPrev = *iPrev ; + } + // corrente da cancellare + if ( ( nRes & 2) != 0) { + delete pCrv ; + iIter = m_CrvLst.erase( iIter) ; + } + // se eseguita una cancellazione, non devo incrementare + if ( ( nRes & 3) != 0) + continue ; + } } // passo al successivo pPrev = pCrv ; @@ -742,7 +762,7 @@ CalcAngle( const ICurve* pCrv1, const ICurve* pCrv2, double& dAngDeg) //---------------------------------------------------------------------------- bool -VerifyAndAdjustSamePoint( ICurve* pCrv1, ICurve* pCrv2) +VerifyAndAdjustSamePoint( ICurve* pCrv1, ICurve* pCrv2, int& nRes) { // verifica dei puntatori if ( pCrv1 == nullptr || pCrv2 == nullptr) @@ -753,19 +773,28 @@ VerifyAndAdjustSamePoint( ICurve* pCrv1, ICurve* pCrv2) if ( ! pCrv1->GetEndPoint( ptP1) || ! pCrv2->GetStartPoint( ptP2)) return false ; // verifica distanza tra estremi - if ( ! AreSamePointXYEpsilon( ptP1, ptP2, 10 * EPS_SMALL)) - return false ; - // se coincidono esattamente, va bene così - if ( AreSamePointExact( ptP1, ptP2)) + if ( ! AreSamePointXYEpsilon( ptP1, ptP2, 10 * EPS_SMALL)) { + nRes = 4 ; return true ; + } + // se coincidono esattamente, va bene così + if ( AreSamePointExact( ptP1, ptP2)) { + nRes = 0 ; + return true ; + } // sono in tolleranza, ma devo ricongiungere gli estremi + nRes = 0 ; Point3d ptMid = 0.5 * ( ptP1 + ptP2) ; - return ( pCrv1->ModifyEnd( ptMid) && pCrv2->ModifyStart( ptMid)) ; + if ( ! pCrv1->ModifyEnd( ptMid)) + nRes += 1 ; + if ( ! pCrv2->ModifyStart( ptMid)) + nRes += 2 ; + return true ; } //---------------------------------------------------------------------------- bool -VerifyAndAdjustInternalAngle( ICurve* pCrv1, ICurve* pCrv2) +VerifyAndAdjustInternalAngle( ICurve* pCrv1, ICurve* pCrv2, int& nRes) { // verifica dei puntatori if ( pCrv1 == nullptr || pCrv2 == nullptr) @@ -785,8 +814,13 @@ VerifyAndAdjustInternalAngle( ICurve* pCrv1, ICurve* pCrv2) ! intCC.GetIntersPointNearTo( 1, ptMid, ptNew2)) return false ; // modifico le due curve sul punto medio di intersezione + nRes = 0 ; Point3d ptNew = 0.5 * ( ptNew1 + ptNew2) ; - return ( pCrv1->ModifyEnd( ptNew) && pCrv2->ModifyStart( ptNew)) ; + if ( ! pCrv1->ModifyEnd( ptNew)) + nRes += 1 ; + if ( ! pCrv2->ModifyStart( ptNew)) + nRes += 2 ; + return true ; } //----------------------------------------------------------------------------