From b2db80edc9d9cdab00a31a8b9a2eae6b3b718f03 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Sat, 22 Aug 2015 13:48:19 +0000 Subject: [PATCH] EgtGeomKernel 1.6h4 : - aggiunto metodo GetCrossOrOverlapIntersCount a SelfIntersCurve - aggiunti metodi GetCrossIntersCount e GetCrossOrOverlapIntersCount a IntersCurveCurve - allentati controlli sui loop delle regioni, ora possono toccarsi ma non attraversarsi in punti isolati - aggiunte funzioni per operazioni booleante tra regioni Add, Subtract e Intersect. --- CurveCompositeOffset.cpp | 2 +- EgtGeomKernel.rc | Bin 11710 -> 11710 bytes EgtGeomKernel.vcxproj | 1 + EgtGeomKernel.vcxproj.filters | 3 + GdbExecutor.cpp | 4 +- IntersCrvCompoCrvCompo.cpp | 2 +- IntersCurveCurve.cpp | 79 +++++-- Intervals.cpp | 28 +-- SelfIntersCurve.cpp | 23 +- SurfFlatRegion.cpp | 150 +++++++++--- SurfFlatRegion.h | 28 ++- SurfFlatRegionBooleans.cpp | 426 ++++++++++++++++++++++++++++++++++ 12 files changed, 661 insertions(+), 85 deletions(-) create mode 100644 SurfFlatRegionBooleans.cpp diff --git a/CurveCompositeOffset.cpp b/CurveCompositeOffset.cpp index 4e0c3e0..32c96b9 100644 --- a/CurveCompositeOffset.cpp +++ b/CurveCompositeOffset.cpp @@ -227,7 +227,7 @@ VerifyAndAdjustInternalAngle( ICurve* pCrv1, ICurve* pCrv2, CurveComposite& ccAu // calcolo l'intersezione tra le due curve IntersCurveCurve intCC( *pCrv1, *pCrv2) ; - if ( intCC.GetNumInters() == 0) + if ( intCC.GetIntersCount() == 0) return false ; // prendo l'intersezione più vicina al punto medio tra gli estremi delle curve Point3d ptP1, ptP2 ; diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 7cf5b92b60a6ee66ff9fa5d2f2ea0c0fafb7cd17..ec3523f0d493d888648dcf0cb697ddeff0e7d02b 100644 GIT binary patch delta 94 zcmdlNy)SyhFE&P#&A-_cnHfzcD{|{@_Trkr0u;H;XNwSVW8B;$>;>dw2zN+>g;Df- LFmBFL4&ed-WjGrO delta 94 zcmdlNy)SyhFE&Qw&A-_cnHh~ID{|{@_Trkr0u;H;XNwSVW8B;$>;>dw2zN+>g;Df- LFmBFL4&ed-W11TR diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index d0e1317..9e76505 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -323,6 +323,7 @@ copy $(TargetPath) \EgtProg\Dll64 + diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index 27fe0a9..759102a 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -306,6 +306,9 @@ File di origine\GeoCreate + + File di origine\Geo + diff --git a/GdbExecutor.cpp b/GdbExecutor.cpp index 22c3265..c0fb3fb 100644 --- a/GdbExecutor.cpp +++ b/GdbExecutor.cpp @@ -5290,10 +5290,10 @@ GdbExecutor::ExecuteOutTextIcci( const string& sCmd2, const STRVECTOR& vsParams) IntersCurveCurve intCC( *pCrv1, *pCrv2, true) ; // preparo il testo con i risultati string sText = "Inters CrvA=" + ToString( nIdEnt1) + " CrvB=" + ToString( nIdEnt2) ; - sText += "
Nbr=" + ToString( intCC.GetNumInters()) ; + sText += "
Nbr=" + ToString( intCC.GetIntersCount()) ; if ( intCC.GetOverlaps()) sText += " Overlaps" ; - for ( int i = 0 ; i < intCC.GetNumInters() ; ++ i) { + for ( int i = 0 ; i < intCC.GetIntersCount() ; ++ i) { IntCrvCrvInfo aInfo ; intCC.GetIntCrvCrvInfo( i, aInfo) ; int nMax = ( aInfo.bOverlap ? 2 : 1) ; diff --git a/IntersCrvCompoCrvCompo.cpp b/IntersCrvCompoCrvCompo.cpp index 8d14b8a..dd98918 100644 --- a/IntersCrvCompoCrvCompo.cpp +++ b/IntersCrvCompoCrvCompo.cpp @@ -525,7 +525,7 @@ IntersCrvCompoCrvCompo::IntersSimpleCurves( const ICurve& CurveA, int nA, const // eseguo l'intersezione di queste curve semplici IntersCurveCurve intCC( CurveA, CurveB) ; // ne recupero i risultati - int nCurrInters = intCC.GetNumInters() ; + int nCurrInters = intCC.GetIntersCount() ; if ( nCurrInters > 0) { m_bOverlaps = ( intCC.GetOverlaps() ? true : m_bOverlaps) ; for ( int j = 0 ; j < nCurrInters ; ++ j) { diff --git a/IntersCurveCurve.cpp b/IntersCurveCurve.cpp index af83743..5d7c83c 100644 --- a/IntersCurveCurve.cpp +++ b/IntersCurveCurve.cpp @@ -36,7 +36,7 @@ IntersCurveCurve::IntersCurveCurve( const ICurve& CurveA, const ICurve& CurveB, // inizializzazioni m_bOverlaps = false ; - m_nNumInters = 0 ; + m_nIntersCount = 0 ; m_pCurve[0] = &CurveA ; m_pCurve[1] = &CurveB ; @@ -132,8 +132,8 @@ IntersCurveCurve::LineLineCalculate( const ICurve& CurveA, const ICurve& CurveB, if ( intLnLn.m_nNumInters > 0) { m_bOverlaps = intLnLn.m_bOverlaps ; - m_nNumInters = intLnLn.m_nNumInters ; - if ( m_nNumInters == 1) + m_nIntersCount = intLnLn.m_nNumInters ; + if ( m_nIntersCount == 1) m_Info.push_back( intLnLn.m_Info) ; } } @@ -146,8 +146,8 @@ IntersCurveCurve::LineArcCalculate( const ICurve& CurveA, const ICurve& CurveB) if ( intLnAr.m_nNumInters > 0) { m_bOverlaps = false ; - m_nNumInters = intLnAr.m_nNumInters ; - for ( int i = 0 ; i < m_nNumInters ; ++ i) + m_nIntersCount = intLnAr.m_nNumInters ; + for ( int i = 0 ; i < m_nIntersCount ; ++ i) m_Info.push_back( intLnAr.m_Info[i]) ; } } @@ -171,8 +171,8 @@ IntersCurveCurve::ArcLineCalculate( const ICurve& CurveA, const ICurve& CurveB) if ( intLnAr.m_nNumInters > 0) { m_bOverlaps = false ; - m_nNumInters = intLnAr.m_nNumInters ; - for ( int i = 0 ; i < m_nNumInters ; ++ i) + m_nIntersCount = intLnAr.m_nNumInters ; + for ( int i = 0 ; i < m_nIntersCount ; ++ i) m_Info.push_back( intLnAr.m_Info[i]) ; // devo scambiare opportunamente le info di intersezione tra A e B SwapInfoAB( m_Info, 0) ; @@ -187,8 +187,8 @@ IntersCurveCurve::ArcArcCalculate( const ICurve& CurveA, const ICurve& CurveB) if ( intArAr.m_nNumInters > 0) { m_bOverlaps = intArAr.m_bOverlaps ; - m_nNumInters = intArAr.m_nNumInters ; - for ( int i = 0 ; i < m_nNumInters ; ++ i) + m_nIntersCount = intArAr.m_nNumInters ; + for ( int i = 0 ; i < m_nIntersCount ; ++ i) m_Info.push_back( intArAr.m_Info[i]) ; } } @@ -234,8 +234,8 @@ IntersCurveCurve::CrvCompoCrvCompoCalculate( const ICurve& CurveA, const ICurve& if ( intCcCc.m_nNumInters > 0) { m_bOverlaps = intCcCc.m_bOverlaps ; - m_nNumInters = intCcCc.m_nNumInters ; - for ( int i = 0 ; i < m_nNumInters ; ++ i) + m_nIntersCount = intCcCc.m_nNumInters ; + for ( int i = 0 ; i < m_nIntersCount ; ++ i) m_Info.push_back( intCcCc.m_Info[i]) ; } } @@ -278,16 +278,55 @@ IntersCurveCurve::GetOverlaps( void) //---------------------------------------------------------------------------- int -IntersCurveCurve::GetNumInters( void) +IntersCurveCurve::GetIntersCount( void) { - return m_nNumInters ; + return m_nIntersCount ; +} + +//---------------------------------------------------------------------------- +int +IntersCurveCurve::GetCrossIntersCount( void) +{ + int nCrossIntersCount = 0 ; + for ( int i = 0 ; i < m_nIntersCount ; ++ i) { + // se con sovrapposizione + if ( m_Info[i].bOverlap) { + if ( m_Info[i].IciA[0].nPrevTy != m_Info[i].IciA[1].nNextTy && + m_Info[i].IciA[0].nPrevTy != ICCT_NULL && m_Info[i].IciA[1].nNextTy != ICCT_NULL) + ++ nCrossIntersCount ; + } + // altrimenti + else { + if ( m_Info[i].IciA[0].nPrevTy != m_Info[i].IciA[0].nNextTy && + m_Info[i].IciA[0].nPrevTy != ICCT_NULL && m_Info[i].IciA[0].nNextTy != ICCT_NULL) + ++ nCrossIntersCount ; + } + } + return nCrossIntersCount ; +} + +//---------------------------------------------------------------------------- +int +IntersCurveCurve::GetCrossOrOverlapIntersCount( void) +{ + int nCrossOverIntersCount = 0 ; + for ( int i = 0 ; i < m_nIntersCount ; ++ i) { + // se con sovrapposizione + if ( m_Info[i].bOverlap) + ++ nCrossOverIntersCount ; + // se altrimenti con attraversamento + else if ( m_Info[i].IciA[0].nPrevTy != m_Info[i].IciA[0].nNextTy && + m_Info[i].IciA[0].nPrevTy != ICCT_NULL && m_Info[i].IciA[0].nNextTy != ICCT_NULL) + ++ nCrossOverIntersCount ; + } + return nCrossOverIntersCount ; } //---------------------------------------------------------------------------- bool IntersCurveCurve::GetIntCrvCrvInfo( int nInd, IntCrvCrvInfo& aInfo) { - if ( nInd < 0 || nInd >= m_nNumInters) + if ( nInd < 0 || nInd >= m_nIntersCount) return false ; aInfo = m_Info[nInd] ; return true ; @@ -297,13 +336,13 @@ IntersCurveCurve::GetIntCrvCrvInfo( int nInd, IntCrvCrvInfo& aInfo) bool IntersCurveCurve::GetIntersPointNearTo( int nCrv, const Point3d& ptNear, Point3d& ptI) { - if ( m_nNumInters == 0 || nCrv < 0 || nCrv > 1) + if ( m_nIntersCount == 0 || nCrv < 0 || nCrv > 1) return false ; // ricerca del punto più vicino tra le intersezioni singole bool bFound = false ; double dMinSqDist = INFINITO * INFINITO ; - for ( int i = 0 ; i < m_nNumInters ; ++ i) { + for ( int i = 0 ; i < m_nIntersCount ; ++ i) { // se è un'intersezione singola if ( ! m_Info[i].bOverlap) { // faccio la verifica sul punto @@ -367,7 +406,7 @@ IntersCurveCurve::GetCurveClassification( int nCrv, CRVCVECTOR& ccClass) if ( ! m_pCurve[1]->IsClosed()) return false ; // se esiste almeno una intersezione - if ( m_nNumInters >= 1) + if ( m_nIntersCount >= 1) return CalcCurveClassification( m_pCurve[0], m_Info, ccClass) ; // altrimenti la curva è completamente interna oppure completamente esterna else @@ -384,7 +423,7 @@ IntersCurveCurve::GetCurveClassification( int nCrv, CRVCVECTOR& ccClass) // esecuzione scambio e controlli SwapInfoAB( InfoTmp, 1) ; // se esiste almeno una intersezione - if ( m_nNumInters >= 1) + if ( m_nIntersCount >= 1) return CalcCurveClassification( m_pCurve[1], InfoTmp, ccClass) ; // altrimenti la curva è completamente interna oppure completamente esterna else @@ -403,7 +442,7 @@ IntersCurveCurve::SwapInfoAB( ICCIVECTOR& Info, int IndCrvOrd) return false ; // eseguo lo scambio - for ( int i = 0 ; i < m_nNumInters ; ++ i) { + for ( int i = 0 ; i < m_nIntersCount ; ++ i) { // scambio le informazioni tra A e B swap( Info[i].IciA[0], Info[i].IciB[0]) ; swap( Info[i].IciA[1], Info[i].IciB[1]) ; @@ -538,7 +577,7 @@ IntersCurveCurve::CalcCurveInOrOut( const ICurve* pCurveA, const ICurve* pCurveB // dichiaro la classe della curva per default int nClass = CRVC_OUT ; // se c'è almeno una intersezione - if ( iCC.GetNumInters() > 0) { + if ( iCC.GetIntersCount() > 0) { // se quanto precede la prima intersezione è interno, allora la curva è interna IntCrvCrvInfo aInfo ; iCC.GetIntCrvCrvInfo( 0, aInfo) ; diff --git a/Intervals.cpp b/Intervals.cpp index 06cc63d..455fa36 100644 --- a/Intervals.cpp +++ b/Intervals.cpp @@ -92,7 +92,7 @@ Intervals::Add( double dMin, double dMax) //---------------------------------------------------------------------------- void -Intervals::Remove( double dMin, double dMax) +Intervals::Subtract( double dMin, double dMax) { // verifico ordine if ( dMin > dMax) @@ -142,7 +142,7 @@ Intervals::Remove( double dMin, double dMax) //---------------------------------------------------------------------------- void -Intervals::Union( const Intervals& Other) +Intervals::Add( const Intervals& Other) { // aggiungo tutti gli intervalli dell'altro for ( auto& Interv : Other.m_lInts) @@ -151,7 +151,16 @@ Intervals::Union( const Intervals& Other) //---------------------------------------------------------------------------- void -Intervals::Intersection( const Intervals& Other) +Intervals::Subtract( const Intervals& Other) +{ + // sottraggo tutti gli intervalli dell'altro + for ( auto& Interv : Other.m_lInts) + Subtract( Interv.first, Interv.second) ; +} + +//---------------------------------------------------------------------------- +void +Intervals::Intersect( const Intervals& Other) { // se l'insieme è vuoto non devo fare alcunché if ( m_lInts.empty()) @@ -160,18 +169,9 @@ Intervals::Intersection( const Intervals& Other) Intervals Aux ; Aux.Set( m_lInts.front().first, m_lInts.back().second) ; // Sottraggo Other da Aux - Aux.Difference( Other) ; + Aux.Subtract( Other) ; // Sottraggo Aux dal corrente - Difference( Aux) ; -} - -//---------------------------------------------------------------------------- -void -Intervals::Difference( const Intervals& Other) -{ - // sottraggo tutti gli intervalli dell'altro - for ( auto& Interv : Other.m_lInts) - Remove( Interv.first, Interv.second) ; + Subtract( Aux) ; } //---------------------------------------------------------------------------- diff --git a/SelfIntersCurve.cpp b/SelfIntersCurve.cpp index 7e25acd..715ed76 100644 --- a/SelfIntersCurve.cpp +++ b/SelfIntersCurve.cpp @@ -176,18 +176,37 @@ SelfIntersCurve::GetCrossIntersCount( void) for ( int i = 0 ; i < m_nIntersCount ; ++ i) { // se con sovrapposizione if ( m_Info[i].bOverlap) { - if ( m_Info[i].IciA[0].nPrevTy != m_Info[i].IciA[1].nNextTy) + if ( m_Info[i].IciA[0].nPrevTy != m_Info[i].IciA[1].nNextTy && + m_Info[i].IciA[0].nPrevTy != ICCT_NULL && m_Info[i].IciA[1].nNextTy != ICCT_NULL) ++ nCrossIntersCount ; } // altrimenti else { - if ( m_Info[i].IciA[0].nPrevTy != m_Info[i].IciA[0].nNextTy) + if ( m_Info[i].IciA[0].nPrevTy != m_Info[i].IciA[0].nNextTy && + m_Info[i].IciA[0].nPrevTy != ICCT_NULL && m_Info[i].IciA[0].nNextTy != ICCT_NULL) ++ nCrossIntersCount ; } } return nCrossIntersCount ; } +//---------------------------------------------------------------------------- +int +SelfIntersCurve::GetCrossOrOverlapIntersCount( void) +{ + int nCrossOverIntersCount = 0 ; + for ( int i = 0 ; i < m_nIntersCount ; ++ i) { + // se con sovrapposizione + if ( m_Info[i].bOverlap) + ++ nCrossOverIntersCount ; + // se altrimenti con attraversamento + else if ( m_Info[i].IciA[0].nPrevTy != m_Info[i].IciA[0].nNextTy && + m_Info[i].IciA[0].nPrevTy != ICCT_NULL && m_Info[i].IciA[0].nNextTy != ICCT_NULL) + ++ nCrossOverIntersCount ; + } + return nCrossOverIntersCount ; +} + //---------------------------------------------------------------------------- bool SelfIntersCurve::GetIntCrvCrvInfo( int nInd, IntCrvCrvInfo& aInfo) diff --git a/SurfFlatRegion.cpp b/SurfFlatRegion.cpp index bc2fd4e..4cce55e 100644 --- a/SurfFlatRegion.cpp +++ b/SurfFlatRegion.cpp @@ -116,16 +116,16 @@ SurfFlatRegion::AddExtLoop( ICurve* pCrv) // porto la curva nel riferimento intrinseco if ( ! pMyCrv->ToLoc( m_frF)) return false ; - // verifico non abbia auto-intersezioni + // verifico non abbia auto-intersezioni che si attraversano SelfIntersCurve sInt( *pMyCrv) ; - if ( sInt.GetIntersCount() > 0) + if ( sInt.GetCrossOrOverlapIntersCount() > 0) return false ; // verifico che sia esterna alle curve esterne degli altri chunk bool bOk = true ; CRVCVECTOR ccClass ; for ( auto i : m_vExtInd) { IntersCurveCurve ccInt( *pMyCrv, *m_vpLoop[i]) ; - if ( ccInt.GetNumInters() > 0 || + if ( ccInt.GetCrossOrOverlapIntersCount() > 0 || ! ccInt.GetCurveClassification( 0, ccClass) || ccClass.empty() || ccClass[0].nClass != CRVC_OUT) { bOk = false ; @@ -138,7 +138,7 @@ SurfFlatRegion::AddExtLoop( ICurve* pCrv) if ( binary_search( m_vExtInd.begin(), m_vExtInd.end(), i)) continue ; IntersCurveCurve ccInt( *pMyCrv, *m_vpLoop[i]) ; - if ( ccInt.GetNumInters() == 0 && + if ( ccInt.GetCrossOrOverlapIntersCount() == 0 && ccInt.GetCurveClassification( 0, ccClass) && ! ccClass.empty() && ccClass[0].nClass == CRVC_OUT) { bOk = true ; @@ -148,15 +148,30 @@ SurfFlatRegion::AddExtLoop( ICurve* pCrv) if ( ! bOk) return false ; // assegno la curva come loop esterno - m_vpLoop.push_back( Release( pMyCrv)) ; - m_vExtInd.push_back( int( m_vpLoop.size()) - 1) ; - m_nStatus = OK ; + if ( MyAddExtLoop( Get( pMyCrv))) + Release( pMyCrv) ; // imposto ricalcolo della grafica ResetAuxSurf() ; m_OGrMgr.Reset() ; return true ; } +//---------------------------------------------------------------------------- +bool +SurfFlatRegion::MyAddExtLoop( ICurve* pCrv) +{ + try { + m_vpLoop.push_back( pCrv) ; + m_vExtInd.push_back( int( m_vpLoop.size()) - 1) ; + m_nStatus = OK ; + } + catch (...) { + return false ; + } + + return true ; +} + //---------------------------------------------------------------------------- bool SurfFlatRegion::AddIntLoop( const ICurve& cCrv) @@ -201,25 +216,40 @@ SurfFlatRegion::AddIntLoop( ICurve* pCrv) pMyCrv->Invert() ; // verifico non abbia auto-intersezioni SelfIntersCurve sInt( *pMyCrv) ; - if ( sInt.GetIntersCount() > 0) + if ( sInt.GetCrossOrOverlapIntersCount() > 0) return false ; // verifico non abbia intersezioni e non sia esterna ai loop già definiti del medesimo chunk CRVCVECTOR ccClass ; for ( int i = m_vExtInd.back() ; i < int( m_vpLoop.size()) ; ++ i) { IntersCurveCurve ccInt( *pMyCrv, *m_vpLoop[i]) ; - if ( ccInt.GetNumInters() > 0 || + if ( ccInt.GetCrossOrOverlapIntersCount() > 0 || ! ccInt.GetCurveClassification( 0, ccClass) || ccClass.empty() || ccClass[0].nClass != CRVC_IN) return false ; } // aggiungo la curva all'elenco dei loop - m_vpLoop.push_back( Release( pMyCrv)) ; + if ( MyAddIntLoop( Get( pMyCrv))) + Release( pMyCrv) ; // imposto ricalcolo della grafica ResetAuxSurf() ; m_OGrMgr.Reset() ; return true ; } +//---------------------------------------------------------------------------- +bool +SurfFlatRegion::MyAddIntLoop( ICurve* pCrv) +{ + try { + m_vpLoop.push_back( pCrv) ; + } + catch (...) { + return false ; + } + + return true ; +} + //---------------------------------------------------------------------------- SurfFlatRegion* SurfFlatRegion::Clone( void) const @@ -831,7 +861,8 @@ SurfFlatRegion::GetAuxSurf( void) const int j = 0 ; ICurve* pLoop = GetMyLoop( i, j) ; while ( pLoop != nullptr) { - if ( ! pLoop->ApproxWithLines( LIN_TOL_SFR, ANG_TOL_STD_DEG, ICurve::APL_STD, vPL[j])) + // approssimo con linee a destra per non avere problemi in punti di contatto tra esterni e interni + if ( ! pLoop->ApproxWithLines( LIN_TOL_SFR, ANG_TOL_STD_DEG, ICurve::APL_RIGHT, vPL[j])) return nullptr ; pLoop = GetMyLoop( i, ++j) ; } @@ -888,8 +919,9 @@ SurfFlatRegion::CloneChunk( int nChunk) const //---------------------------------------------------------------------------- bool -SurfFlatRegion::GetCurveClassification( const ICurve& Crv, CRVCVECTOR& ccClass) const +SurfFlatRegion::MyGetCurveClassification( const ICurve& Crv, CRVCVECTOR& ccClass) const { + // la curva devono già essere nel riferimento intrinseco della regione // verifico lo stato if ( m_nStatus != OK || m_vpLoop.empty()) return false ; @@ -900,18 +932,6 @@ SurfFlatRegion::GetCurveClassification( const ICurve& Crv, CRVCVECTOR& ccClass) double dStart, dEnd ; if ( ! Crv.GetDomain( dStart, dEnd)) return false ; - // curva in locale nel riferimento intrinseco - const ICurve* pCrvLoc = nullptr ; - PtrOwner pCopyCrv ; - if ( AreSameFrame( m_frF, GLOB_FRM)) - pCrvLoc = &Crv ; - else { - pCopyCrv.Set( Crv.Clone()) ; - if ( IsNull( pCopyCrv)) - return false ; - pCopyCrv->ToLoc( m_frF) ; - pCrvLoc = Get( pCopyCrv) ; - } // intervalli totali delle diverse classi Intervals inTIn, inTOut, inTOnP, inTOnM ; @@ -925,7 +945,7 @@ SurfFlatRegion::GetCurveClassification( const ICurve& Crv, CRVCVECTOR& ccClass) for ( int nLoop = 0 ; nLoop < GetLoopCount( nChunk) ; ++ nLoop) { const ICurve* pLoop = GetMyLoop( nChunk, nLoop) ; // intersezione - IntersCurveCurve ccInt( *pCrvLoc, *pLoop) ; + IntersCurveCurve ccInt( Crv, *pLoop) ; // classificazione CRVCVECTOR ccPart ; if ( ! ccInt.GetCurveClassification( 0, ccPart)) @@ -936,16 +956,46 @@ SurfFlatRegion::GetCurveClassification( const ICurve& Crv, CRVCVECTOR& ccClass) // IN è Remove degli altri break ; case CRVC_OUT : - inCOut.Add( ccOne.dParS, ccOne.dParE) ; - inCIn.Remove( ccOne.dParS, ccOne.dParE) ; + // intervallo standard + if ( ccOne.dParS < ccOne.dParE - EPS_PARAM) { + inCOut.Add( ccOne.dParS, ccOne.dParE) ; + inCIn.Subtract( ccOne.dParS, ccOne.dParE) ; + } + // intervallo che attraversa punto di chiusura della curva + else { + inCOut.Add( ccOne.dParS, dEnd) ; + inCOut.Add( dStart, ccOne.dParE) ; + inCIn.Subtract( ccOne.dParS, dEnd) ; + inCIn.Subtract( dStart, ccOne.dParE) ; + } break ; case CRVC_ON_P : - inCOnP.Add( ccOne.dParS, ccOne.dParE) ; - inCIn.Remove( ccOne.dParS, ccOne.dParE) ; + // intervallo standard + if ( ccOne.dParS < ccOne.dParE - EPS_PARAM) { + inCOnP.Add( ccOne.dParS, ccOne.dParE) ; + inCIn.Subtract( ccOne.dParS, ccOne.dParE) ; + } + // intervallo che attraversa punto di chiusura della curva + else { + inCOnP.Add( ccOne.dParS, dEnd) ; + inCOnP.Add( dStart, ccOne.dParE) ; + inCIn.Subtract( ccOne.dParS, dEnd) ; + inCIn.Subtract( dStart, ccOne.dParE) ; + } break ; case CRVC_ON_M : - inCOnM.Add( ccOne.dParS, ccOne.dParE) ; - inCIn.Remove( ccOne.dParS, ccOne.dParE) ; + // intervallo standard + if ( ccOne.dParS < ccOne.dParE - EPS_PARAM) { + inCOnM.Add( ccOne.dParS, ccOne.dParE) ; + inCIn.Subtract( ccOne.dParS, ccOne.dParE) ; + } + // intervallo che attraversa punto di chiusura della curva + else { + inCOnM.Add( ccOne.dParS, dEnd) ; + inCOnM.Add( dStart, ccOne.dParE) ; + inCIn.Subtract( ccOne.dParS, dEnd) ; + inCIn.Subtract( dStart, ccOne.dParE) ; + } break ; default : return false ; } @@ -953,13 +1003,13 @@ SurfFlatRegion::GetCurveClassification( const ICurve& Crv, CRVCVECTOR& ccClass) } // aggiorno gli intervalli di classificazione totali // In, OnP e OnM vengono aggiornati per somma - inTIn.Union( inCIn) ; - inTOnP.Union( inCOnP) ; - inTOnM.Union( inCOnM) ; + inTIn.Add( inCIn) ; + inTOnP.Add( inCOnP) ; + inTOnM.Add( inCOnM) ; // Out viene ricavato per differenza degli altri - inTOut.Difference( inCIn) ; - inTOut.Difference( inCOnP) ; - inTOut.Difference( inCOnM) ; + inTOut.Subtract( inCIn) ; + inTOut.Subtract( inCOnP) ; + inTOut.Subtract( inCOnM) ; } // ricostruisco la classificazione completa e la ordino @@ -987,4 +1037,30 @@ SurfFlatRegion::GetCurveClassification( const ICurve& Crv, CRVCVECTOR& ccClass) sort( ccClass.begin(), ccClass.end(), []( const CrvClass& a, const CrvClass& b) { return a.dParS < b.dParS ; }) ; return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFlatRegion::GetCurveClassification( const ICurve& Crv, CRVCVECTOR& ccClass) const +{ + // verifico lo stato + if ( m_nStatus != OK || m_vpLoop.empty()) + return false ; + // verifico la curva + if ( &Crv == nullptr || ! Crv.IsValid()) + return false ; + // curva in locale nel riferimento intrinseco + const ICurve* pCrvLoc = nullptr ; + PtrOwner pCopyCrv ; + if ( AreSameFrame( m_frF, GLOB_FRM)) + pCrvLoc = &Crv ; + else { + pCopyCrv.Set( Crv.Clone()) ; + if ( IsNull( pCopyCrv)) + return false ; + pCopyCrv->ToLoc( m_frF) ; + pCrvLoc = Get( pCopyCrv) ; + } + // esecuzione classificazione nel riferimento intrinseco + return MyGetCurveClassification( *pCrvLoc, ccClass) ; } \ No newline at end of file diff --git a/SurfFlatRegion.h b/SurfFlatRegion.h index e47e407..49f2845 100644 --- a/SurfFlatRegion.h +++ b/SurfFlatRegion.h @@ -75,6 +75,9 @@ class SurfFlatRegion : public ISurfFlatRegion, public IGeoObjRW virtual bool AddExtLoop( ICurve* pCrv) ; virtual bool AddIntLoop( const ICurve& cCrv) ; virtual bool AddIntLoop( ICurve* pCrv) ; + virtual bool Add( const ISurfFlatRegion& Other) ; + virtual bool Subtract( const ISurfFlatRegion& Other) ; + virtual bool Intersect( const ISurfFlatRegion& Other) ; virtual const Vector3d& GetNormVersor( void) const { return m_frF.VersZ() ; } virtual int GetChunkCount( void) const ; @@ -98,14 +101,6 @@ class SurfFlatRegion : public ISurfFlatRegion, public IGeoObjRW { if ( ! CopyFrom( stSrc)) LOG_ERROR( GetEGkLogger(), "SurfFlatRegion : copy error") return *this ; } - private : - bool CopyFrom( const SurfFlatRegion& clSrc) ; - int GetIndFromChunkLoop( int nChunk, int nLoop) const ; - bool GetChunkLoopFromInd( int nInd, int& nChunk, int& nLoop) const ; - ICurve* GetMyLoop( int nInd) const ; // indice nel vettore di tutti i loop - ICurve* GetMyLoop( int nChunk, int nLoop) const ; // nChunk 0-based, nLoop 0-based (1°esterno, successivi interni) - void ResetAuxSurf( void) const ; - bool ConvertArcsToBezierCurves( void) ; private : enum Status { ERR = 0, OK = 1, TO_VERIFY = 2} ; @@ -113,6 +108,23 @@ class SurfFlatRegion : public ISurfFlatRegion, public IGeoObjRW private : typedef std::deque PCRV_DEQUE ; + private : + bool CopyFrom( const SurfFlatRegion& clSrc) ; + bool MyAddExtLoop( ICurve* pCrv) ; + bool MyAddIntLoop( ICurve* pCrv) ; + int GetIndFromChunkLoop( int nChunk, int nLoop) const ; + bool GetChunkLoopFromInd( int nInd, int& nChunk, int& nLoop) const ; + ICurve* GetMyLoop( int nInd) const ; // indice nel vettore di tutti i loop + ICurve* GetMyLoop( int nChunk, int nLoop) const ; // nChunk 0-based, nLoop 0-based (1°esterno, successivi interni) + void ResetAuxSurf( void) const ; + bool ConvertArcsToBezierCurves( void) ; + bool MyGetCurveClassification( const ICurve& Crv, CRVCVECTOR& ccClass) const ; + static bool MySelectCurves( const PCRV_DEQUE& vpLoop, const SurfFlatRegion& Other, + int nType1, bool bInvert1, int nType2, bool bInvert2, PCRV_DEQUE& vpCurve) ; + static bool MyChainCurves( PCRV_DEQUE& vpCurve, PCRV_DEQUE& vpLoop) ; + static SurfFlatRegion* MyNewSurfFromLoops( PCRV_DEQUE& vpLoop) ; + static bool MyTestAndDelete( PCRV_DEQUE& vpCrv) ; + private : ObjGraphicsMgr m_OGrMgr ; // gestore grafica dell'oggetto mutable SurfTriMesh* m_pSTM ; // superficie trimesh ausiliaria diff --git a/SurfFlatRegionBooleans.cpp b/SurfFlatRegionBooleans.cpp new file mode 100644 index 0000000..b3b7497 --- /dev/null +++ b/SurfFlatRegionBooleans.cpp @@ -0,0 +1,426 @@ +//---------------------------------------------------------------------------- +// EgalTech 2015-2015 +//---------------------------------------------------------------------------- +// File : SurfFlatRegion.cpp Data : 18.08.15 Versione : 1.6h4 +// Contenuto : Implementazione delle funzioni booleane per SurfFlatRegion. +// +// +// +// Modifiche : 18.08.15 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "SurfFlatRegion.h" +#include "CurveComposite.h" +#include "GeoConst.h" +#include "/EgtDev/Include/EGkChainCurves.h" +#include "/EgtDev/Include/EGkIntervals.h" +#include "/EgtDev/Include/EgtPointerOwner.h" + +using namespace std ; + +//---------------------------------------------------------------------------- +bool +SurfFlatRegion::Add( const ISurfFlatRegion& Other) +{ + // converto l'altra regione nell'oggetto base + const SurfFlatRegion& SfrOther = dynamic_cast( Other) ; + if ( &SfrOther == nullptr) + return false ; + + // verifico che le due regioni giacciano nello stesso piano + if ( ! AreSameVectorApprox( m_frF.VersZ(), SfrOther.m_frF.VersZ()) || + fabs( ( m_frF.Orig() - SfrOther.m_frF.Orig()) * m_frF.VersZ()) > EPS_SMALL) + return false ; + + // gestione eventuale copia dell'altra per trasformare il riferimento + const SurfFlatRegion* pOther = &SfrOther ; + PtrOwner pCopyOth ; + // se riferimenti intrinseci diversi, la trasformo + if ( ! AreSameFrame( m_frF, SfrOther.m_frF)) { + // creo la copia + pCopyOth.Set( SfrOther.Clone()) ; + if ( IsNull( pCopyOth)) + return false ; + // calcolo riferimento di traformazione + Frame3d frTransf = pCopyOth->m_frF ; + frTransf.ToLoc( m_frF) ; + // trasformo le curve + for ( auto& pLoop : pCopyOth->m_vpLoop) + pLoop->ToGlob( frTransf) ; + // assegno il nuovo riferimento + pCopyOth->m_frF = m_frF ; + // aggiorno puntatore della copia in lavoro + pOther = Get( pCopyOth) ; + } + + // vettore con curve utili da entrambe le regioni + PCRV_DEQUE vpCurve ; + if ( ! MySelectCurves( m_vpLoop, *pOther, CRVC_OUT, false, CRVC_ON_P, false, vpCurve) || + ! MySelectCurves( pOther->m_vpLoop, *this, CRVC_OUT, false, CRVC_NULL, false, vpCurve)) { + MyTestAndDelete( vpCurve) ; + return false ; + } + + // vettore con curve concatenate che sono i contorni del risultato + PCRV_DEQUE vpLoop ; + // concateno e verifico di aver usato tutte le curve + if ( ! MyChainCurves( vpCurve, vpLoop) || ! MyTestAndDelete( vpCurve)) { + MyTestAndDelete( vpLoop) ; + return false ; + } + + // creo una nuova regione a partire da questi loop + PtrOwner pSfr( MyNewSurfFromLoops( vpLoop)) ; + if ( IsNull( pSfr)) + return false ; + + // pulisco la superficie corrente + for ( auto& pLoop : m_vpLoop) + delete pLoop ; + m_vpLoop.clear() ; + + // sposto i dati della nuova superficie in quella corrente + m_vExtInd = pSfr->m_vExtInd ; + m_vpLoop = pSfr->m_vpLoop ; + for ( auto& pLoop : pSfr->m_vpLoop) + pLoop = nullptr ; + m_nStatus = pSfr->m_nStatus ; + + // imposto ricalcolo della grafica + ResetAuxSurf() ; + m_OGrMgr.Reset() ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFlatRegion::Subtract( const ISurfFlatRegion& Other) +{ + // converto l'altra regione nell'oggetto base + const SurfFlatRegion& SfrOther = dynamic_cast( Other) ; + if ( &SfrOther == nullptr) + return false ; + + // verifico che le due regioni giacciano nello stesso piano + if ( ! AreSameVectorApprox( m_frF.VersZ(), SfrOther.m_frF.VersZ()) || + fabs( ( m_frF.Orig() - SfrOther.m_frF.Orig()) * m_frF.VersZ()) > EPS_SMALL) + return false ; + + // gestione eventuale copia dell'altra per trasformare il riferimento + const SurfFlatRegion* pOther = &SfrOther ; + PtrOwner pCopyOth ; + // se riferimenti intrinseci diversi, la trasformo + if ( ! AreSameFrame( m_frF, SfrOther.m_frF)) { + // creo la copia + pCopyOth.Set( SfrOther.Clone()) ; + if ( IsNull( pCopyOth)) + return false ; + // calcolo riferimento di traformazione + Frame3d frTransf = pCopyOth->m_frF ; + frTransf.ToLoc( m_frF) ; + // trasformo le curve + for ( auto& pLoop : pCopyOth->m_vpLoop) + pLoop->ToGlob( frTransf) ; + // assegno il nuovo riferimento + pCopyOth->m_frF = m_frF ; + // aggiorno puntatore della copia in lavoro + pOther = Get( pCopyOth) ; + } + + // vettore con curve utili da entrambe le regioni + PCRV_DEQUE vpCurve ; + if ( ! MySelectCurves( m_vpLoop, *pOther, CRVC_OUT, false, CRVC_ON_M, false, vpCurve) || + ! MySelectCurves( pOther->m_vpLoop, *this, CRVC_IN, true, CRVC_NULL, false, vpCurve)) { + MyTestAndDelete( vpCurve) ; + return false ; + } + + // vettore con curve concatenate che sono i contorni del risultato + PCRV_DEQUE vpLoop ; + // concateno e verifico di aver usato tutte le curve + if ( ! MyChainCurves( vpCurve, vpLoop) || ! MyTestAndDelete( vpCurve)) { + MyTestAndDelete( vpLoop) ; + return false ; + } + + // creo una nuova regione a partire da questi loop + PtrOwner pSfr( MyNewSurfFromLoops( vpLoop)) ; + if ( IsNull( pSfr)) + return false ; + + // pulisco la superficie corrente + for ( auto& pLoop : m_vpLoop) + delete pLoop ; + m_vpLoop.clear() ; + + // sposto i dati della nuova superficie in quella corrente + m_vExtInd = pSfr->m_vExtInd ; + m_vpLoop = pSfr->m_vpLoop ; + for ( auto& pLoop : pSfr->m_vpLoop) + pLoop = nullptr ; + m_nStatus = pSfr->m_nStatus ; + + // imposto ricalcolo della grafica + ResetAuxSurf() ; + m_OGrMgr.Reset() ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFlatRegion::Intersect( const ISurfFlatRegion& Other) +{ + // converto l'altra regione nell'oggetto base + const SurfFlatRegion& SfrOther = dynamic_cast( Other) ; + if ( &SfrOther == nullptr) + return false ; + + // verifico che le due regioni giacciano nello stesso piano + if ( ! AreSameVectorApprox( m_frF.VersZ(), SfrOther.m_frF.VersZ()) || + fabs( ( m_frF.Orig() - SfrOther.m_frF.Orig()) * m_frF.VersZ()) > EPS_SMALL) + return false ; + + // gestione eventuale copia dell'altra per trasformare il riferimento + const SurfFlatRegion* pOther = &SfrOther ; + PtrOwner pCopyOth ; + // se riferimenti intrinseci diversi, la trasformo + if ( ! AreSameFrame( m_frF, SfrOther.m_frF)) { + // creo la copia + pCopyOth.Set( SfrOther.Clone()) ; + if ( IsNull( pCopyOth)) + return false ; + // calcolo riferimento di traformazione + Frame3d frTransf = pCopyOth->m_frF ; + frTransf.ToLoc( m_frF) ; + // trasformo le curve + for ( auto& pLoop : pCopyOth->m_vpLoop) + pLoop->ToGlob( frTransf) ; + // assegno il nuovo riferimento + pCopyOth->m_frF = m_frF ; + // aggiorno puntatore della copia in lavoro + pOther = Get( pCopyOth) ; + } + + // vettore con curve utili da entrambe le regioni + PCRV_DEQUE vpCurve ; + if ( ! MySelectCurves( m_vpLoop, *pOther, CRVC_IN, false, CRVC_ON_P, false, vpCurve) || + ! MySelectCurves( pOther->m_vpLoop, *this, CRVC_IN, false, CRVC_NULL, false, vpCurve)) { + MyTestAndDelete( vpCurve) ; + return false ; + } + + // vettore con curve concatenate che sono i contorni del risultato + PCRV_DEQUE vpLoop ; + // concateno e verifico di aver usato tutte le curve + if ( ! MyChainCurves( vpCurve, vpLoop) || ! MyTestAndDelete( vpCurve)) { + MyTestAndDelete( vpLoop) ; + return false ; + } + + // creo una nuova regione a partire da questi loop + PtrOwner pSfr( MyNewSurfFromLoops( vpLoop)) ; + if ( IsNull( pSfr)) + return false ; + + // pulisco la superficie corrente + for ( auto& pLoop : m_vpLoop) + delete pLoop ; + m_vpLoop.clear() ; + + // sposto i dati della nuova superficie in quella corrente + m_vExtInd = pSfr->m_vExtInd ; + m_vpLoop = pSfr->m_vpLoop ; + for ( auto& pLoop : pSfr->m_vpLoop) + pLoop = nullptr ; + m_nStatus = pSfr->m_nStatus ; + + // imposto ricalcolo della grafica + ResetAuxSurf() ; + m_OGrMgr.Reset() ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFlatRegion::MySelectCurves( const PCRV_DEQUE& vpLoop, const SurfFlatRegion& Other, + int nType1, bool bInvert1, int nType2, bool bInvert2, + PCRV_DEQUE& vpCurve) +{ + // classifico le curve rispetto alla regione altra e copio le parti utili + for ( auto& pLoop : vpLoop) { + // eseguo classificazione + CRVCVECTOR ccClass ; + if ( ! Other.MyGetCurveClassification( *pLoop, ccClass)) + return false ; + // creo intervalli validi, tenendo classificazioni ricevute + Intervals inOk1, inOk2 ; + for ( auto& ccOne : ccClass) { + if ( nType1 != CRVC_NULL && ccOne.nClass == nType1) + inOk1.Add( ccOne.dParE, ccOne.dParS) ; + else if ( nType2 != CRVC_NULL && ccOne.nClass == nType2) + inOk2.Add( ccOne.dParE, ccOne.dParS) ; + } + // copio queste parti + double dParS, dParE ; + bool bFound = inOk1.GetFirst( dParS, dParE) ; + while ( bFound) { + ICurve* pCrv = pLoop->CopyParamRange( dParS, dParE) ; + if ( pCrv != nullptr) { + if ( bInvert1) + pCrv->Invert() ; + vpCurve.push_back( pCrv) ; + } + bFound = inOk1.GetNext( dParS, dParE) ; + } + bFound = inOk2.GetFirst( dParS, dParE) ; + while ( bFound) { + ICurve* pCrv = pLoop->CopyParamRange( dParS, dParE) ; + if ( pCrv != nullptr) { + if ( bInvert2) + pCrv->Invert() ; + vpCurve.push_back( pCrv) ; + } + bFound = inOk2.GetNext( dParS, dParE) ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFlatRegion::MyChainCurves( PCRV_DEQUE& vpCurve, PCRV_DEQUE& vpLoop) +{ + // concateno le curve + ChainCurves chainC ; + chainC.Init( false, 5 * EPS_SMALL, int( vpCurve.size())) ; + for ( int i = 0 ; i < int( vpCurve.size()) ; ++i) { + // recupero i dati della curva necessari al concatenamento e li assegno + Point3d ptStart, ptEnd ; + Vector3d vtStart, vtEnd ; + if ( ! vpCurve[i]->GetStartPoint( ptStart) || ! vpCurve[i]->GetStartDir( vtStart) || + ! vpCurve[i]->GetEndPoint( ptEnd) || ! vpCurve[i]->GetEndDir( vtEnd)) + return false ; + if ( ! chainC.AddCurve( i + 1, ptStart, vtStart, ptEnd, vtEnd)) + return false ; + } + // recupero i percorsi concatenati + INTVECTOR vIds ; + Point3d ptNearStart ; + while ( chainC.GetChainFromNear( ptNearStart, false, vIds)) { + // creo una curva composita + PtrOwner pCrvCompo( CreateBasicCurveComposite()) ; + if ( IsNull( pCrvCompo)) + return false ; + // recupero le curve e le inserisco nella nuova curva composita + for ( auto i : vIds) { + // la aggiungo alla curva composta + if ( ! pCrvCompo->AddCurve( vpCurve[i-1], true, 5 * EPS_SMALL)) + return false ; + vpCurve[i-1] = nullptr ; + } + // aggiorno il nuovo punto vicino + if ( pCrvCompo->GetCurveCount() > 0) + pCrvCompo->GetEndPoint( ptNearStart) ; + // compatto la nuova curva + pCrvCompo->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG) ; + // inserisco la curva composita nel gruppo destinazione + if ( pCrvCompo->GetCurveCount() > 0) { + vpLoop.push_back( ::Release( pCrvCompo)) ; + } + } + return true ; +} + +//---------------------------------------------------------------------------- +SurfFlatRegion* +SurfFlatRegion::MyNewSurfFromLoops( PCRV_DEQUE& vpLoop) +{ + // verifico che le curve siano chiuse e ne determino l'area + typedef std::pair INDAREA ; // coppia indice, area + typedef std::vector INDAREAVECTOR ; // vettore di coppie indice, area + INDAREAVECTOR vArea ; + vArea.reserve( vpLoop.size()) ; + for ( int i = 0 ; i < int( vpLoop.size()) ; ++ i) { + double dArea ; + if ( ! vpLoop[i]->GetAreaXY( dArea)) + return nullptr ; + vArea.emplace_back( i, dArea) ; + } + // ordino in senso decrescente sull'area + sort( vArea.begin(), vArea.end(), + []( const INDAREA& a, const INDAREA&b) { return a.second > b.second ; }) ; + + // determino quanti sono i nuovi cicli esterni (area positiva) + int nLoopCount = int( vArea.size()) ; + int nExtCount = 0 ; + for ( int i = 0 ; i < nLoopCount ; ++ i) { + if ( vArea[i].second > 0) + ++ nExtCount ; + } + + // creo una nuova regione + PtrOwner pSfr( CreateBasicSurfFlatRegion()) ; + // ciclo sui loop esterni, all'indietro dal più piccolo al più grande + for ( int i = nExtCount - 1 ; i >= 0 ; -- i) { + // inserisco il nuovo esterno + int j = vArea[i].first ; + ICurve* pExtLoop = vpLoop[j] ; + double dExtArea = vArea[i].second ; + if ( pSfr->MyAddExtLoop( vpLoop[j])) { + vpLoop[j] = nullptr ; + vArea[i].first = - 1 ; + } + else + continue ; + // provo ad inserire i loop interni + for ( int k = nExtCount ; k < nLoopCount ; ++ k) { + // verifico non sia già stato inserito + if ( vArea[k].first < 0) + continue ; + // salto gli interni con area maggiore dell'esterno corrente + if ( fabs( vArea[k].second) > dExtArea) + continue ; + int l = vArea[k].first ; + // verifico che sia interno all'esterno corrente + CRVCVECTOR ccClass ; + IntersCurveCurve ccInt( *vpLoop[l], *pExtLoop) ; + if ( ccInt.GetCrossOrOverlapIntersCount() > 0 || + ! ccInt.GetCurveClassification( 0, ccClass) || + ccClass.empty() || ccClass[0].nClass != CRVC_IN) + continue ; + // lo inserisco + if ( pSfr->MyAddIntLoop( vpLoop[l])) { + vpLoop[l] = nullptr ; + vArea[k].first = - 1 ; + } + } + } + // se non valida, errore + if ( ! pSfr->IsValid()) + return nullptr ; + // verifico non siano rimasti loop inutilizzati + if ( ! MyTestAndDelete( vpLoop)) + return nullptr ; + // tutto bene, ritorno la superficie appena creata + return Release( pSfr) ; +} + +//---------------------------------------------------------------------------- +bool +SurfFlatRegion::MyTestAndDelete( PCRV_DEQUE& vpCrv) +{ + bool bOk = true ; + for ( auto& pCrv : vpCrv) { + if ( pCrv != nullptr) { + delete pCrv ; + pCrv = nullptr ; + bOk = false ; + } + } + return bOk ; +}