diff --git a/CAvToolSurfTm.cpp b/CAvToolSurfTm.cpp index 878ea15..baea710 100644 --- a/CAvToolSurfTm.cpp +++ b/CAvToolSurfTm.cpp @@ -104,6 +104,9 @@ CAvToolSurfTm::TestPosition( const Point3d& ptT, const Vector3d& vtDir, const Ve // Se utensile non definito, errore if ( m_Tool.GetType() == Tool::UNDEF) return false ; + // Se direzioni non definite, errore + if ( vtDir.IsSmall() || vtMove.IsSmall()) + return false ; // Imposto il riferimento di movimento if ( ! AreSameOrOppositeVectorApprox( vtDir, vtMove)) m_frMove.Set( ORIG, vtMove, vtDir) ; @@ -122,6 +125,9 @@ CAvToolSurfTm::TestPath( PNTULIST& lPntM, const Vector3d& vtDir, const Vector3d& // Se utensile non definito, errore if ( m_Tool.GetType() == Tool::UNDEF) return false ; + // Se direzioni non definite, errore + if ( vtDir.IsSmall() || vtMove.IsSmall()) + return false ; // Se lista vuota, non devo fare alcunché if ( lPntM.empty()) return true ; diff --git a/CurveAux.cpp b/CurveAux.cpp index 4c6d624..2f5d09b 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -535,6 +535,8 @@ NurbsCurveCanonicalize( CNurbsData& cnData) } } if ( ! bRepetead){ + // salvo il vettore dei nodi in caso mi accorga di avere tra le mani una curva unclamped + DBLVECTOR vU = cnData.vU ; // se il primo e l'ultimo punto non coincidono allora aggiungo il primo punto in fondo al vettore dei punti di controllo if ( ! AreSamePointApprox( cnData.vCP[0], cnData.vCP.back()) ) { cnData.vCP.push_back( cnData.vCP[0]) ; @@ -545,7 +547,36 @@ NurbsCurveCanonicalize( CNurbsData& cnData) if ( int( cnData.vU.size()) != int(cnData.vCP.size()) + cnData.nDeg - 1) { // devo poi anche togliere i nodi di troppo // presuppongo che la convenzione sia che i nodi di troppo sono alla fine del vettore dei nodi cnData.vU = DBLVECTOR( cnData.vU.begin(), cnData.vU.end() - cnData.nDeg) ; - // controlloeventualmente anche i nodi extra + // controllo eventualmente anche i nodi extra + // se ne ho due in più ne tolgo uno in cima e uno in fondo + if ( cnData.vU.size() == int( cnData.vCP.size()) + cnData.nDeg + 1 ) // significa che ci sono due nodi extra, uno all'inizio e uno alla fine, da togliere + cnData.vU = vector( cnData.vU.begin() + 1, cnData.vU.end() - 1) ; + // se ne ho solo uno in più lo tolgo in cima + else if ( cnData.vU.size() == int( cnData.vCP.size()) + cnData.nDeg) + cnData.vU = vector( cnData.vU.begin() + 1, cnData.vU.end()) ; + } + // controllo se il vettore dei nodi ha la giusta molteplicità all'inizio e alla fine, sennò ha comunque bisogno di essere resa non periodica + double dU0 = cnData.vU[0] ; + double dULast = cnData.vU.back() ; + bool bSame = true ; + for ( int i = 1 ; i < cnData.nDeg ; ++i ) { + bSame = bSame && abs(cnData.vU[i] - dU0) < EPS_SMALL ; + bSame = bSame && abs(cnData.vU.end()[-( i+ 1)] - dULast) < EPS_SMALL ; + } + if ( bSame) { + cnData.bPeriodic = false ; + return true ; + } + else { + // aggiungo i punti ripetuti ( il primo l'ho già aggiunto) + for ( int i = 1 ; i < cnData.nDeg ; ++i ) { + cnData.vCP.push_back( cnData.vCP[i]) ; + if ( cnData.bRat) + cnData.vW.push_back( cnData.vW[i]) ; + } + // recupero il vettore dei nodi + cnData.vU = vU ; + // verifico se ho nodi extra // se ne ho due in più ne tolgo uno in cima e uno in fondo if ( cnData.vU.size() == int( cnData.vCP.size()) + cnData.nDeg + 1 ) // significa che ci sono due nodi extra, uno all'inizio e uno alla fine, da togliere cnData.vU = vector( cnData.vU.begin() + 1, cnData.vU.end() - 1) ; @@ -553,8 +584,6 @@ NurbsCurveCanonicalize( CNurbsData& cnData) else if ( cnData.vU.size() == int( cnData.vCP.size()) + cnData.nDeg) cnData.vU = vector( cnData.vU.begin() + 1, cnData.vU.end()) ; } - cnData.bPeriodic = false ; - return true ; } } @@ -568,7 +597,7 @@ NurbsCurveCanonicalize( CNurbsData& cnData) } } if ( bCollapsed) - return true ; + return false ; // va trasformata in non-periodica (clamped) // bisogna aumentare la molteplicità dei nodi u_p-1 e u_(m-p+1) fino ad arrivare al grado della nurbs diff --git a/SurfAux.cpp b/SurfAux.cpp index 50e1be2..4e9e612 100644 --- a/SurfAux.cpp +++ b/SurfAux.cpp @@ -62,11 +62,12 @@ NurbsSurfaceCanonicalize( SNurbsSurfData& snData) nuCurve.vCP = vPtCtrl ; nuCurve.vW = vWeCtrl ; // i punti dell' oggetto nuCurve devono essere in forma non omogenea - NurbsCurveCanonicalize( nuCurve) ; - for ( int i = 0 ; i < snData.nCPU ; ++i) { - snData.mCP[i][j] = nuCurve.vCP[i] ; + if ( NurbsCurveCanonicalize( nuCurve)) { // se NurbsCurveCanonicalize ha restituito false (la curva potrebbe esserre un punto di polo) allora non modifico i punti e il vettore dei nodi della superficie + for ( int i = 0 ; i < snData.nCPU ; ++i) { + snData.mCP[i][j] = nuCurve.vCP[i] ; + } + snData.vU = nuCurve.vU ; } - snData.vU = nuCurve.vU ; } snData.bPeriodicU = false ; } @@ -99,11 +100,12 @@ NurbsSurfaceCanonicalize( SNurbsSurfData& snData) nuCurve.vCP = vPtCtrl ; nuCurve.vW = vWeCtrl ; // i punti dell' oggetto nuCurve devono essere in forma non omogenea - NurbsCurveCanonicalize( nuCurve) ; - for ( int j = 0 ; j < snData.nCPV ; ++j ) { - snData.mCP[i][j] = nuCurve.vCP[j] ; + if ( NurbsCurveCanonicalize( nuCurve)) { // se NurbsCurveCanonicalize ha restituito false (la curva potrebbe esserre un punto di polo) allora non modifico i punti e il vettore dei nodi della superficie + for ( int j = 0 ; j < snData.nCPV ; ++j ) { + snData.mCP[i][j] = nuCurve.vCP[j] ; + } + snData.vV = nuCurve.vU ; } - snData.vV = nuCurve.vU ; } snData.bPeriodicV = false ; } @@ -618,6 +620,7 @@ MakeUniform( ISurfFlatRegion*& pSfr, bool& bRescaled, const DBLVECTOR& vU0, cons if ( pRescaledSfr->IsValid()) { if ( bRetry) pRescaledSfr->Offset( -10 * EPS_SMALL, ICurve::OFF_CHAMFER) ; //contro OFFSET + delete pSfr ; pSfr = Release( pRescaledSfr) ; } } @@ -629,6 +632,7 @@ MakeUniform( ISurfFlatRegion*& pSfr, bool& bRescaled, const DBLVECTOR& vU0, cons if ( ! IsNull( pRescaledSfr) && pRescaledSfr->IsValid()) { if ( bRetry) pRescaledSfr->Offset( -10 * EPS_SMALL, ICurve::OFF_CHAMFER) ; // contro OFFSET + delete pSfr ; pSfr = Release( pRescaledSfr) ; } diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 87568ca..ad0991d 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -157,6 +157,7 @@ SurfBezier::SetTrimRegion( ISurfFlatRegion& sfrTrimReg, bool bIntersectOrSubtrac pSfrTrim->Offset( 10* EPS_SMALL, ICurve::OFF_EXTEND) ; if ( ! pSfrTrim->Intersect( sfrTrimReg) || ! pSfrTrim->IsValid()) return false ; + pSfrTrim->Offset( -10* EPS_SMALL, ICurve::OFF_EXTEND) ; } } // bIntersectOrSubtract == false per ottenere lo spazio parametrico trimmato devo fare la SOTTRAZIONE tra il rettangolo totale e l'area passata @@ -166,6 +167,7 @@ SurfBezier::SetTrimRegion( ISurfFlatRegion& sfrTrimReg, bool bIntersectOrSubtrac pSfrTrim->Offset( 10* EPS_SMALL, ICurve::OFF_EXTEND) ; if ( ! pSfrTrim->Subtract( sfrTrimReg) || ! pSfrTrim->IsValid()) return false ; + pSfrTrim->Offset( -10* EPS_SMALL, ICurve::OFF_EXTEND) ; } } ResetAuxSurf() ; @@ -3112,7 +3114,7 @@ SurfBezier::GetLoops( ICRVCOMPOPOVECTOR& vCC, bool bLineOrBezier, int nEdge) con ICurveComposite* SurfBezier::GetSingleEdge3D( bool bLineOrBezier, int nEdge) const { - if ( m_mCCEdge.size() == 0) + if ( m_mCCEdge.size() == 0 && bLineOrBezier) GetAuxSurf() ; // questa funzione dà per scontato che la superficie NON sia trimmata if ( nEdge < 0 || nEdge > 3 || m_bTrimmed) @@ -3213,10 +3215,10 @@ bool SurfBezier::IsPlanar( void) const { // costruisco il contorno della superficie unendo gli edge e chiedo se la polyline è piana. - PtrOwner pCCEdge( GetSingleEdge3D( true, 0)) ; - pCCEdge->AddCurve( GetSingleEdge3D( true, 1)) ; - pCCEdge->AddCurve( GetSingleEdge3D( true, 2)) ; - pCCEdge->AddCurve( GetSingleEdge3D( true, 3)) ; + PtrOwner pCCEdge( GetSingleEdge3D( false, 0)) ; + pCCEdge->AddCurve( GetSingleEdge3D( false, 1)) ; + pCCEdge->AddCurve( GetSingleEdge3D( false, 2)) ; + pCCEdge->AddCurve( GetSingleEdge3D( false, 3)) ; PolyLine plApprox ; pCCEdge->ApproxWithLines( 0.01, 15, 0, plApprox) ; Plane3d plPlane ; diff --git a/SurfTriMeshBooleans.cpp b/SurfTriMeshBooleans.cpp index a1310ba..d4e027a 100644 --- a/SurfTriMeshBooleans.cpp +++ b/SurfTriMeshBooleans.cpp @@ -76,10 +76,9 @@ SurfTriMesh::DecomposeLoop( CHAINVECTOR& cvOpenChain, INTVECTOR& vnDegVec, PNTMA ( nLastOpenLoopPoint == 0 && ( Loop1.size() == 2 || Loop2.size() == 2))) continue ; // la catena aperta non è interna al loop chiuso attuale - // il loop 1 segue sempre la direzione della catena, il loop 2 ha dentro la catena invertita - // Ho sempre che il loop 1 è sempre interno ( la direzione della catena è determinata - // dalla normale dei triangoli che la formano; avendo chimatao la chian senza ammettere inversioni, sono - // curve tutte concordi ) e il loop 2 che è esterno + // il loop 2 segue sempre la direzione della catena, il loop 1 ha dentro la catena invertita + // ( la direzione della catena è determinata dalla normale dei triangoli che la formano; + // avendo chiamato la chain senza ammettere inversioni, sono curve tutte concordi ) bLoopSplitted = true ; // ricostrusico i due loop mediante concatenazione Chain cvCounterChain ; @@ -584,6 +583,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT POLYLINEVECTOR vplPolyVec ; vplPolyVec.resize( cvBoundClosedLoopVec.size()) ; for ( int nLoop = 0 ; nLoop < int( vplPolyVec.size()) ; ++ nLoop) { + for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) ; ++ nLine) vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][nLine]) ; @@ -591,7 +591,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT // Assegno ai loop trovati i rispettivi interni // Assumo che i loop interni a uno dei loop creati fino ad'ora siano tutti sullo stesso livello. - // Il caso generale si risolve con una struttura ad albero in cui il nodi corrispondente a un + // Il caso generale si risolve con una struttura ad albero in cui il nodo corrispondente a un // loop è figlio del nodo corrispondente al loop che lo contiene. INTVECTOR vInnerLoop ; for ( int nCLI = 0 ; nCLI < int( cvClosedChain.size()) ; ++ nCLI) { @@ -742,6 +742,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT // se ho più loop, essi descrivono un poligono di n-lati POLYLINEVECTOR vPolygons ; vPolygons.emplace_back( vplPolyVec[nLoop]) ; + for ( int nL = 0 ; nL < int( vInnerLoop.size()) ; ++ nL) { // per ognuno di essi, ricavo la PolyLine dai punti PolyLine CurLoop ; @@ -955,11 +956,22 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT vPolygons.erase( vPolygons.begin() + i) ; else ++ i ; + + } + + bool bCordirectedNormals_intLoop = bCodirectedNormals ; + if ( ! vPolygons.empty()) { + Polygon3d pgPol ; + pgPol.FromPolyLine( vPolygons[0]) ; + // controllo direzioni delle normali + bCordirectedNormals_intLoop = trTria.GetN() * pgPol.GetVersN() > 0. ; + if ( ! bCordirectedNormals_intLoop) + vPolygons[0].Invert() ; } if ( Triangulate().MakeAdvanced( vPolygons, vPt, vTr)) { // Inserisco i nuovi triangoli - for (int n = 0 ; n < int( vTr.size()) - 2 ; n += 3) { + for ( int n = 0 ; n < int( vTr.size()) - 2 ; n += 3) { int nNewTriaVertId[3] = { vTr[n], vTr[n + 1], vTr[n + 2]} ; int nNewId[3] = { Surf.AddVertex( vPt[nNewTriaVertId[0]]), Surf.AddVertex( vPt[nNewTriaVertId[1]]), @@ -969,7 +981,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT Surf.m_vTria[nNewTriaNum].nETempFlag[0] = 0 ; Surf.m_vTria[nNewTriaNum].nETempFlag[1] = 0 ; Surf.m_vTria[nNewTriaNum].nETempFlag[2] = 0 ; - if ( bCodirectedNormals) + if ( bCordirectedNormals_intLoop) Surf.m_vTria[nNewTriaNum].nTempPart = 1 ; else Surf.m_vTria[nNewTriaNum].nTempPart = -1 ; @@ -1767,6 +1779,7 @@ SurfTriMesh::Subtract( const ISurfTriMesh& Other) SurfB.Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ; IntersectTriMeshTriangle( SurfB) ; + IdentifyParts() ; SurfB.IdentifyParts() ; diff --git a/Tree.cpp b/Tree.cpp index f7f4224..20e7574 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -20,6 +20,7 @@ #include "CurveComposite.h" #include "SurfFlatRegion.h" #include "IntersLineLine.h" +#include "AdjustLoops.h" #include "/EgtDev/Include/EGkPolyLine.h" #include "/EgtDev/Include/EGkDistPointCurve.h" #include "/EgtDev/Include/EGkCurve.h" @@ -64,36 +65,144 @@ Tree::Tree( const Point3d ptBl, const Point3d ptTr) //---------------------------------------------------------------------------- bool -Tree::LimitLoop( PolyLine& pl, POLYLINEVECTOR& vPl) const +Tree::LimitLoop( PolyLine& pl, POLYLINEVECTOR& vPl, BOOLVECTOR& vbOrientation) const { - // creo la flat region di trim, quella del parametrico e li interseco - PtrOwner pSfrTrim( GetSurfFlatRegionFromPolyLine( pl)) ; - bool bInverted = false ; - if ( ! pSfrTrim->GetNormVersor().IsZplus()) { - pSfrTrim->Invert() ; - bInverted = true ; - } - PtrOwner pParamTrim( GetSurfFlatRegionRectangle( SBZ_TREG_COEFF * m_nSpanU, SBZ_TREG_COEFF * m_nSpanV)) ; - if ( ! pParamTrim->Intersect( *pSfrTrim) || ! pParamTrim->IsValid()) { - pParamTrim->Offset( 10 * EPS_SMALL, ICurve::OFF_EXTEND) ; - if ( ! pParamTrim->Intersect( *pSfrTrim) || ! pParamTrim->IsValid()) - return false ; + // //questo metodo NON VA BENE perchè tiene anche parte dei loop che stanno fuori dal parametrico e quindi il FINDCELL può fallire + // + //// creo la flat region di trim, quella del parametrico e li interseco + //PtrOwner pSfrTrim( GetSurfFlatRegionFromPolyLine( pl)) ; + //bool bInverted = false ; + //if ( ! pSfrTrim->GetNormVersor().IsZplus()) { + // pSfrTrim->Invert() ; + // bInverted = true ; + //} + //PtrOwner pParamTrim( GetSurfFlatRegionRectangle( SBZ_TREG_COEFF * m_nSpanU, SBZ_TREG_COEFF * m_nSpanV)) ; + //if ( ! pParamTrim->Intersect( *pSfrTrim) || ! pParamTrim->IsValid()) { + // if ( ! pParamTrim->Offset( 10 * EPS_SMALL, ICurve::OFF_EXTEND)) + // return false ; + // if ( ! pParamTrim->Intersect( *pSfrTrim) || ! pParamTrim->IsValid()) + // return false ; + // if ( ! pParamTrim->Offset( -10 * EPS_SMALL, ICurve::OFF_EXTEND)) + // return false ; + //} + + //// ricostruisco la curva tenendo solo le parti dentro lo spazio parametrico + //// devo recuperare la polyline dei bordi dei vari chunk creati + //for ( int c = 0 ; c < int( pParamTrim->GetChunkCount()) ; ++c) { + // for ( int l = 0 ; l < pParamTrim->GetLoopCount(c) ; ++l) { + // PtrOwner pCrv ( pParamTrim->GetLoop( c, l)) ; + // if ( bInverted) + // pCrv->Invert() ; + // PolyLine plApprox ; + // double dLinTol = 10 * EPS_SMALL, dAngTolDeg = 5 ; + // int nType = 0 ; + // pCrv->ApproxWithLines( dLinTol, dAngTolDeg, nType, plApprox) ; + // // aggiungo la polyline del chunk + // vPl.push_back( plApprox) ; + // } + //} + + + + //// CON LE CURVE ( INTERSEZIONI CON BORDO PARAMETRICO) + PtrOwner pCCEdge( CreateCurveComposite()) ; + pCCEdge->AddPoint( m_mTree.at(-1).GetTopRight()) ; + pCCEdge->AddLine( m_mTree.at(-1).GetTopLeft()) ; + pCCEdge->AddLine( m_mTree.at(-1).GetBottomLeft()) ; + pCCEdge->AddLine( m_mTree.at(-1).GetBottomRight()) ; + pCCEdge->Close() ; + + PtrOwner pCC( CreateCurveComposite()) ; + pCC->FromPolyLine( pl) ; + ICURVEPLIST vCrv ; + AdjustLoops( Release( pCC), vCrv, false) ; + + if ( vCrv.size() > 1) + VerifyLoopOrientation( vCrv, vbOrientation) ; + for ( auto itCrv = vCrv.begin() ; itCrv != vCrv.end() ; ++itCrv) { + IntersCurveCurve icc( *pCCEdge, *(*itCrv)) ; + CRVCVECTOR vCrvClass ; + ICRVCOMPOPOVECTOR vCC ; + if ( ! icc.GetCurveClassification( 1, 0.01, vCrvClass)) + return false ; // se non riesco a calcolare la classificazione potrei provare a ricostruire a mano usando le intersezioni trovate + int nLast = 0 ; + if ( vCrvClass.size() > 1) { + for ( int i = 0 ; i < int( vCrvClass.size()) ; ++i) { + if ( vCrvClass[i].nClass != CRVC_OUT) { + // se continua la curva precedente allora la giunta + if ( vCC.size() != 0 && vCrvClass[i].dParS == vCrvClass[nLast].dParE) + vCC.back()->AddCurve( (*itCrv)->CopyParamRange( vCrvClass[i].dParS, vCrvClass[i].dParE)) ; + // sennò creo una nuova curva + else + vCC.emplace_back( GetCurveComposite( (*itCrv)->CopyParamRange( vCrvClass[i].dParS, vCrvClass[i].dParE))) ; + nLast = i ; + } + } + + POLYLINEVECTOR vPL ; + // qui devo ricostruire la curva con i pezzi da tenere + for ( int i = 0 ; i < int( vCC.size()) ; ++i) { + PolyLine plApprox ; + vCC[i]->ApproxWithLines( 0.01,15, 0, plApprox) ; + vPL.push_back( plApprox) ; + } + PolyLine plNew ; + // ricostruzione col bordo + CloseOpenCuts( vPL, plNew) ; + vPl.push_back( plNew) ; + } + else { + PolyLine plApprox ; (*itCrv)->ApproxWithLines( 0.01, 15, 0, plApprox) ; + vPl.push_back( plApprox) ; + } } - // ricostruisco la curva tenendo solo le parti dentro lo spazio parametrico - // devo recuperare la polyline dei bordi dei vari chunk creati - for ( int c = 0 ; c < int( pParamTrim->GetChunkCount()) ; ++c) { - PtrOwner pCrv ( pParamTrim->GetLoop( c, 0)) ; - if ( bInverted) - pCrv->Invert() ; - PolyLine plApprox ; - double dLinTol = 10 * EPS_SMALL, dAngTolDeg = 5 ; - int nType = 0 ; - pCrv->ApproxWithLines( dLinTol, dAngTolDeg, nType, plApprox) ; - // aggiungo la polyline del chunk + for ( auto it = vCrv.begin() ; it != vCrv.end() ; ++it) + delete (*it) ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +Tree::VerifyLoopOrientation( ICURVEPLIST& vpCrv, BOOLVECTOR& vbOrientation) const +{ + // verifico che il verso dei loop sia corretto controllando le relazioni tra loop + vpCrv.sort( []( ICurve* a, ICurve* b) { double AreaA, AreaB ; a->GetAreaXY( AreaA) ; b->GetAreaXY( AreaB) ; return abs(AreaA) > abs(AreaB) ;}) ; + auto it = vpCrv.begin() ; + for ( ++it ; it != vpCrv.end() ; ++it) { + bool bIdentified = false ; + for ( auto k = it ; k != vpCrv.begin() ;) { + --k ; + IntersCurveCurve icc( **k, **it) ; + int nRes = icc.GetRegionCurveClassification() ; + if ( nRes == CCREGC_IN1) { + bIdentified = true ; + vbOrientation.push_back( ! vbOrientation[ distance( vpCrv.begin(), k)]) ; // l'orientazione deve essere opposta alla prima curva che contiene la corrente + break ; + } + } + if ( ! bIdentified) + vbOrientation.push_back( vbOrientation[0]) ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Tree::AdjustLoop( PolyLine& pl, POLYLINEVECTOR& vPl, BOOLVECTOR& vbOrientation) const +{ + PtrOwner pCC( CreateCurveComposite()) ; + pCC->FromPolyLine( pl) ; + ICURVEPLIST vCrv ; + AdjustLoops( Release( pCC), vCrv, false) ; + + if ( vCrv.size() > 1) + VerifyLoopOrientation( vCrv, vbOrientation) ; + for ( auto itCrv = vCrv.begin() ; itCrv != vCrv.end() ; ++itCrv) { + PolyLine plApprox ; (*itCrv)->ApproxWithLines( 0.01, 15, 0, plApprox) ; vPl.push_back( plApprox) ; } - return true ; } @@ -108,7 +217,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi m_vnLeaves.clear() ; m_vnParents.clear() ; m_mVert.clear() ; - m_vLoop.clear() ; + //m_vLoop.clear() ; m_mChunk.clear() ; m_vPlApprox.clear() ; m_vPolygons.clear() ; @@ -129,6 +238,15 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi m_bBilinear = true ; if ( nSpanU * nSpanV != 1) m_bMulti = true ; + // creo la cella Root + Point3d ptTop( nSpanU * SBZ_TREG_COEFF, nSpanV * SBZ_TREG_COEFF) ; + bool bLimited = false ; + if ( ! AreSamePointExact( ptMax,ORIG) && ! AreSamePointExact( ptMax,ptTop)) { + ptTop = ptMax ; + bLimited = true ; + } + Cell cRoot( ptMin, ptTop) ; + m_mTree.insert( pair< int, Cell>( -1, cRoot)) ; // recupero i loop di trim e li divido per chunk if ( m_bTrimmed) { int nLoop = 0 ; @@ -139,7 +257,6 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi for ( int i = 0 ; i < pTrimReg->GetChunkCount() ; ++ i) { PtrOwner pChunk( pTrimReg->CloneChunk( i)) ; for ( int j = 0 ; j < pChunk->GetLoopCount( 0) ; ++ j) { - //vChunk.push_back( nLoop) ; // i chunk della falt region sono ancora flat region composte da 1 chunk PtrOwner pLoop ( pChunk->GetLoop( 0, j)) ; // rimuovo i difetti dei loop prima di salvarli @@ -148,9 +265,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi pCrvCompo->RemoveSmallDefects( dLinTol, dAngTolDeg, true) ; pCrvCompo->RemoveSmallParts( dLinTol, dAngTolDeg) ; PtrOwner pCrv( pCrvCompo->Clone()) ; - m_vLoop.emplace_back( Release( pLoop)) ; - m_mChunk[nLoop] = i ; - ++ nLoop ; + // approssimo i loop di trim con delle spezzate PolyLine plApprox ; int nType = 0 ; @@ -164,25 +279,23 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi bCCW = true ; else bCCW = false ; - // limito il loop allo spazio parametrico // potrei ottenere più loop a partire da quello originale - POLYLINEVECTOR vPlLimited ; - if ( ! LimitLoop( plApprox, vPlLimited)) - return false ; - for ( int k = 0 ; k < int( vPlLimited.size()) ; ++k) - m_vPlApprox.push_back( tuple(vPlLimited[k], bCCW)) ; + + POLYLINEVECTOR vPlAdjusted ; + BOOLVECTOR vbOrientation ; + vbOrientation.push_back( bCCW) ; + AdjustLoop( plApprox, vPlAdjusted, vbOrientation) ; + + nLoop = int ( m_vPlApprox.size()) ; + for ( int k = 0 ; k < int( vPlAdjusted.size()) ; ++k ) + m_vPlApprox.push_back( tuple(vPlAdjusted[k], vbOrientation[k])) ; + // aggiorno la mappa del chunk di appartenenza per tutti i loop aggiunti // do per scontato che siano tutti dello stesso chunk anche se li ho separati + //m_vLoop.emplace_back( Release( pLoop)) ; + for ( int k = nLoop ; k < int( m_vPlApprox.size()); ++k) + m_mChunk[k] = i ; } } } // salvo i vertici 3d della cella root - Point3d ptTop( nSpanU * SBZ_TREG_COEFF, nSpanV * SBZ_TREG_COEFF) ; - bool bLimited = false ; - if ( ! AreSamePointExact( ptMax,ORIG) && ! AreSamePointExact( ptMax,ptTop)) { - ptTop = ptMax ; - bLimited = true ; - } - //m_mTree.clear() ; - Cell cRoot( ptMin, ptTop) ; - m_mTree.insert( pair< int, Cell>( -1, cRoot)) ; Point3d ptP00, ptP10, ptP11, ptP01 ; bool bOk = false ; if ( ! bLimited) { @@ -1049,7 +1162,7 @@ Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) const for ( int k : vTopNeighs) vCells.push_back( m_mTree.at( k)) ; // le celle restituite sono ordinate per x crescente - sort( vCells.begin(), vCells.end(), Cell::minorX) ; + std::sort( vCells.begin(), vCells.end(), Cell::minorX) ; vTopNeighs.clear() ; for ( Cell c : vCells) vTopNeighs.push_back( c.m_nId) ; @@ -1131,7 +1244,7 @@ Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) const for ( int k : vBottomNeighs) vCells.push_back( m_mTree.at( k)) ; // le celle restituite sono ordinate per x crescente - sort( vCells.begin(), vCells.end(), Cell::minorX) ; + std::sort( vCells.begin(), vCells.end(), Cell::minorX) ; vBottomNeighs.clear() ; for ( Cell c : vCells) vBottomNeighs.push_back( c.m_nId) ; @@ -1212,7 +1325,7 @@ Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) const for ( int k : vLeftNeighs) vCells.push_back( m_mTree.at( k)) ; // le celle restituite sono ordinate per y crescente - sort( vCells.begin(), vCells.end(), Cell::minorY) ; + std::sort( vCells.begin(), vCells.end(), Cell::minorY) ; vLeftNeighs.clear() ; for ( Cell c : vCells) vLeftNeighs.push_back( c.m_nId) ; @@ -1293,7 +1406,7 @@ Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) const for ( int k : vRightNeighs) vCells.push_back( m_mTree.at( k)) ; // le celle restituite sono ordinate per y crescente - sort( vCells.begin(), vCells.end(), Cell::minorY) ; + std::sort( vCells.begin(), vCells.end(), Cell::minorY) ; vRightNeighs.clear() ; for ( Cell c : vCells) vRightNeighs.push_back( c.m_nId) ; @@ -1428,6 +1541,7 @@ Tree::GetPolygons( POLYLINEMATRIX& vPolygons) POLYLINEVECTOR vPolygonsBasic ; GetPolygonsBasic( vPolygonsBasic) ; // aggiungo 4 elementi al vettore che contiene ciò che resta degli edge dopo il trim + m_vCEdge2D.clear() ; for ( int i = 0 ; i < 4 ; ++i) { m_vCEdge2D.emplace_back() ; m_vCEdge2D.back().second.Init( false, EPS_SMALL, 1) ; @@ -1560,7 +1674,7 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons, INTVECTOR vCells) vNeigh.clear() ; vVertices.push_back( m_mTree.at( nId).GetTopRight()) ; GetTopNeigh ( nId, vNeigh) ; - reverse( vNeigh.begin(), vNeigh.end()) ; + std::reverse( vNeigh.begin(), vNeigh.end()) ; // aggiungo i vertici che sono sul lato top, solo se ho più di un vicino top if ( ! vNeigh.empty() && vNeigh.size() != 1) { // se la superficie è chiusa lungo il parametro V e la cella è sul lato top @@ -1581,7 +1695,7 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons, INTVECTOR vCells) bTopLeft = false ; vNeigh.clear() ; GetLeftNeigh ( nId, vNeigh) ; - reverse( vNeigh.begin(), vNeigh.end()) ; + std::reverse( vNeigh.begin(), vNeigh.end()) ; // aggiungo i vertici che sono sul lato left, solo se ho più di un vicino left if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) { // se la superficie è chiusa lungo il parametro U e la cella è sul lato left @@ -2034,7 +2148,7 @@ Tree::TraceLoopLabelCell( const POLYLINEVECTOR& vplPolygons) // riordino i vettori di intersezione per ogni cella e setto il flag RightEdgeIn for ( int nId : m_vnLeaves) { - sort( m_mTree[nId].m_vInters.begin(), m_mTree[nId].m_vInters.end()) ; + std::sort( m_mTree[nId].m_vInters.begin(), m_mTree[nId].m_vInters.end()) ; SetRightEdgeIn( nId) ; } @@ -2319,7 +2433,7 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool INTVECTOR vNeigh, vNeigh1 ; if ( nEdge == 0) { GetTopNeigh( nId, vNeigh) ; - reverse( vNeigh.begin(), vNeigh.end()) ; + std::reverse( vNeigh.begin(), vNeigh.end()) ; for ( int j : vNeigh) { if ( ptInters.x >= m_mTree[j].GetBottomLeft().x) { nId = j ; @@ -2339,7 +2453,7 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool } else if ( nEdge == 1) { GetLeftNeigh( nId, vNeigh) ; - reverse( vNeigh.begin(), vNeigh.end()) ; + std::reverse( vNeigh.begin(), vNeigh.end()) ; for ( int j : vNeigh) { if ( ptInters.y >= m_mTree[j].GetBottomLeft().y) { nId = j ; @@ -3641,6 +3755,8 @@ Tree::OnWhichEdge( int nId, const Point3d& ptToAssign, int& nEdge) const nEdge = 2 ; else if ( ptToAssign.y > ptBL.y && ptToAssign.y < ptTR.y && abs( ptToAssign.x - ptTR.x) < EPS_SMALL) nEdge = 3 ; + else if ( ptToAssign.y > ptBL.y && ptToAssign.y < ptTR.y && ptToAssign.x > ptBL.x && ptToAssign.x < ptTR.x) + nEdge = -1 ; else return false ; return true ; @@ -3658,10 +3774,10 @@ Tree::GetEdges3D( POLYLINEMATRIX& mPLEdges) GetRootNeigh( 0, vEdges[0]) ; // le celle sui bordi orizzontali sono ordinate per x o y crescente, ma i io voglio costruire gli edge in senso antiorario a partire dal ptTR, // quindi devo invertire gli Edge 0 e 1 - reverse( vEdges[0].begin(), vEdges[0].end()) ; + std::reverse( vEdges[0].begin(), vEdges[0].end()) ; vEdges.emplace_back() ; GetRootNeigh( 1, vEdges[1]) ; - reverse( vEdges[1].begin(), vEdges[1].end()) ; + std::reverse( vEdges[1].begin(), vEdges[1].end()) ; vEdges.emplace_back() ; GetRootNeigh( 2, vEdges[2]) ; vEdges.emplace_back() ; @@ -3871,12 +3987,12 @@ Tree::AdjustCuts( void) if ( int( m_mTree.at( -1).m_vInters.size()) == 1) return true ; // li riordino per ordine di quali taglio incontrerei percorrendo il bordo della cella a partire da ptTR - sort( m_mTree.at( -1).m_vInters.begin(), m_mTree.at( -1).m_vInters.end(), [](Inters& a, Inters& b){ return Inters::FirstEncounter(a,b) ;}) ; + std::sort( m_mTree.at( -1).m_vInters.begin(), m_mTree.at( -1).m_vInters.end(), [](Inters& a, Inters& b){ return Inters::FirstEncounter(a,b) ;}) ; // ora controllo che le intersezioni che trovo siano ingressi alternati ad uscite, sennò inverto l'intersezione bool bPreviousWasStart = m_mTree.at( -1).m_vInters.at(0).bSortedbyStart ; for ( int i = 0 ; i < int( m_mTree.at( -1).m_vInters.size()); ++i) { if ( m_mTree.at( -1).m_vInters.at(i).bSortedbyStart == bPreviousWasStart) { - reverse( m_mTree.at( -1).m_vInters.at(i).vpt.begin(), m_mTree.at( -1).m_vInters.at(i).vpt.end()) ; + std::reverse( m_mTree.at( -1).m_vInters.at(i).vpt.begin(), m_mTree.at( -1).m_vInters.at(i).vpt.end()) ; int nEdgeOutNew = m_mTree.at( -1).m_vInters.at(i).nIn ; m_mTree.at( -1).m_vInters.at(i).nIn = m_mTree.at( -1).m_vInters.at(i).nOut ; m_mTree.at( -1).m_vInters.at(i).nOut = nEdgeOutNew ; @@ -3916,5 +4032,217 @@ Tree::CreateCellContour( POLYLINEMATRIX& vPolygons) if ( nPolyBefore == nPoly) break ; } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Tree::CloseOpenCuts( POLYLINEVECTOR& vPL, PolyLine& plNew) const // da verificare e comunque funzione probabilmente inutile +{ + if ( vPL.size() == 1 && vPL[0].IsClosed()) { + plNew = vPL[0] ; + return true ; + } + + vector vInters ; + for ( int i = 0 ; i < int( vPL.size()) ; ++i) { + vInters.emplace_back() ; + Point3d ptStart ; vPL[i].GetFirstPoint( ptStart) ; + OnWhichEdge( -1, ptStart, vInters.back().nIn) ; + Point3d ptEnd ; vPL[i].GetLastPoint( ptEnd) ; + OnWhichEdge( -1, ptEnd, vInters.back().nOut) ; + PNTULIST lPnt = vPL[i].GetUPointList() ; + for ( auto it = lPnt.begin() ; it != lPnt.end() ; ++it) + vInters.back().vpt.push_back( (*it).first) ; + } + + std::sort( vInters.begin(), vInters.end(), [](Inters &left, Inters &right) { return left < right;}) ; + bool bNotCameBack = true ; + int nEdge = vInters[0].nOut ; + PNTULIST lPnt = vPL[0].GetUPointList() ; + for ( auto it = lPnt.begin() ; it != lPnt.end() ; ++it) + plNew.AddUPoint( (*it).second, (*it).first) ; + // se ero in un vertice passo all'edge successivo + if ( nEdge > 3 && nEdge != 7) + nEdge = nEdge - 4 ; + else if ( nEdge == 7) + nEdge = 0 ; + int nInters = 0 ; + while ( bNotCameBack) { + bool bAtNextStart = false ; + //PolyLine plEdge ; + double dCount ; plNew.GetLastU( dCount) ; + plNew.AddUPoint( dCount, vInters[nInters].vpt.back()) ; + ++ dCount ; + ++ nInters ; + if ( nInters == vInters.size()) + nInters = 0 ; + // scorro tutti i lati finché non torno allo start del loop + while( ! bAtNextStart) { + Point3d ptToAdd ; + if ( nEdge == 0) + ptToAdd = m_mTree.at(-1).GetTopLeft() ; + else if ( nEdge == 1) + ptToAdd = m_mTree.at(-1).GetBottomLeft() ; + else if ( nEdge == 2) + ptToAdd = m_mTree.at(-1).GetBottomRight() ; + else if ( nEdge == 3) + ptToAdd = m_mTree.at(-1).GetTopRight() ; + if ( plNew.AddUPoint( dCount, ptToAdd)) + ++ dCount ; + if ( nEdge > 3 && nEdge != 7) + nEdge = nEdge - 4 ; + else if ( nEdge < 3) + ++ nEdge ; + else + nEdge = 0 ; + if ( AreSameEdge(nEdge,vInters[nInters].nIn)) + bAtNextStart = true ; + } + if ( nInters != 0 && nInters < int(vPL.size())) { + // aggiungo la polyline successiva + PNTULIST lPnt = vPL[nInters].GetUPointList() ; + double dLastU ; vPL[nInters-1].GetLastU( dLastU) ; + ++ dLastU ; + for ( auto it = lPnt.begin() ; it != lPnt.end() ; ++it) + plNew.AddUPoint( dLastU + (*it).second, (*it).first) ; + } + if ( AreSameEdge(nEdge, vInters[0].nIn)) { + plNew.Close() ; + bNotCameBack = false ; + } + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Tree::CloseOpenCuts( void) +{ + int nRoot = -1 ; + // tra i loop del parametrico seleziono quelli aperti + // creo il vettore inters, lo riordino e poi rendo chiusi i loop ( che possono restare indipendenti o unirsi ad altri loop aperti) + INTVECTOR vOpen ; + for ( int i = 0 ; i < int(m_vPlApprox.size()) ; ++i ) { + if ( ! get<0>(m_vPlApprox[i]).IsClosed()) { + m_mTree.at( nRoot).m_vInters.emplace_back() ; + Point3d ptStart ; get<0>(m_vPlApprox[i]).GetFirstPoint( ptStart) ; + OnWhichEdge( nRoot, ptStart, m_mTree.at( nRoot).m_vInters.back().nIn) ; + Point3d ptEnd ; get<0>(m_vPlApprox[i]).GetLastPoint( ptEnd) ; + OnWhichEdge( nRoot, ptEnd, m_mTree.at( nRoot).m_vInters.back().nOut) ; + vOpen.push_back( i) ; + } + } + // riordino le intersezioni + std::sort( m_mTree.at(nRoot).m_vInters.begin(), m_mTree.at(nRoot).m_vInters.end()) ; + + m_vnLeaves.push_back( -1) ; + // chiamo la GetPolygons + POLYLINEMATRIX mPL ; + GetPolygons( mPL) ; + + //creo il nuovo vettore di polyline di trim + // tengo quelli che erano i trim chiusi + for ( int t = int(vOpen.size()) - 1 ; t > -1 ; ++t ) { + m_vPlApprox.erase( m_vPlApprox.begin() + vOpen[t]) ; + } + + // aggiungo i nuovi trim creati + for ( int t = 0 ; t < int( mPL[0].size()) ; ++t) { + m_vPlApprox.push_back( pair(mPL[0][t], true)) ; + } + + m_vnLeaves.clear() ; + m_mTree.at( nRoot).m_vInters.clear() ; + + //// tra i loop del parametrico seleziono quelli aperti + //// creo il vettore inters, lo riordino e poi rendo chiusi i loop ( che possono restare indipendenti o unirsi ad altri loop aperti) + //vector> vInters ; + //INTVECTOR vClosed ; + //for ( int i = 0 ; i < int(m_vPlApprox.size()) ; ++i ) { + // if ( ! get<0>(m_vPlApprox[i]).IsClosed()) { + // vInters.emplace_back() ; + // vInters.back().first = i ; + // Point3d ptStart ; get<0>(m_vPlApprox[i]).GetFirstPoint( ptStart) ; + // OnWhichEdge( -1, ptStart, vInters.back().second.nIn) ; + // Point3d ptEnd ; get<0>(m_vPlApprox[i]).GetLastPoint( ptEnd) ; + // OnWhichEdge( -1, ptEnd, vInters.back().second.nOut) ; + // } + // else + // vClosed.push_back( i) ; + //} + + //// A MANO + //// chiudo le curve aperte e se necessario le giunto tra loro + //if ( vInters.size() != 0) { + // ICurveComposite* pCCOpen ( CreateBasicCurveComposite()) ; + // pCCOpen->FromPolyLine( get<0>(m_vPlApprox[vInters[0].first])) ; + // //sort( vInters.begin(), vInters.end()) ; + // sort( vInters.begin(), vInters.end(), [](pair &left, pair &right) { return left.second < right.second;}) ; + // bool bNotCameBack = true ; + // int nEdge = vInters[0].second.nOut ; + + // // se ero in un vertice passo all'edge successivo + // if ( nEdge > 3 && nEdge != 7) + // nEdge = nEdge - 4 ; + // else if ( nEdge == 7) + // nEdge = 0 ; + // int nInters = 0 ; + // while ( bNotCameBack) { + // bool bAtNextStart = false ; + // PolyLine plEdge ; + // int nCount = 0 ; + // plEdge.AddUPoint( nCount, vInters[nInters].ptEnd) ; + // ++ nCount ; + // ++ nInters ; + // if ( nInters == vInters.size()) + // nInters = 0 ; + // // scorro tutti i lati finché non torno allo start del loop + // while( ! bAtNextStart) { + // Point3d ptToAdd ; + // if ( nEdge == 0) + // ptToAdd = m_mTree.at(-1).GetTopLeft() ; + // else if ( nEdge == 1) + // ptToAdd = m_mTree.at(-1).GetBottomLeft() ; + // else if ( nEdge == 2) + // ptToAdd = m_mTree.at(-1).GetBottomRight() ; + // else if ( nEdge == 3) + // ptToAdd = m_mTree.at(-1).GetTopRight() ; + // if ( plEdge.AddUPoint( nCount, ptToAdd)) + // ++ nCount ; + // if ( nEdge > 3 && nEdge != 7) + // nEdge = nEdge - 4 ; + // else if ( nEdge < 3) + // ++ nEdge ; + // else + // nEdge = 0 ; + // if ( AreSameEdge(nEdge,vInters[nInters].second.nIn)) + // bAtNextStart = true ; + // } + // ICurveComposite* pCC( CreateCurveComposite()) ; + // pCC->FromPolyLine( plEdge) ; + // // aggiungo il tratto di edge + // pCCOpen->AddCurve( pCC) ; + // // agggiungo il prossio taglio + // if ( nInters != 0) + // pCCOpen->AddCurve( Release( vInters[nInters].pCrv)) ; + // if ( AreSameEdge(nEdge, vInters[0].second.nIn)) { + // pCCOpen->Close() ; + // bNotCameBack = false ; + // } + // } + // if ( ! pCCOpen->IsClosed()) { + // LOG_ERROR( pGenLog, "Error creating the contour from open trims") ; + // return nullptr ; + // } + // if ( ! bPlanarSurf) { + // if ( ! SimplifyCurve( pCCOpen)) { + // LOG_ERROR( pGenLog, "Error simplifying the contour recreated from the open trims") ; + // return nullptr ; + // } + // } + // SfrCntr.AddCurve( pCCOpen) ; + //} + return true ; } \ No newline at end of file diff --git a/Tree.h b/Tree.h index e656220..39a6cd1 100644 --- a/Tree.h +++ b/Tree.h @@ -254,7 +254,7 @@ class Tree std::vector GetPoles( void) { return m_vbPole ;} ; // funzione che restituisce i flag che indicano se i lati sono collassati in dei poli private : - bool LimitLoop( PolyLine& pl, POLYLINEVECTOR& vPl) const ; // funzione che limita i loop di trim allo spazio parametrico + bool LimitLoop( PolyLine& pl, POLYLINEVECTOR& vPl, BOOLVECTOR& vbOrientation) const ; // funzione che limita i loop di trim allo spazio parametrico bool Split( int nId, double dSplitValue) ; // funzione di split di una cella al parametro indicato nella direzione data da bVert bool Split( int nId) ; // funzione di split di una cella dell'albero a met� nella direzione data da bVert void Balance( void) ; // creo rami in modo che tutte tutte le foglie abbiano come adiacenti foglie ad una profondit� di +- 1 @@ -285,6 +285,10 @@ class Tree bool OnWhichEdge( int nId, const Point3d& ptToAssign, int& nEdge) const ; // indica a quale edge o vertice il punto è vicino entro EPS_SMALL bool AdjustCuts( void) ; bool UpdateSplitLoop( PolyLine& pl, int& nCount, Point3d& pt) ; + bool CloseOpenCuts( void) ; + bool CloseOpenCuts( POLYLINEVECTOR& vPL, PolyLine& pl) const ; + bool VerifyLoopOrientation( ICURVEPLIST& vpCrv, BOOLVECTOR& vbOrientation) const ; // verifico l'orientazione ( CCW o CW) delle polyline in base a come sono contenute le une nelle altre + bool AdjustLoop( PolyLine& pl, POLYLINEVECTOR& vPl, BOOLVECTOR& vbOrientation) const ; private : @@ -293,7 +297,7 @@ class Tree bool m_bTrimmed ; // superficie trimmata //INTMATRIX m_vChunk ; // elenco dei loop divisi per chunk std::map m_mChunk ; // mappa in cui vengono salvati chunk di appartenza per ogni loop di trim - ICURVEPOVECTOR m_vLoop ; // curve di loop + //ICURVEPOVECTOR m_vLoop ; // curve di loop std::vector> m_vPlApprox ; // vettore contenente le approssimazioni dei loop // il bool indica se la curva è CCW bool m_bBilinear ; // superficie bilineare bool m_bMulti ; // superficie multi-patch