//---------------------------------------------------------------------------- // EgalTech 2019-2019 //---------------------------------------------------------------------------- // File : SurfTriMeshBooleans.cpp Data : 27.05.19 Versione : 2.1e5 // Contenuto : Implementazione delle funzioni booleane per SurfFTrimesh. // // // // Modifiche : 10.05.19 LM Creazione modulo. // // //---------------------------------------------------------------------------- #include "stdafx.h" #include "SurfTriMesh.h" #include "CurveLine.h" #include "CurveComposite.h" #include "SurfFlatRegion.h" #include "DistPointLine.h" #include "Triangulate.h" #include "GeoConst.h" #include "/EgtDev/Include/EgkCurve.h" #include "/EgtDev/Include/EgkDistPointCurve.h" #include "/EgtDev/Include/EgkIntersLineTria.h" #include "/EgtDev/Include/EgkIntersTriaTria.h" #include "/EgtDev/Include/EGkChainCurves.h" #include //---------------------------------------------------------------------------- struct TriaInOut { Triangle3d trTria ; bool bTriaInside ; } ; //---------------------------------------------------------------------------- bool FindRectangleTriangleIntersectionSegment(const Point3d ptP1, const Point3d ptP2, const Point3d ptP3, const Point3d ptP4, const Triangle3d& trTria, Point3d& ptStSeg, Point3d& ptEnSeg) { // Definisco i due triangoli formanti il rettangolo Triangle3d trTria1, trTria2 ; trTria1.Set( ptP1, ptP2, ptP4) ; trTria2.Set( ptP2, ptP3, ptP4) ; trTria1.Validate() ; trTria2.Validate() ; Vector3d vtSeg = ptP2 - ptP1 ; vtSeg.Normalize() ; // Interseco il triangolo corrente col primo dei due triangoli del rettangolo Point3d ptIntA1, ptIntB1 ; TRIA3DVECTOR vTria1 ; int nIntType1 = IntersTriaTria( trTria1, trTria, ptIntA1, ptIntB1, vTria1) ; if ( nIntType1 == ITTT_YES) { if ( ( ptIntB1 - ptIntA1) * vtSeg < 0.) std::swap( ptIntA1, ptIntB1) ; ptStSeg = ptIntA1 ; ptEnSeg = ptIntB1 ; } // Interseco il triangolo corrente con il secondo dei due triangoli del rettangolo Point3d ptIntA2, ptIntB2 ; TRIA3DVECTOR vTria2 ; int nIntType2 = IntersTriaTria( trTria2, trTria, ptIntA2, ptIntB2, vTria2) ; if ( nIntType2 == ITTT_YES) { if ( ( ptIntB2 - ptIntA2) * vtSeg < 0.) std::swap( ptIntA2, ptIntB2) ; ptEnSeg = ptIntB2 ; if ( ! ( nIntType1 == ITTT_YES)) ptStSeg = ptIntA2 ; } return ( nIntType1 == ITTT_YES || nIntType2 == ITTT_YES) ; } //---------------------------------------------------------------------------- bool FindRectangleTriangleIntersectionSegment2( const Point3d ptP1, const Point3d ptP2, const Point3d ptP3, const Point3d ptP4, const Triangle3d& trTria, Point3d& ptStSeg, Point3d& ptEnSeg) { // Definisco i due triangoli formanti il rettangolo Triangle3d trTria1, trTria2; trTria1.Set(ptP1, ptP2, ptP4); trTria2.Set(ptP2, ptP3, ptP4); trTria1.Validate(); trTria2.Validate(); Vector3d vtSeg = ptP3 - ptP1; vtSeg.Normalize(); // Interseco il triangolo corrente col primo dei due triangoli del rettangolo Point3d ptIntA1, ptIntB1; TRIA3DVECTOR vTria1; int nIntType1 = IntersTriaTria(trTria1, trTria, ptIntA1, ptIntB1, vTria1); if ( nIntType1 == ITTT_YES) { if ((ptIntB1 - ptIntA1) * vtSeg < 0.) std::swap(ptIntA1, ptIntB1); ptStSeg = ptIntA1; ptEnSeg = ptIntB1; } // Interseco il triangolo corrente con il secondo dei due triangoli del rettangolo Point3d ptIntA2, ptIntB2; TRIA3DVECTOR vTria2; int nIntType2 = IntersTriaTria(trTria2, trTria, ptIntA2, ptIntB2, vTria2); if ( nIntType2 == ITTT_YES) { if ((ptIntB2 - ptIntA2) * vtSeg < 0.) std::swap(ptIntA2, ptIntB2); ptEnSeg = ptIntB2; if ( !( nIntType1 == ITTT_YES)) ptStSeg = ptIntA2; } return ( nIntType1 == ITTT_YES || nIntType2 == ITTT_YES); } //---------------------------------------------------------------------------- bool SurfTriMesh::GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq) { // La superficie deve essere valida if ( m_nStatus != OK) return false ; // La curva deve essere valida e chiusa; il vettore estrusione deve essere non nullo Vector3d vtExtr ; if ( ( ! cvCurve.GetExtrusion( vtExtr)) || ( ! cvCurve.IsClosed()) || vtExtr.IsSmall()) return false ; // Approssimo la curva con segmenti PolyLine plLine ; cvCurve.ApproxWithLines( LIN_TOL_FINE, ANG_TOL_STD_DEG, ICurve::APL_STD, plLine) ; // Appiattisco la polilinea nel piano perpendicolare all'estrusione Frame3d frCurve ; Point3d ptStart ; cvCurve.GetStartPoint( ptStart) ; frCurve.Set( ptStart, vtExtr) ; plLine.ToLoc( frCurve) ; plLine.Flatten() ; double dArea ; plLine.GetAreaXY( dArea) ; BBox3d b3Crv ; plLine.GetLocalBBox( b3Crv) ; plLine.ToGlob( frCurve) ; // Assegno il senso di rotazione della curva (visto dalla punta del vettore estrusione) bool bCCW = ( dArea > 0) ; // Recupero Bounding-box della trimesh BBox3d b3SurfBox ; GetLocalBBox( b3SurfBox) ; // Trovo minima e massima distanza dei vertici del bounding-box della TriMesh dal piano della curva b3SurfBox.ToLoc( frCurve) ; Point3d ptMin, ptMax ; b3SurfBox.GetMinMax( ptMin, ptMax) ; Vector3d vtMax = ( ptMax.z + 10) * vtExtr ; Vector3d vtMin = ( ptMin.z - 10) * vtExtr ; // Ciclo sui triangoli bool bModif = false ; int nNumTria = GetTriangleSize() ; for ( int nT = 0 ; nT < nNumTria ; ++ nT) { // Recupero il triangolo Triangle3d trTria ; GetTriangle( nT, trTria) ; // Box del triangolo nel riferimento locale della curva BBox3d b3Tria ; trTria.GetLocalBBox( b3Tria) ; b3Tria.ToLoc( frCurve) ; // Se il box del triangolo non interseca quello della curva if ( ! b3Crv.OverlapsXY( b3Tria)) { if ( bCCW) { RemoveTriangle( nT) ; bModif = true ; } continue ; } // Determino il numero di vertici che cadono nella curva int nVertInside = 0 ; // Ciclo sui vertici del triangolo for ( int nV = 0 ; nV < 3 ; ++ nV) { // Vertice del triangolo e sua proiezione sul piano della curva Point3d ptVert ; if ( ! GetVertex( m_vTria[nT].nIdVert[nV], ptVert)) continue ; double dDistVertPlane = ( ptVert - ptStart) * vtExtr ; Point3d ptVertOnPlane = ptVert - dDistVertPlane * vtExtr ; // Ciclo sui segmenti della curva, per determinare se la proiezione sulla curva di almeno un vertice // del triangolo è all'interno del loop oppure un punto della curva, spostandosi lungo una // retta parallela al versore di estrusione, interseca il triangolo. double dSqDistVertCurve = DBL_MAX ; Point3d ptStMin, ptEnMin ; Point3d ptSt, ptEn ; bool bContinue = plLine.GetFirstLine( ptSt, ptEn) ; while ( bContinue) { CurveLine cvLine ; cvLine.Set( ptSt, ptEn) ; // Calcolo della distanza del vertice proiettato sul piano della curva // dal segmento corrente DistPointLine dCurDistCalc( ptVertOnPlane, cvLine) ; double dCurSqDist ; // Se tale distanza è minore della minima distanza attuale, la aggiorno insieme con gli estremi // del segmento a distanza minima if ( dCurDistCalc.GetSqDist( dCurSqDist) && dCurSqDist < dSqDistVertCurve) { dSqDistVertCurve = dCurSqDist ; ptStMin = ptSt ; ptEnMin = ptEn ; } bContinue = plLine.GetNextLine( ptSt, ptEn) ; } // Direzione del segmento a minima distanza dal vertice corrente proiettato sul piano della curva Vector3d vtTan = ptEnMin - ptStMin ; vtTan.Normalize() ; // Se punto proiettato nella curva aumentiamo il numero di punti interni if ( ( ptVertOnPlane - ptStMin) * ( vtTan ^ vtExtr) < EPS_SMALL) ++ nVertInside ; } // Casi in cui l'orientamento della curva stabilisce la parti interne ed esterne del triangolo if ( abs( trTria.GetN() * vtExtr) > EPS_ZERO) { // Vettore di segmenti std::vector vLine ; // Ciclo sui segmenti Point3d ptSt, ptEn ; bool bContinue = plLine.GetFirstLine( ptSt, ptEn) ; while ( bContinue) { Point3d ptSegSt, ptSegEn ; // C'è interferenza fra il rettangolo, ottenuto dall'estrusione del segmento corrente, e il triangolo if ( FindRectangleTriangleIntersectionSegment( ptSt + vtMin, ptEn + vtMin, ptEn + vtMax, ptSt + vtMax, trTria, ptSegSt, ptSegEn)) { // Costruisco il tratto di curva CurveLine cvLine ; if ( cvLine.Set( ptSegSt, ptSegEn)) vLine.emplace_back( cvLine) ; } bContinue = plLine.GetNextLine( ptSt, ptEn) ; } // Creo i loop ChainCurves LoopCreator ; LoopCreator.Init( false, EPS_SMALL, int( vLine.size())) ; // Carico le curve per concatenarle for ( int nCv = 0 ; nCv < int( vLine.size()) ; ++ nCv) { Point3d ptSt = vLine[nCv].GetStart() ; Point3d ptEn = vLine[nCv].GetEnd() ; Vector3d vtDir; vLine[nCv].GetStartDir( vtDir) ; LoopCreator.AddCurve( nCv + 1, ptSt, vtDir, ptEn, vtDir) ; } // Recupero i concatenamenti INTVECTOR vIds ; Point3d ptNearStart ; std::vector cvLoopVec ; while ( LoopCreator.GetChainFromNear( ptNearStart, false, vIds)) { CurveComposite cvLoop ; for ( auto i : vIds) { // Aggiungo la linea alla curva composta. if ( ! cvLoop.AddCurve( vLine[i - 1], true, 10 * EPS_SMALL)) return false ; } cvLoop.MergeCurves( 10 * EPS_SMALL, ANG_TOL_STD_DEG) ; cvLoopVec.emplace_back( cvLoop) ; } // Fra i loop trovati separo gli aperti dai chiusi std::vector cvInnerClosedLoopVec ; std::vector cvOpenLoopVec ; for ( int nL = 0 ; nL < int( cvLoopVec.size()) ; ++ nL) { if ( cvLoopVec[nL].IsClosed()) cvInnerClosedLoopVec.emplace_back( cvLoopVec[nL]) ; else cvOpenLoopVec.emplace_back( cvLoopVec[nL]) ; } // Se contemporaneamente c'è almeno un loop chiuso e almeno uno aperto, // oppure c'è più di un loop chiuso, vi è un errore. if ( ( cvInnerClosedLoopVec.size() > 0 && cvOpenLoopVec.size() > 0.) || cvInnerClosedLoopVec.size() > 1) return false ; // Se c'è un loop chiuso if ( cvInnerClosedLoopVec.size() == 1) { // Passo da curva composita a PolyLine PolyLine plInnerLoop ; const ICurve* pCv = cvInnerClosedLoopVec[0].GetFirstCurve() ; while ( pCv != nullptr) { // Estremi del segmento corrente del loop chiuso corrente Point3d ptSegSt, ptSegEn ; pCv->GetStartPoint( ptSegSt) ; pCv->GetEndPoint( ptSegEn) ; plInnerLoop.AddUPoint( 0., ptSegSt) ; plInnerLoop.AddUPoint( 0., ptSegEn) ; pCv = cvInnerClosedLoopVec[0].GetNextCurve() ; } // Se necessario inverto il loop trovato if ( trTria.GetN() * vtExtr < - EPS_ZERO) plInnerLoop.Invert() ; // Tre vertici dentro la curva if ( nVertInside == 3) { // Accedo agli indici del triangolo int nTriaVertId[3] ; GetTriangle( nT, nTriaVertId) ; PolyLine plExternalLoop ; Point3d ptTriaVert0, ptTriaVert1, ptTriaVert2 ; GetVertex( nTriaVertId[0], ptTriaVert0) ; GetVertex( nTriaVertId[1], ptTriaVert1) ; GetVertex( nTriaVertId[2], ptTriaVert2) ; // Rimuovo il triangolo corrente RemoveTriangle( nT) ; plExternalLoop.AddUPoint( 0., ptTriaVert0) ; plExternalLoop.AddUPoint( 0., ptTriaVert1) ; plExternalLoop.AddUPoint( 0., ptTriaVert2) ; plExternalLoop.AddUPoint( 0., ptTriaVert0) ; // Poligonalizzo il loop Triangulate CreateTriangulation ; PNTVECTOR vPt ; INTVECTOR vTr ; POLYLINEVECTOR vPL ; vPL.emplace_back( plExternalLoop) ; vPL.emplace_back( plInnerLoop) ; CreateTriangulation.Make( vPL, vPt, vTr) ; // Aggiungo i triangoli 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] = { AddVertex( vPt[nNewTriaVertId[0]]), AddVertex( vPt[nNewTriaVertId[1]]), AddVertex( vPt[nNewTriaVertId[2]]) } ; AddTriangle( nNewId) ; bModif = true ; } } // Se nessun vertice dentro (Con un loop chiuso o ci sono tre vertici dentro alla curva o nessuno) else { // Rimuovo il triangolo corrente RemoveTriangle( nT) ; // Poligonalizzo il loop Triangulate CreateTriangulation ; PNTVECTOR vPt ; INTVECTOR vTr ; CreateTriangulation.Make( plInnerLoop, vPt, vTr) ; // Aggiungo i triangoli 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] = { AddVertex(vPt[nNewTriaVertId[0]]), AddVertex(vPt[nNewTriaVertId[1]]), AddVertex(vPt[nNewTriaVertId[2]]) } ; AddTriangle( nNewId) ; bModif = true ; } } } // Loop aperti, devo chiuderli else if ( cvOpenLoopVec.size() > 0) { // Creo il loop chiuso padre di tutti, il perimetro del triangolo. // Questo viene diviso in sotto-loop chiusi mediante quelli aperti. // I loop chiusi trovati precedentemente sono interni a uno dei sotto-loop // chiusi di cui è formato il perimetro. std::vector cvBoundClosedLoopVec ; CurveComposite cvFirstLoop ; CurveLine cvEdge ; cvEdge.Set( trTria.GetP( 0), trTria.GetP( 1)) ; cvFirstLoop.AddCurve( cvEdge, true, 10 * EPS_SMALL) ; cvEdge.Set( trTria.GetP( 1), trTria.GetP( 2)) ; cvFirstLoop.AddCurve( cvEdge, true, 10 * EPS_SMALL) ; cvEdge.Set( trTria.GetP( 2), trTria.GetP( 0)) ; cvFirstLoop.AddCurve( cvEdge, true, 10 * EPS_SMALL) ; cvBoundClosedLoopVec.emplace_back( cvFirstLoop) ; std::vector vbInOut ; vbInOut.push_back( true) ; // Divido il loop di partenza in sotto-loop while ( cvOpenLoopVec.size() > 0) { int nLastOpenLoopN = int( cvOpenLoopVec.size()) - 1 ; for ( int nL = 0 ; nL < int( cvBoundClosedLoopVec.size()) ; ++ nL) { // Estremi del loop aperto Point3d ptOpenLoopStP, ptOpenLoopEnP ; cvOpenLoopVec[nLastOpenLoopN].GetStartPoint( ptOpenLoopStP) ; cvOpenLoopVec[nLastOpenLoopN].GetEndPoint( ptOpenLoopEnP) ; // Cerco se esistono dei tratti del loop chiuso corrente che sono // toccati dagli estremi del loop aperto corrente const ICurve* pCvSt = nullptr ; const ICurve* pCvEn = nullptr ; const ICurve* pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ; while ( pCv != nullptr && ( pCvSt == nullptr || pCvEn == nullptr)) { // Estremi del segmento corrente del loop chiuso corrente Point3d ptSegSt, ptSegEn ; pCv->GetStartPoint( ptSegSt) ; pCv->GetEndPoint( ptSegEn) ; // Vedo se gli estremi del loop aperto stanno su un segmento del chiuso DistPointLine dStDistCalc( ptOpenLoopStP, ptSegSt, ptSegEn) ; DistPointLine dEnDistCalc( ptOpenLoopEnP, ptSegSt, ptSegEn) ; double dSqDistSt ; dStDistCalc.GetSqDist( dSqDistSt) ; if ( SqDist( ptOpenLoopStP, ptSegSt) < EPS_SMALL * EPS_SMALL || SqDist( ptOpenLoopStP, ptSegEn) < EPS_SMALL * EPS_SMALL) dSqDistSt = 1. ; if ( dSqDistSt < EPS_SMALL * EPS_SMALL) pCvSt = pCv ; double dSqDistEn ; dEnDistCalc.GetSqDist( dSqDistEn) ; if ( SqDist( ptOpenLoopEnP, ptSegSt) < EPS_SMALL * EPS_SMALL || SqDist( ptOpenLoopEnP, ptSegEn) < EPS_SMALL * EPS_SMALL) dSqDistEn = 1. ; if ( dSqDistEn < EPS_SMALL * EPS_SMALL) pCvEn = pCv ; pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ; } // Se entrambi gli estremi del loop aperto sono su un segmento del loop chiuso devo dividere il loop in due if ( pCvSt != nullptr && pCvEn != nullptr) { // Entrambi gli estremi del loop aperto sono su uno stesso segmento del loop chiuso if ( pCvSt == pCvEn) { bool bFirstInside ; bool bFirstSt ; CurveComposite cvSplitLoop1, cvSplitLoop2 ; // Creo primo loop pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ; while ( pCv != nullptr) { // Segmenti loop chiuso if ( pCv != pCvSt && pCv != pCvEn) { Point3d ptSegSt, ptSegEn ; pCv->GetStartPoint( ptSegSt) ; pCv->GetEndPoint( ptSegEn) ; CurveLine cvSeg ; cvSeg.Set( ptSegSt, ptSegEn) ; cvSplitLoop1.AddCurve( cvSeg) ; } // Dal chiuso all'aperto else if ( pCv == pCvSt) { // Distanze degli estremi del loop aperto dal punto iniziale del segmento corrente Point3d ptSegSt, ptSegEn ; pCv->GetStartPoint( ptSegSt) ; double dDistStSt = SqDist( ptSegSt, ptOpenLoopStP) ; double dDistStEn = SqDist( ptSegSt, ptOpenLoopEnP) ; // Devo percorrere il loop aperto nel suo verso if ( dDistStSt < dDistStEn) { // Dall'inizio del segmento corrente fino all'inizio del loop aperto ptSegEn = ptOpenLoopStP ; CurveLine cvSeg ; cvSeg.Set( ptSegSt, ptSegEn) ; cvSplitLoop1.AddCurve( cvSeg) ; // Loop aperto const ICurve* pOpenStart = cvOpenLoopVec[nLastOpenLoopN].GetFirstCurve() ; const ICurve* pOpen = pOpenStart ; while ( pOpen != nullptr) { Point3d ptOpenSt, ptOpenEn ; pOpen->GetStartPoint( ptOpenSt) ; pOpen->GetEndPoint( ptOpenEn) ; CurveLine cvOpenSeg ; cvOpenSeg.Set( ptOpenSt, ptOpenEn) ; cvSplitLoop1.AddCurve( cvOpenSeg) ; if ( pOpen == pOpenStart) { Vector3d vtLast = ptSegSt - ptSegEn ; vtLast.Normalize() ; Vector3d vtFirst = ptOpenEn - ptOpenSt ; vtFirst.Normalize() ; bFirstInside = vtLast * ( vtFirst ^ vtExtr) < 0. ; } pOpen = cvOpenLoopVec[nLastOpenLoopN].GetNextCurve() ; } // Dalla fine del loop aperto alla fine del segmento corrente ptSegSt = ptOpenLoopEnP ; pCv->GetEndPoint( ptSegEn) ; cvSeg ; cvSeg.Set( ptSegSt, ptSegEn) ; cvSplitLoop1.AddCurve( cvSeg) ; bFirstSt = true ; } // Devo percorrere il loop aperto contro il suo verso else { // Dall'inizio del segmento corrente fino alla fine del loop aperto ptSegEn = ptOpenLoopEnP ; CurveLine cvSeg ; cvSeg.Set( ptSegSt, ptSegEn) ; cvSplitLoop1.AddCurve( cvSeg) ; // Loop aperto const ICurve* pOpenLast = cvOpenLoopVec[nLastOpenLoopN].GetLastCurve() ; const ICurve* pOpen = pOpenLast ; while ( pOpen != nullptr) { Point3d ptOpenSt, ptOpenEn ; pOpen->GetStartPoint( ptOpenSt) ; pOpen->GetEndPoint( ptOpenEn) ; CurveLine cvOpenSeg ; cvOpenSeg.Set( ptOpenEn, ptOpenSt) ; cvSplitLoop1.AddCurve( cvOpenSeg) ; if ( pOpen == pOpenLast) { Vector3d vtLast = ptSegSt - ptSegEn ; vtLast.Normalize() ; Vector3d vtFirst = ptOpenEn - ptOpenSt ; vtFirst.Normalize() ; bFirstInside = vtLast * ( vtFirst ^ vtExtr) < 0. ; } pOpen = cvOpenLoopVec[nLastOpenLoopN].GetPrevCurve() ; } // Dall'inizio del loop aperto fino alla fine del segmento corrente ptSegSt = ptOpenLoopStP ; pCv->GetEndPoint( ptSegEn) ; cvSeg ; cvSeg.Set( ptSegSt, ptSegEn) ; cvSplitLoop1.AddCurve( cvSeg) ; bFirstSt = false ; } } pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ; } // Creo secondo loop if ( bFirstSt) { // Tratto segmento ove cadono gli estremi del loop aperto CurveLine cvSeg ; cvSeg.Set( ptOpenLoopStP, ptOpenLoopEnP) ; cvSplitLoop2.AddCurve( cvSeg) ; // Loop aperto const ICurve* pOpen = cvOpenLoopVec[nLastOpenLoopN].GetLastCurve(); while (pOpen != nullptr) { Point3d ptOpenSt, ptOpenEn; pOpen->GetStartPoint(ptOpenSt); pOpen->GetEndPoint(ptOpenEn); CurveLine cvOpenSeg; cvOpenSeg.Set(ptOpenEn, ptOpenSt); cvSplitLoop2.AddCurve(cvOpenSeg); pOpen = cvOpenLoopVec[nLastOpenLoopN].GetPrevCurve(); } } else { // Tratto segmento ove cadono gli estremi del loop aperto CurveLine cvSeg ; cvSeg.Set( ptOpenLoopEnP, ptOpenLoopStP) ; cvSplitLoop2.AddCurve( cvSeg) ; // Loop aperto const ICurve* pOpen = cvOpenLoopVec[nLastOpenLoopN].GetFirstCurve() ; while ( pOpen != nullptr) { Point3d ptOpenSt, ptOpenEn ; pOpen->GetStartPoint( ptOpenSt) ; pOpen->GetEndPoint( ptOpenEn) ; CurveLine cvOpenSeg ; cvOpenSeg.Set( ptOpenSt, ptOpenEn) ; cvSplitLoop2.AddCurve( cvOpenSeg); pOpen = cvOpenLoopVec[nLastOpenLoopN].GetNextCurve() ; } } // Aggiungo i nuovi loop nel vettore cvBoundClosedLoopVec[nL] = cvSplitLoop1 ; cvBoundClosedLoopVec.emplace_back( cvSplitLoop2) ; vbInOut[nL] = bFirstInside ; vbInOut.push_back( ! bFirstInside) ; } // Estremi dell'aperto su due diversi segmenti del chiuso else { bool bFirstInside ; bool bFirstSt ; CurveComposite cvSplitLoop1, cvSplitLoop2 ; // Creo primo loop pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ; while ( pCv != nullptr) { // Segmento su cui non incide nessun estremo del loop aperto if ( pCv != pCvSt && pCv != pCvEn) { Point3d ptSegSt, ptSegEn ; pCv->GetStartPoint( ptSegSt) ; pCv->GetEndPoint( ptSegEn) ; CurveLine cvSeg ; cvSeg.Set( ptSegSt, ptSegEn) ; cvSplitLoop1.AddCurve( cvSeg) ; } // Segmento su cui incide l'estremo iniziale del loop aperto else if ( pCv == pCvSt) { // Dall'inizio del segmento corrente fino all'inizio del loop aperto Point3d ptSegSt ; pCv->GetStartPoint( ptSegSt) ; CurveLine cvSeg ; cvSeg.Set( ptSegSt, ptOpenLoopStP) ; cvSplitLoop1.AddCurve( cvSeg) ; // Loop aperto const ICurve* pOpenFirst = cvOpenLoopVec[nLastOpenLoopN].GetFirstCurve(); const ICurve* pOpen = pOpenFirst ; while ( pOpen != nullptr) { // Valuto se cvSplitLoop1 è interno o esterno Point3d ptOpenSt, ptOpenEn ; pOpen->GetStartPoint( ptOpenSt) ; pOpen->GetEndPoint( ptOpenEn) ; CurveLine cvOpenSeg ; cvOpenSeg.Set( ptOpenSt, ptOpenEn) ; cvSplitLoop1.AddCurve( cvOpenSeg) ; if ( pOpen == pOpenFirst) { Vector3d vtLast = ptSegSt - ptOpenLoopStP ; vtLast.Normalize() ; Vector3d vtFirst = ptOpenEn - ptOpenSt ; vtFirst.Normalize() ; bFirstInside = vtLast * ( vtFirst ^ vtExtr) < 0. ; } pOpen = cvOpenLoopVec[nLastOpenLoopN].GetNextCurve() ; } // Dalla fine del loop aperto fino alla fine del segmento ove arriva il loop aperto while ( pCv != pCvEn) pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ; Point3d ptSegEn ; pCv->GetEndPoint( ptSegEn) ; cvSeg ; cvSeg.Set( ptOpenLoopEnP, ptSegEn) ; cvSplitLoop1.AddCurve( cvSeg) ; bFirstSt = true ; } // Segmento su cui incide l'estremo finale del loop aperto else { // Dall'inizio del segmento corrente fino alla fine del loop aperto Point3d ptSegSt ; pCv->GetStartPoint( ptSegSt) ; CurveLine cvSeg ; cvSeg.Set( ptSegSt, ptOpenLoopEnP) ; cvSplitLoop1.AddCurve( cvSeg) ; // Loop aperto const ICurve* pOpenLast = cvOpenLoopVec[nLastOpenLoopN].GetLastCurve() ; const ICurve* pOpen = pOpenLast ; while ( pOpen != nullptr) { Point3d ptOpenSt , ptOpenEn ; pOpen->GetStartPoint( ptOpenSt) ; pOpen->GetEndPoint( ptOpenEn) ; CurveLine cvOpenSeg ; cvOpenSeg.Set( ptOpenEn, ptOpenSt) ; cvSplitLoop1.AddCurve( cvOpenSeg) ; if ( pOpen == pOpenLast) { Vector3d vtLast = ptSegSt - ptOpenLoopEnP ; vtLast.Normalize() ; Vector3d vtFirst = ptOpenEn - ptOpenSt ; vtFirst.Normalize() ; bFirstInside = vtLast * ( vtFirst ^ vtExtr) < 0. ; } pOpen = cvOpenLoopVec[nLastOpenLoopN].GetPrevCurve() ; } // Dalla fine del loop aperto fino alla fine del segmento ove arriva il loop aperto while ( pCv != pCvSt) pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ; Point3d ptSegEn ; pCv->GetEndPoint( ptSegEn) ; cvSeg.Set( ptOpenLoopStP, ptSegEn) ; cvSplitLoop1.AddCurve( cvSeg) ; bFirstSt = false ; } pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ; } // Creo secondo loop if ( bFirstSt) { // Individuo il segmento ove incide l'estremo iniziale del loop aperto pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ; while ( pCv != pCvSt) pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ; // Dall'estremo finale del loop aperto alla fine del segmento su cui giace Point3d ptSegSt, ptSegEn ; ptSegSt = ptOpenLoopStP ; pCv->GetEndPoint( ptSegEn) ; CurveLine cvSeg ; cvSeg.Set( ptSegSt, ptSegEn) ; cvSplitLoop2.AddCurve( cvSeg) ; // Loop chiuso fino a segmento ove cade l'estremo finale dell'aperto const ICurve* pCvStop = pCvEn ; pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ; if ( pCv == nullptr) pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ; while ( pCv != pCvStop) { if ( pCv == nullptr) pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ; pCv->GetStartPoint( ptSegSt) ; pCv->GetEndPoint( ptSegEn) ; CurveLine cvSeg ; cvSeg.Set( ptSegSt, ptSegEn) ; cvSplitLoop2.AddCurve( cvSeg) ; pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ; } // Dall'inizio del segmento del loop chiuso ove cade l'estremo finale del loop aperto // a quest'ultimo pCv->GetStartPoint( ptSegSt) ; ptSegEn = ptOpenLoopEnP ; cvSeg.Set( ptSegSt, ptOpenLoopEnP) ; cvSplitLoop2.AddCurve( cvSeg) ; // Loop aperto const ICurve* pOpen = cvOpenLoopVec[nLastOpenLoopN].GetLastCurve() ; while ( pOpen != nullptr) { Point3d ptOpenSt, ptOpenEn ; pOpen->GetStartPoint( ptOpenSt) ; pOpen->GetEndPoint( ptOpenEn) ; CurveLine cvOpenSeg ; cvOpenSeg.Set( ptOpenEn, ptOpenSt) ; cvSplitLoop2.AddCurve( cvOpenSeg) ; pOpen = cvOpenLoopVec[nLastOpenLoopN].GetPrevCurve() ; } } else { // Individuo il segmento ove incide l'estremo finale del loop aperto pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ; while ( pCv != pCvEn) pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ; // Dall'estremo finale del loop aperto alla fine del segmento su cui giace Point3d ptSegSt, ptSegEn ; ptSegSt = ptOpenLoopEnP ; pCv->GetEndPoint( ptSegEn) ; CurveLine cvSeg ; cvSeg.Set( ptSegSt, ptSegEn) ; cvSplitLoop2.AddCurve( cvSeg) ; // Loop chiuso fino al segmento ove cade l'inizio del loop aperto const ICurve* pCvStop = pCvSt ; pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ; if ( pCv == nullptr) pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ; while ( pCv != pCvStop) { if ( pCv == nullptr) pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ; pCv->GetStartPoint( ptSegSt) ; pCv->GetEndPoint( ptSegEn) ; CurveLine cvSeg ; cvSeg.Set( ptSegSt, ptSegEn) ; cvSplitLoop2.AddCurve( cvSeg) ; pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ; } // Dall'inizio del segmento del loop chiuso ove cade l'estremo iniziale del loop aperto // a quest'ultimo pCv->GetStartPoint( ptSegSt) ; ptSegEn = ptOpenLoopStP ; cvSeg.Set( ptSegSt, ptOpenLoopStP) ; cvSplitLoop2.AddCurve( cvSeg) ; // Loop aperto const ICurve* pOpen = cvOpenLoopVec[nLastOpenLoopN].GetFirstCurve() ; while ( pOpen != nullptr) { Point3d ptOpenSt, ptOpenEn ; pOpen->GetStartPoint( ptOpenSt); pOpen->GetEndPoint( ptOpenEn); CurveLine cvOpenSeg ; cvOpenSeg.Set( ptOpenSt, ptOpenEn) ; cvSplitLoop2.AddCurve( cvOpenSeg) ; pOpen = cvOpenLoopVec[nLastOpenLoopN].GetNextCurve() ; } } // Aggiungo i nuovi loop nel vettore cvBoundClosedLoopVec[nL] = cvSplitLoop1 ; cvBoundClosedLoopVec.emplace_back( cvSplitLoop2) ; vbInOut[nL] = bFirstInside ; vbInOut.push_back( ! bFirstInside) ; } } } cvOpenLoopVec.resize( nLastOpenLoopN) ; } RemoveTriangle( nT) ; // Trasformo i loop compositi in loop polyline std::vector vplPolyVec ; vplPolyVec.resize( cvBoundClosedLoopVec.size()) ; for ( int nL = 0 ; nL < int( vplPolyVec.size()) ; ++ nL) { const ICurve* pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ; while ( pCv != nullptr) { // Estremi del segmento corrente del loop chiuso corrente Point3d ptSegSt, ptSegEn ; pCv->GetStartPoint( ptSegSt) ; pCv->GetEndPoint( ptSegEn) ; vplPolyVec[nL].AddUPoint( 0., ptSegSt) ; vplPolyVec[nL].AddUPoint( 0., ptSegEn) ; pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ; } if ( vbInOut[nL]) { // Poligonalizzo il loop Triangulate CreateTriangulation ; PNTVECTOR vPt ; INTVECTOR vTr ; CreateTriangulation.Make( vplPolyVec[nL], vPt, vTr) ; // Aggiungo i triangoli 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] = { AddVertex(vPt[nNewTriaVertId[0]]), AddVertex(vPt[nNewTriaVertId[1]]), AddVertex(vPt[nNewTriaVertId[2]]) } ; AddTriangle( nNewId) ; bModif = true ; } } } } else if ( nVertInside == 0) RemoveTriangle( nT) ; } // L'orientamento del loop non stabilise i vertici dentro e fuori else { std::vector vTriaVec ; TriaInOut trStartTria ; trStartTria.trTria = trTria ; trStartTria.bTriaInside = true ; vTriaVec.emplace_back( trStartTria) ; vTriaVec.resize( 1) ; // Ciclo sui segmenti Point3d ptSt, ptEn ; bool bContinue = plLine.GetFirstLine( ptSt, ptEn) ; while ( bContinue) { for ( int nTr = 0 ; nTr < int( vTriaVec.size()) ; ++ nTr) { Point3d ptSegSt, ptSegEn ; // C'è interferenza fra il rettangolo, ottenuto dall'estrusione del segmento corrente, e il triangolo if ( FindRectangleTriangleIntersectionSegment2( ptSt + vtMin, ptEn + vtMin, ptEn + vtMax, ptSt + vtMax, vTriaVec[nTr].trTria, ptSegSt, ptSegEn)) { // Stabilisco su quali lati del triangolo cadono gli estremi del segmento intersezione int nStEdge = -1 ; int nEnEdge = -1 ; for ( int nV = 0 ; nV < 3 ; ++ nV) { int nW = (nV + 1) % 3 ; Point3d ptVertV = vTriaVec[nTr].trTria.GetP( nV) ; Point3d ptVertW = vTriaVec[nTr].trTria.GetP( nW) ; DistPointLine dStDistCalc( ptSegSt, ptVertV, ptVertW) ; DistPointLine dEnDistCalc( ptSegEn, ptVertV, ptVertW) ; double dSqDistSt ; dStDistCalc.GetSqDist( dSqDistSt) ; if ( dSqDistSt < EPS_SMALL * EPS_SMALL) nStEdge = nV ; double dSqDistEn ; dEnDistCalc.GetSqDist( dSqDistEn) ; if ( dSqDistEn < EPS_SMALL * EPS_SMALL) nEnEdge = nV ; } int nMinInd, nMaxInd ; Point3d ptMin, ptMax ; if ( nStEdge < nEnEdge) { nMinInd = nStEdge ; nMaxInd = nEnEdge ; ptMin = ptSegSt ; ptMax = ptSegEn ; } else { nMinInd = nEnEdge ; nMaxInd = nStEdge ; ptMin = ptSegEn ; ptMax = ptSegSt ; } TriaInOut trSingleTria ; PolyLine plInnerLoop ; bool bLoopInside ; if ( nMaxInd == ( nMinInd + 1) % 3) { trSingleTria.trTria.SetP( 0, ptMin) ; trSingleTria.trTria.SetP( 1, vTriaVec[nTr].trTria.GetP( ( nMinInd + 1) % 3)) ; trSingleTria.trTria.SetP( 2, ptMax) ; Vector3d vtTan = ptEn - ptSt ; vtTan.Normalize() ; if ( ( trSingleTria.trTria.GetP(1) - trSingleTria.trTria.GetP(0)) * ( vtTan ^ vtExtr) < 0.) trSingleTria.bTriaInside = true ; else trSingleTria.bTriaInside = false ; trSingleTria.trTria.Validate( true) ; plInnerLoop.AddUPoint( 0., ptMin) ; plInnerLoop.AddUPoint( 0., ptMax) ; plInnerLoop.AddUPoint( 0., vTriaVec[nTr].trTria.GetP( ( nMinInd + 2) % 3)) ; plInnerLoop.AddUPoint( 0., vTriaVec[nTr].trTria.GetP( nMinInd)) ; plInnerLoop.AddUPoint( 0., ptMin) ; if ( ( vTriaVec[nTr].trTria.GetP( nMinInd) - ptMin) * ( vtTan ^ vtExtr) < 0.) bLoopInside = true ; else bLoopInside = false ; } else { trSingleTria.trTria.SetP( 0, ptMin) ; trSingleTria.trTria.SetP( 1, ptMax) ; trSingleTria.trTria.SetP( 2, vTriaVec[nTr].trTria.GetP( nMinInd)) ; Vector3d vtTan = ptEn - ptSt ; vtTan.Normalize() ; if ( ( trSingleTria.trTria.GetP( 2) - trSingleTria.trTria.GetP( 0)) * ( vtTan ^ vtExtr) < 0.) trSingleTria.bTriaInside = true ; else trSingleTria.bTriaInside = false ; trSingleTria.trTria.Validate( true) ; plInnerLoop.AddUPoint( 0., ptMin) ; plInnerLoop.AddUPoint( 0., vTriaVec[nTr].trTria.GetP( ( nMinInd + 1) % 3)) ; plInnerLoop.AddUPoint( 0., vTriaVec[nTr].trTria.GetP( ( nMinInd + 2) % 3)) ; plInnerLoop.AddUPoint( 0., ptMax) ; plInnerLoop.AddUPoint( 0., ptMin) ; if ( ( vTriaVec[nTr].trTria.GetP( ( nMinInd + 1) % 3) - ptMin) * ( vtTan ^ vtExtr) < 0.) bLoopInside = true ; else bLoopInside = false ; } // Poligonalizzo il loop Triangulate CreateTriangulation ; PNTVECTOR vPt ; INTVECTOR vTr ; CreateTriangulation.Make( plInnerLoop, vPt, vTr) ; // Aggiungo i triangoli al vettore int nOldSize = int( vTriaVec.size()) ; int nAddSize = int( vTr.size() / 3) ; vTriaVec.resize( nOldSize + nAddSize) ; for ( int m = nOldSize - 1 ; m > nTr ; -- m) { vTriaVec[m + nAddSize] = vTriaVec[m] ; } vTriaVec[nTr] = trSingleTria ; for ( int n = 0 ; n < int( vTr.size()) - 2 ; n += 3) { int nNewTriaVertId[3] = { vTr[n], vTr[n + 1], vTr[n + 2] } ; TriaInOut trNewTria ; trNewTria.trTria.SetP( 0, vPt[nNewTriaVertId[0]]) ; trNewTria.trTria.SetP( 1, vPt[nNewTriaVertId[1]]) ; trNewTria.trTria.SetP( 2, vPt[nNewTriaVertId[2]]) ; trNewTria.trTria.Validate( true) ; trNewTria.bTriaInside = bLoopInside ; vTriaVec[nTr + 1 + (n / 3)] = trNewTria ; } -- nTr ; } } bContinue = plLine.GetNextLine( ptSt, ptEn) ; } // Se non sono state trovate intersezioni col triangolo if ( vTriaVec.size() == 1) { // Se almeno un punto interno (sotto l'ipotesi di nessuna intersezione // equivale a tre punti interni) deve essere conservato così com'è. if ( nVertInside > 0) continue ; // Altrimenti il triangolo deve essere eliminato else { RemoveTriangle( nT) ; continue ; } } RemoveTriangle( nT) ; bModif = true ; // Aggiungo i triangoli alla trimesh for ( int n = 0 ; n < int( vTriaVec.size()) ; ++ n) { if ( vTriaVec[n].bTriaInside) { int nNewId[3] = { AddVertex(vTriaVec[n].trTria.GetP( 0)), AddVertex(vTriaVec[n].trTria.GetP( 1)), AddVertex(vTriaVec[n].trTria.GetP( 2)) } ; AddTriangle( nNewId) ; } } } } // Se avvenuta modifica, aggiorno tutto if ( bModif) return ( AdjustVertices() && DoCompacting()) ; return true ; }