//---------------------------------------------------------------------------- // EgalTech 2015-2022 //---------------------------------------------------------------------------- // File : StmFromCurves.cpp Data : 08.12.22 Versione : 2.4l2 // Contenuto : Implementazione di funzioni per creazione di superfici Stm // a partire da curve, con diversi metodi. // // // Modifiche : 01.02.15 DS Creazione modulo. // 11.08.16 DS In GetSurfFlatRegionFromFatCurve sostituito Offset a SimpleOffset. // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "CurveLine.h" #include "CurveArc.h" #include "CurveComposite.h" #include "SurfFlatRegion.h" #include "AdjustLoops.h" #include "GeoConst.h" #include "Voronoi.h" #include "/EgtDev/Include/EGkPolyLine.h" #include "/EgtDev/Include/EGkBiArcs.h" #include "/EgtDev/Include/EGkOffsetCurve.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include using namespace std ; //------------------------------------------------------------------------------- ISurfFlatRegion* GetSurfFlatRegionRectangle( double dWidth, double dLen) { // le dimensioni devono essere significative if ( dWidth < EPS_SMALL || dLen < EPS_SMALL) return nullptr ; // creo il contorno PolyLine PL ; PL.AddUPoint( 0, ORIG) ; PL.AddUPoint( 1, Point3d( dWidth, 0, 0)) ; PL.AddUPoint( 2, Point3d( dWidth, dLen, 0)) ; PL.AddUPoint( 3, Point3d( 0, dLen, 0)) ; PL.AddUPoint( 4, ORIG) ; PtrOwner pCC( CreateBasicCurveComposite()) ; if ( IsNull( pCC) || ! pCC->FromPolyLine( PL)) return nullptr ; // creo il rettangolo PtrOwner pSfr( CreateBasicSurfFlatRegion()) ; if ( IsNull( pSfr) || ! pSfr->AddExtLoop( Release( pCC))) return nullptr ; else return Release( pSfr) ; } //------------------------------------------------------------------------------- ISurfFlatRegion* GetSurfFlatRegionStadium( double dWidth, double dLen) { // le dimensioni devono essere significative if ( dWidth < EPS_SMALL || dLen < EPS_SMALL) return nullptr ; // se dimensioni praticamente uguali, è un disco if ( abs( dWidth - dLen) < 10 * EPS_SMALL) return GetSurfFlatRegionDisk( ( dWidth + dLen) / 4) ; // creo il contorno PolyArc PA ; if ( dWidth > dLen) { double dRad = dLen / 2 ; PA.AddUPoint( 0, Point3d( dRad, 0, 0), 0) ; PA.AddUPoint( 1, Point3d( dWidth - dRad, 0, 0), 1) ; PA.AddUPoint( 2, Point3d( dWidth - dRad, dLen, 0), 0) ; PA.AddUPoint( 3, Point3d( dRad, dLen, 0), 1) ; PA.AddUPoint( 4, Point3d( dRad, 0, 0), 0) ; } else { double dRad = dWidth / 2 ; PA.AddUPoint( 0, Point3d( dWidth, dRad, 0), 0) ; PA.AddUPoint( 1, Point3d( dWidth, dLen - dRad, 0), 1) ; PA.AddUPoint( 2, Point3d( 0, dLen - dRad, 0), 0) ; PA.AddUPoint( 3, Point3d( 0, dRad, 0), 1) ; PA.AddUPoint( 4, Point3d( dWidth, dRad, 0), 0) ; } PtrOwner pCC( CreateBasicCurveComposite()) ; if ( IsNull( pCC) || ! pCC->FromPolyArc( PA)) return nullptr ; // creo il rettangolo PtrOwner pSfr( CreateBasicSurfFlatRegion()) ; if ( IsNull( pSfr) || ! pSfr->AddExtLoop( Release( pCC))) return nullptr ; else return Release( pSfr) ; } //------------------------------------------------------------------------------- ISurfFlatRegion* GetSurfFlatRegionDisk( double dRadius) { // le dimensioni devono essere significative if ( dRadius < EPS_SMALL) return nullptr ; // creo la circonferenza di riferimento PtrOwner pArc( CreateBasicCurveArc()) ; if ( IsNull( pArc)) return nullptr ; pArc->Set( ORIG, Z_AX, dRadius, X_AX, ANG_FULL, 0) ; // creo il disco PtrOwner pSfr( CreateBasicSurfFlatRegion()) ; if ( IsNull( pSfr) || ! pSfr->AddExtLoop( Release( pArc))) return nullptr ; else return Release( pSfr) ; } //------------------------------------------------------------------------------- ISurfFlatRegion* GetSurfFlatRegionFromFatCurve( ICurve* pCrv, double dRadius, bool bSquareEnds, bool bSquareMids, double dOffsLinTol, bool bMergeOnlySameProps) { // metodo di calcolo impostato da USE_VORONOI // mi impossesso della curva PtrOwner pCurve( pCrv) ; if ( IsNull( pCurve)) return nullptr ; // la inserisco in una curva composita Vector3d vtExtr ; pCrv->GetExtrusion( vtExtr) ; if ( vtExtr.IsSmall()) vtExtr = Z_AX ; // ----------------- CALCOLO STANDARD -------------------------------- if ( ! USE_VORONOI) { PtrOwner pCompo1 ; if ( ! pCompo1.Set( ConvertCurveToBasicComposite( Release( pCurve)))) return nullptr ; pCompo1->SetExtrusion( vtExtr) ; // se distanza tra gli estremi minore di due volte il raggio la chiudo, purchè curva abbastanza lunga Point3d ptStart, ptEnd, ptMid ; Vector3d vtStart, vtEnd ; pCompo1->GetStartPoint( ptStart) ; pCompo1->GetStartDir( vtStart) ; pCompo1->GetEndPoint( ptEnd) ; pCompo1->GetEndDir( vtEnd) ; pCompo1->GetMidPoint( ptMid) ; if ( AreSamePointEpsilon( ptStart, ptEnd, 2 * dRadius) && Dist( ptStart, ptMid) > 2 * dRadius && Dist( ptEnd, ptMid) > 2 * dRadius) { if ( AreSamePointEpsilon( ptStart, ptEnd, max( 0.1 * dRadius, 10 * EPS_SMALL))) { Point3d ptNew = Media( ptStart, ptEnd) ; pCompo1->ModifyStart( ptNew) ; pCompo1->ModifyEnd( ptNew) ; } else { // piano della curva Frame3d frLoc ; if ( ! AreSameVectorApprox( vtExtr, Z_AX)) frLoc.Set( ptStart, vtExtr) ; // costruisco il biarco nel piano della curva ptStart.ToLoc( frLoc) ; ptEnd.ToLoc( frLoc) ; Vector3d vtELoc( vtEnd) ; vtELoc.ToLoc( frLoc) ; Vector3d vtSLoc( vtStart) ; vtSLoc.ToLoc( frLoc) ; double dAngEnd ; vtELoc.ToSpherical( nullptr, nullptr, &dAngEnd) ; double dAngStart ; vtSLoc.ToSpherical( nullptr, nullptr, &dAngStart) ; PtrOwner pClose( GetBiArc( ptEnd, dAngEnd, ptStart, dAngStart, 0.5)) ; // aggiungo il biarco if ( ! IsNull( pClose)) { // porto il biarco in globale pClose->ToGlob( frLoc) ; pCompo1->AddCurve( Release( pClose)) ; } else pCompo1->Close() ; } } // tipo di offset int nOffsType = ( bSquareMids ? ICurve::OFF_EXTEND : ICurve::OFF_FILLET) ; // se curva chiusa if ( pCompo1->IsClosed()) { // fondo le curve allineate pCompo1->MergeCurves( LIN_TOL_FINE, ANG_TOL_STD_DEG) ; // ne faccio una copia e la inverto PtrOwner pCompo2( pCompo1->Clone()) ; if ( IsNull( pCompo2) || ! pCompo2->Invert()) return nullptr ; // per creare la regione SurfFlatRegionByContours SfrCntr( false, false) ; // offset della prima curva a destra del raggio OffsetCurve OffsCrv1( dOffsLinTol) ; if ( ! OffsCrv1.Make( pCompo1, dRadius, nOffsType)) return nullptr ; ICurve* pOffs1 = OffsCrv1.GetLongerCurve() ; while ( pOffs1 != nullptr) { SfrCntr.AddCurve( pOffs1) ; pOffs1 = OffsCrv1.GetLongerCurve() ; } // offset della seconda curva a destra del raggio (è invertita rispetto alla precedente) OffsetCurve OffsCrv2( dOffsLinTol) ; if ( ! OffsCrv2.Make( pCompo2, dRadius, nOffsType)) return nullptr ; ICurve* pOffs2 = OffsCrv2.GetLongerCurve() ; while ( pOffs2 != nullptr) { SfrCntr.AddCurve( pOffs2) ; pOffs2 = OffsCrv2.GetLongerCurve() ; } // creo la regione return SfrCntr.GetSurf() ; } // altrimenti else { // se richiesti estremi squadrati, la allungo del raggio alle due estremità if ( bSquareEnds) { pCompo1->ExtendStartByLen( dRadius) ; pCompo1->ExtendEndByLen( dRadius) ; } // fondo le curve allineate pCompo1->MergeCurves( LIN_TOL_FINE, ANG_TOL_STD_DEG) ; // ne faccio una copia e la inverto PtrOwner pCompo2( pCompo1->Clone()) ; if ( IsNull( pCompo2) || ! pCompo2->Invert()) return nullptr ; // creo la regione SurfFlatRegionByContours SfrCntr( false, false) ; // offset della prima curva a destra del raggio OffsetCurve OffsCrv1( dOffsLinTol) ; if ( ! OffsCrv1.Make( pCompo1, dRadius, nOffsType)) return nullptr ; ICurve* pOffs1 = OffsCrv1.GetLongerCurve() ; if ( pOffs1 == nullptr) return nullptr ; pCompo1->Clear() ; while ( pOffs1 != nullptr) { if ( pOffs1->IsClosed()) SfrCntr.AddCurve( pOffs1) ; else pCompo1->AddCurve( pOffs1) ; pOffs1 = OffsCrv1.GetLongerCurve() ; } // offset della seconda curva a destra del raggio OffsetCurve OffsCrv2( dOffsLinTol) ; if ( ! OffsCrv2.Make( pCompo2, dRadius, nOffsType)) return nullptr ; ICurve* pOffs2 = OffsCrv2.GetLongerCurve() ; if ( pOffs2 == nullptr) return nullptr ; pCompo2->Clear() ; while ( pOffs2 != nullptr) { if ( pOffs2->IsClosed()) SfrCntr.AddCurve( pOffs2) ; else pCompo2->AddCurve( pOffs2) ; pOffs2 = OffsCrv2.GetLongerCurve() ; } // se estremi squadrati if ( bSquareEnds) { // aggiungo alla prima curva una linea che la unisca alla seconda PtrOwner pLine( CreateBasicCurveLine()) ; Point3d ptEnd1, ptStart2 ; if ( IsNull( pLine) || ! pCompo1->GetEndPoint( ptEnd1) || ! pCompo2->GetStartPoint( ptStart2) || ! pLine->Set( ptEnd1, ptStart2) || ! pCompo1->AddCurve( Release( pLine))) return nullptr ; // unisco le due curve composite e le chiudo if ( ! pCompo1->AddCurve( Release( pCompo2)) || ! pCompo1->Close()) return nullptr ; } // altrimenti estremi arrotondati else { // aggiungo alla prima curva un arco che la unisca alla seconda PtrOwner pArc1( CreateBasicCurveArc()) ; Point3d ptEnd1, ptStart2 ; Vector3d vtEnd1, vtStart2 ; if ( IsNull( pArc1) || ! pCompo1->GetEndPoint( ptEnd1) || ! pCompo1->GetEndDir( vtEnd1) || ! pCompo2->GetStartPoint( ptStart2) || ! pCompo2->GetStartDir( vtStart2)) return nullptr ; // verifico se arco tangente alla prima o alla seconda curva if ( AreSameVectorApprox( vtEnd1, vtEnd)) { if ( ! pArc1->Set2PVN( ptEnd1, ptStart2, vtEnd1, vtExtr) || ! pCompo1->AddCurve( Release( pArc1))) return nullptr ; } else { if ( ! pArc1->Set2PVN( ptStart2, ptEnd1, -vtStart2, vtExtr) || ! pArc1->Invert() || ! pCompo1->AddCurve( Release( pArc1))) return nullptr ; } // aggiungo alla seconda curva un arco che la unisca alla prima PtrOwner pArc2( CreateBasicCurveArc()) ; Point3d ptEnd2, ptStart1 ; Vector3d vtEnd2, vtStart1 ; if ( IsNull( pArc2) || ! pCompo2->GetEndPoint( ptEnd2) || ! pCompo2->GetEndDir( vtEnd2) || ! pCompo1->GetStartPoint( ptStart1) || ! pCompo1->GetStartDir( vtStart1)) return nullptr ; // verifico se arco tangente alla seconda o alla prima curva if ( AreOppositeVectorApprox( vtEnd2, vtStart)) { if ( ! pArc2->Set2PVN( ptEnd2, ptStart1, vtEnd2, vtExtr) || ! pCompo2->AddCurve( Release( pArc2))) return nullptr ; } else { if ( ! pArc2->Set2PVN( ptStart1, ptEnd2, -vtStart1, vtExtr) || ! pArc2->Invert() || ! pCompo2->AddCurve( Release( pArc2))) return nullptr ; } // unisco le due curve composite if ( ! pCompo1->AddCurve( Release( pCompo2))) return nullptr ; } SfrCntr.AddCurve( Release( pCompo1)) ; return SfrCntr.GetSurf() ; } } // ---------------------- CALCOLO CON VORONOI ------------------------------------ else { // calcolo la fat curve con Voronoi ICURVEPOVECTOR vFatCurves ; if ( ! CalcCurveFatCurve( *pCurve, vFatCurves, dRadius, bSquareEnds, bSquareMids, bMergeOnlySameProps)) return nullptr ; // costruisco la superficie a partire dalle curve SurfFlatRegionByContours SfrCntr( false, false) ; for ( int i = 0 ; i < ( int)vFatCurves.size() ; i++) SfrCntr.AddCurve( Release( vFatCurves[i])) ; return SfrCntr.GetSurf() ; } } //---------------------------------------------------------------------------- ISurfFlatRegion* GetSurfFlatRegionFromTriangle( const Triangle3d& Tria) { // Creo la regione. PtrOwner pSfr( CreateBasicSurfFlatRegion()) ; if ( IsNull( pSfr)) return nullptr ; // Creo curva composita. PtrOwner pLoop( CreateBasicCurveComposite()) ; if ( IsNull( pLoop)) return nullptr ; if ( ! pLoop->AddPoint( Tria.GetP( 0)) || ! pLoop->AddLine( Tria.GetP( 1)) || ! pLoop->AddLine( Tria.GetP( 2)) || ! pLoop->Close()) return nullptr ; pSfr->AddExtLoop( Release( pLoop)) ; return Release( pSfr) ; } //---------------------------------------------------------------------------- ISurfFlatRegion* GetSurfFlatRegionFromPolyLine( const PolyLine& ContourPolyLine) { // Creo curva composita. PtrOwner pLoop( CreateBasicCurveComposite()) ; if ( IsNull( pLoop) || ! pLoop->FromPolyLine( ContourPolyLine)) return nullptr ; // Creo la regione. PtrOwner pSfr( CreateBasicSurfFlatRegion()) ; if ( IsNull( pSfr) || ! pSfr->AddExtLoop( Release( pLoop))) return nullptr ; return Release( pSfr) ; } //---------------------------------------------------------------------------- ISurfFlatRegion* GetSurfFlatRegionFromPolyLineVector( const POLYLINEVECTOR& vContoursPolyLineVec) { // Creo la regione. PtrOwner pSfr( CreateBasicSurfFlatRegion()) ; if ( IsNull( pSfr)) return nullptr ; // Ciclo sulle PolyLine. for ( int nL = 0 ; nL < int( vContoursPolyLineVec.size()) ; ++ nL) { // Creo curva composita. PtrOwner pLoop( CreateBasicCurveComposite()) ; if ( IsNull( pLoop) || ! pLoop->FromPolyLine( vContoursPolyLineVec[nL])) return nullptr ; // Loop esterno if ( nL == 0) { if ( ! pSfr->AddExtLoop( Release( pLoop))) return nullptr ; } // Loop interno else { if ( ! pSfr->AddIntLoop( Release( pLoop))) return nullptr ; } } return Release( pSfr) ; } //------------------------------------------------------------------------------- // Classe SurfFlatRegionByContours //------------------------------------------------------------------------------- SurfFlatRegionByContours::~SurfFlatRegionByContours(void) { // cancello eventuali curve rimaste for ( auto& pCrv : m_vpCrv) { if ( pCrv != nullptr) delete pCrv ; pCrv = nullptr ; } m_vpCrv.clear() ; } //------------------------------------------------------------------------------- bool SurfFlatRegionByContours::AddCurve( ICurve* pCrv) { // acquisisco la curva PtrOwner pMyCrv( pCrv) ; if ( IsNull( pMyCrv) || ! pMyCrv->IsValid()) return false ; // verifico sia chiusa if ( ! pMyCrv->IsClosed()) return false ; // verifico sia piana e imposto estrusione come normale al piano double dArea ; Plane3d plPlane ; if ( ! pMyCrv->GetArea( plPlane, dArea)) return false ; pMyCrv->SetExtrusion( plPlane.GetVersN()) ; pMyCrv->SetThickness( 0) ; // rimuovo eventuali sovrapposizioni (calcolate nel suo piano) ICURVEPLIST CrvLst ; if ( ! AdjustLoops( Release( pMyCrv), CrvLst, true)) return false ; // la/le inserisco nel vettore delle curve for ( auto& pSingCrv : CrvLst) m_vpCrv.push_back( pSingCrv) ; return true ; } //------------------------------------------------------------------------------- bool SurfFlatRegionByContours::Prepare( void) { // calcolo piano medio e area delle curve m_vArea.reserve( m_vpCrv.size()) ; Vector3d vtN0 ; for ( int i = 0 ; i < int( m_vpCrv.size()) ; ++ i) { // calcolo piano medio e area Plane3d plPlane ; double dArea ; if ( ! m_vpCrv[i]->GetArea( plPlane, dArea)) return false ; // imposto la normale del primo contorno come riferimento if ( i == 0) vtN0 = plPlane.GetVersN() ; // verifico che le normali siano molto vicine if ( ! AreSameOrOppositeVectorApprox( plPlane.GetVersN(), vtN0)) return false ; // assegno il segno all'area secondo il verso della normale if ( ( plPlane.GetVersN() * vtN0) > 0) m_vArea.emplace_back( i, dArea) ; else m_vArea.emplace_back( i, - dArea) ; } // ordino in senso decrescente sull'area sort( m_vArea.begin(), m_vArea.end(), []( const INDAREA& a, const INDAREA& b) { return ( abs( a.second) > abs( b.second)) ; }) ; return true ; } //------------------------------------------------------------------------------- ISurfFlatRegion* SurfFlatRegionByContours::GetSurf( void) { // se è la prima superficie, devo preparare if ( m_bFirst) { if ( ! Prepare()) return nullptr ; m_bFirst = false ; } // altrimenti, se ammessa una sola superficie errore else if ( ! m_bAllowedMore) { return nullptr ; } // creo la superficie PtrOwner pSfr( CreateBasicSurfFlatRegion()) ; if ( IsNull( pSfr)) return nullptr ; // aggiungo le diverse curve bool bExtLoop = false ; bool bFirstCrv ; do { bFirstCrv = true ; for ( int i = 0 ; i < int( m_vArea.size()) ; ++ i) { // recupero indice di percorso e verifico sia valido int j = m_vArea[i].first ; if ( j < 0) continue ; // la prima deve essere il loop esterno if ( bFirstCrv) { // ne faccio una copia PtrOwner pCrv( m_vpCrv[j]->Clone()) ; if ( IsNull( pCrv)) { m_vArea[i].first = - 1 ; continue ; } // provo a inserirla if ( pSfr->AddExtLoop( Release( pCrv))) { bExtLoop = true ; bFirstCrv = false ; delete m_vpCrv[j] ; m_vpCrv[j] = nullptr ; m_vArea[i].first = - 1 ; } } // gli altri sono loop interni else { // ne faccio una copia PtrOwner pCrv( m_vpCrv[j]->Clone()) ; if ( IsNull( pCrv)) { m_vArea[i].first = - 1 ; continue ; } // provo a inserirla if ( pSfr->AddIntLoop( Release( pCrv))) { delete m_vpCrv[j] ; m_vpCrv[j] = nullptr ; m_vArea[i].first = - 1 ; } } } } while ( m_bAllowedMultiChunk && ! bFirstCrv) ; // se non valida, errore if ( ! bExtLoop || ! pSfr->IsValid()) return nullptr ; // restituisco la superficie return Release( pSfr) ; } //------------------------------------------------------------------------------- bool SurfFlatRegionByContours::AllCurvesUsed( void) { // verifico se sono rimaste delle curve for ( auto& pCrv : m_vpCrv) { if ( pCrv != nullptr) return false ; } return true ; } //------------------------------------------------------------------------------- bool SurfFlatRegionByContours::GetUnusedCurveTempProps( INTVECTOR& vId) { vId.clear() ; // verifico se sono rimaste delle curve for ( auto& pCrv : m_vpCrv) { if ( pCrv != nullptr) vId.push_back( pCrv->GetTempProp()) ; } return ( ! vId.empty()) ; } //------------------------------------------------------------------------------- bool CalcRegionPolyLines( const POLYLINEVECTOR& vPL, Vector3d& vtN, INTMATRIX& vnPLIndMat, BOOLVECTOR& vbInvert) { // vnPLIndMat : ogni riga corrisponde ad un chunk, in posizione 0 c'è il loop esterno e nelle successive i loop interni // vbInvert : riferito al vettore delle polyline, riporta true se la polyline è stata invertita // ricavo versore normale Plane3d plPlane ; double dArea ; if ( ! vPL[0].IsClosedAndFlat( plPlane, dArea, 50 * EPS_SMALL)) return false ; vtN = plPlane.GetVersN() ; typedef std::pair INDAREA ; std::vector m_vArea ; // calcolo piano medio e area delle curve m_vArea.reserve( vPL.size()) ; VCT3DVECTOR vvtN ; for ( int i = 0 ; i < int( vPL.size()) ; ++ i) { // calcolo piano medio e area Plane3d plPlane ; double dArea ; if ( ! vPL[i].IsClosedAndFlat( plPlane, dArea)) return false ; // verifico che le normali siano molto vicine if ( ! AreSameOrOppositeVectorApprox( plPlane.GetVersN(), vtN)) return false ; // salvo la normale vvtN.push_back( plPlane.GetVersN()) ; // assegno il segno all'area secondo il verso della normale if ( ( plPlane.GetVersN() * vtN) > 0) m_vArea.emplace_back( i, dArea) ; else m_vArea.emplace_back( i, - dArea) ; } // ordino in senso decrescente sull'area sort( m_vArea.begin(), m_vArea.end(), []( const INDAREA& a, const INDAREA& b) { return ( abs( a.second) > abs( b.second)) ; }) ; // dalle PolyLine passo alle curve nel piano XY ( prendo la prima come riferimento, trascuro le Z delle successive) Frame3d frRef ; frRef.Set( ORIG, vtN) ; if ( ! frRef.IsValid()) return false ; ICRVCOMPOPOVECTOR vCrvCompo( int( vPL.size())) ; for ( int i = 0 ; i < int( vPL.size()) ; ++ i) { vCrvCompo[i].Set( CreateCurveComposite()) ; vCrvCompo[i]->FromPolyLine( vPL[i]) ; vCrvCompo[i]->ToLoc( frRef) ; } // restituisco la normale del loop più grande bool bInvertAll = vvtN[m_vArea[0].first] * vtN < 0 ; vtN = vvtN[m_vArea[0].first] ; //// vettore di indici per ordinare le PolyLine INTVECTOR vPL_IndOrder ; vPL_IndOrder.resize( int( vPL.size())) ; for ( int i = 0 ; i < int( m_vArea.size()) ; ++ i) vPL_IndOrder[i] = m_vArea[i].first ; // aggiungo le diverse curve bool bFirstCrv ; Plane3d plExtLoop ; double dAreaExtLoop = 0. ; vbInvert.resize( vPL.size()) ; fill( vbInvert.begin(), vbInvert.end(), false) ; do { bFirstCrv = true ; for ( int i = 0 ; i < int( m_vArea.size()) ; ++ i) { // recupero indice di percorso e verifico sia valido int j = m_vArea[i].first ; if ( j < 0) continue ; // lo inserisco come esterno... if ( bFirstCrv) { vnPLIndMat.push_back({ j}) ; m_vArea[i].first = -1 ; dAreaExtLoop = m_vArea[i].second ; // inverto se necessario if ( m_vArea[i].second < EPS_SMALL) { vCrvCompo[j]->Invert() ; dAreaExtLoop *= -1 ; vbInvert[j] = true ; } bFirstCrv = false ; } // ... altrimenti verifico se il loop è interno o no else { // il loop è interno se è sia interno al loop esterno della riga di vnPLIndMat e allo stesso tempo // esterno a tutti i loop già inseriti nella riga attuale. // verifica rispetto loop esterno IntersCurveCurve ccInt( *vCrvCompo[vnPLIndMat.back().front()], *vCrvCompo[j]) ; CRVCVECTOR ccClass ; if ( ccInt.GetCrossOrOverlapIntersCount() > 0 || ! ccInt.GetCurveClassification( 1, EPS_SMALL, ccClass) || ccClass.empty() || ccClass[0].nClass != CRVC_IN) continue ; // verifica rispetto ai loop interni bool bOk = true ; for ( int k = 1 ; k < int( vnPLIndMat.back().size()) ; ++ k) { IntersCurveCurve ccInt2( *vCrvCompo[vnPLIndMat.back()[k]], *vCrvCompo[j]) ; CRVCVECTOR ccClass2 ; if ( ccInt2.GetCrossOrOverlapIntersCount() > 0 || ! ccInt2.GetCurveClassification( 1, EPS_SMALL, ccClass2) || ccClass2.empty() || ccClass2[0].nClass != CRVC_IN) { bOk = false ; break ; } } if ( bOk) { // inserisco nella matrice vnPLIndMat.back().push_back( j) ; m_vArea[i].first = -1 ; // inverto se necessario if ( m_vArea[i].second * dAreaExtLoop > 0.) { vCrvCompo[j]->Invert() ; vbInvert[j] = true ; } } } } } while ( ! bFirstCrv) ; if ( bInvertAll) { for ( int i = 0 ; i < int( vPL.size()) ; ++i) vbInvert[i] = ! vbInvert[i] ; } return true ; }