From 95915b16e5a245f0cefc3bb62b3cb8d2418b7c0f Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Mon, 19 Feb 2024 13:07:50 +0100 Subject: [PATCH] EgtGeomKernel : - migliorie per Stm booleans. --- IntersTriaTria.cpp | 6 +- StmFromCurves.cpp | 98 ++++++++++++++ SurfTriMeshBooleans.cpp | 267 ++++++++++++++++++++++----------------- SurfTriMeshUtilities.cpp | 2 +- Triangulate.cpp | 2 +- 5 files changed, 253 insertions(+), 122 deletions(-) diff --git a/IntersTriaTria.cpp b/IntersTriaTria.cpp index 9da4969..40a4e7a 100644 --- a/IntersTriaTria.cpp +++ b/IntersTriaTria.cpp @@ -119,12 +119,12 @@ IntersTriaTria( const Triangle3d& trTria1, const Triangle3d& trTria2, Point3d& p Point3d ptSt1, ptEn1 ; int nRes1 = IntersCoplanarLineTria( ptL, vtL, 100.0, trTria1, ptSt1, ptEn1, false) ; - // limito la liena di intersezione con il secondo triangolo + // limito la linea di intersezione con il secondo triangolo Point3d ptSt2, ptEn2 ; int nRes2 = IntersCoplanarLineTria( ptL, vtL, 100.0, trTria2, ptSt2, ptEn2, false) ; // eseguo classificazione - double dIntStU, dIntEnU; + double dIntStU, dIntEnU ; int nIntType = FindTriaTriaIntersType( trTria1, trTria2, ptL, vtL, ( ptSt1 - ptL) * vtL, ( ptEn1 - ptL) * vtL, ( ptSt2 - ptL) * vtL, ( ptEn2 - ptL) * vtL, @@ -234,7 +234,7 @@ int FindTriaTriaIntersType( const Triangle3d& trTria1, const Triangle3d& trTria2, const Point3d& ptLineSt, const Vector3d& vtLineDir, double dStU1, double dEnU1, double dStU2, double dEnU2, int nRes1, int nRes2, double& dIntStU, double& dIntEnU) { - // Controllo su validit� input + // Controllo su validità input if ( ! ( trTria1.IsValid() && trTria2.IsValid() && vtLineDir.IsNormalized())) return ITTT_NO ; // Casi diff --git a/StmFromCurves.cpp b/StmFromCurves.cpp index cb52072..ff13106 100644 --- a/StmFromCurves.cpp +++ b/StmFromCurves.cpp @@ -26,6 +26,7 @@ #include #include #include +#include using namespace std ; @@ -817,5 +818,102 @@ CalcRegionPolyLines( const CICURVEPVECTOR& vpCurve, double dLinTol, 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()) ; + 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 ; + // 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) ; + } + + // creo una matrice di interi ; ogni riga corrisponde ad un chunk, dove in posizione 0 c'è il loop esterno e nelle + // successive i loop interni + INTMATRIX vnPLIndMat ; + + // aggiungo le diverse curve + bool bExtLoop = false ; + bool bFirstCrv ; + Plane3d plExtLoop ; + 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 ; + // inverto se necessario + if ( m_vArea[i].second < EPS_SMALL) { + vPL[j].Invert() ; + vCrvCompo[j]->Invert() ; + } + 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 * m_vArea[vnPLIndMat.back().front()].second) > 0.) { + vPL[j].Invert() ; + vCrvCompo[j]->Invert() ; + } + } + } + } + } while ( ! bFirstCrv) ; + return true ; } diff --git a/SurfTriMeshBooleans.cpp b/SurfTriMeshBooleans.cpp index 8303cdb..0a4fd8c 100644 --- a/SurfTriMeshBooleans.cpp +++ b/SurfTriMeshBooleans.cpp @@ -53,9 +53,10 @@ SurfTriMesh::DecomposeLoop( CHAINVECTOR& cvOpenChain, INTVECTOR& vnDegVec, PNTMA if ( vnDegVec[nC] > 0) ++ nExistNotDeg ; } + // Divido il loop di partenza in sotto-loop int nIterationCount = 0 ; - while ( cvOpenChain.size() > 0) { + while ( cvOpenChain.size() > 0) { // per ogni catena aperta... bool bLoopSplitted = false ; int nLastOpenLoopN = int( cvOpenChain.size()) - 1 ; if ( vnDegVec[nLastOpenLoopN] == 1) { @@ -64,13 +65,24 @@ SurfTriMesh::DecomposeLoop( CHAINVECTOR& cvOpenChain, INTVECTOR& vnDegVec, PNTMA int nLastOpenLoopPoint = max( int( cvOpenChain[nLastOpenLoopN].size()) - 1, 0) ; Point3d ptOpenLoopStP = cvOpenChain[nLastOpenLoopN][0].ptSt ; Point3d ptOpenLoopEnP = cvOpenChain[nLastOpenLoopN][nLastOpenLoopPoint].ptEn ; + // costruisco il primo e il secondo loop che si generano + // NB. il loop esterno è chiuso, mentre la catena aperta + // è la successione dei tratti lineari dovuti ai triangoli dell'altra superficie PNTVECTOR Loop1, Loop2 ; + // cambio il punto iniziale del loop di bordo se non coincide già con ptStart della catena aperta bool bChangedStart = ChangeStart( ptOpenLoopStP, cvBoundClosedLoopVec[nLoop]) ; + // splitto bool bSplitted = SplitAtPoint( ptOpenLoopEnP, cvBoundClosedLoopVec[nLoop], Loop1, Loop2) ; if ( ! ( bChangedStart && bSplitted) || ( nLastOpenLoopPoint == 0 && ( Loop1.size() == 2 || Loop2.size() == 2))) - continue ; + 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 bLoopSplitted = true ; + // ricostrusico i due loop mediante concatenazione Chain cvCounterChain ; for ( int nPt = int( cvOpenChain[nLastOpenLoopN].size()) - 1 ; nPt >= 0 ; -- nPt) { IntSegment CurSeg ; @@ -182,7 +194,7 @@ SurfTriMesh::DecomposeLoop( CHAINVECTOR& cvOpenChain, INTVECTOR& vnDegVec, PNTMA // elimino i punti superflui prima for ( int i = 0 ; i < nCvFirst ; ++ i) cvBoundClosedLoopVec[nLoop].erase( cvBoundClosedLoopVec[nLoop].begin()) ; - // verifico se questo punto � dalla parte valida o no + // verifico se questo punto è dalla parte valida o no bool bC12 = ( ( ptM12 - ptProva) * vtVecProva < 0) ; vbInOut[nLoop] = bC12 ; } @@ -193,7 +205,7 @@ SurfTriMesh::DecomposeLoop( CHAINVECTOR& cvOpenChain, INTVECTOR& vnDegVec, PNTMA // elimino i punti superflui intermedi for ( int i = nCvFirst + 2 ; i < nCvSecond ; ++ i) cvBoundClosedLoopVec[nLoop].erase( cvBoundClosedLoopVec[nLoop].begin() + nCvFirst + 2) ; - // verifico se questo punto � dalla parte valida o no + // verifico se questo punto è dalla parte valida o no bool bC21 = ( ( ptM21 - ptProva) * vtVecProva < 0) ; vbInOut[nLoop] = bC21 ; } @@ -235,9 +247,13 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT // La superficie deve essere valida if ( ! Surf.IsValid()) return false ; - // Ritriangolarizzo i triangoli + + // itero sulla unorderd_map for ( auto it = LoopLines.begin() ; it != LoopLines.end() ; ++ it) { + + // itero sulle catene ( secondo parametro della mappa) for ( int nS1 = 0 ; nS1 < int( it->second.size()) - 1 ; ++ nS1) { + // tolgo i tratti degeneri ad un punto for ( int nS2 = nS1 + 1 ; nS2 < int( it->second.size()) ; ++ nS2) { if ( AreSamePointApprox( it->second[nS1].ptSt, it->second[nS2].ptEn) && AreSamePointApprox( it->second[nS1].ptEn, it->second[nS2].ptSt) && @@ -249,22 +265,21 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT } } } - + // se non resta nulla, allora passo alla mappa successiva if ( int( it->second.size()) == 0) continue ; + // Se il triangolo è stato sottoposto a ritriangolazione, le sue componenti sono classificabili come dentro-fuori. // Lo tolgo dall'insieme dei triangoli ambigui (intersezione edge-edge) - else { - auto itS = Ambiguos.find( it->first) ; - if ( itS != Ambiguos.end()) { - Ambiguos.erase( itS) ; - } - } + auto itS = Ambiguos.find( it->first) ; + if ( itS != Ambiguos.end()) + Ambiguos.erase( itS) ; - // Creo i loop + // CREAZIONE DEI LOOP --------------------------------------------- + // Chain ChainCurves LoopCreator ; LoopCreator.Init( false, 2 * EPS_SMALL, int( it->second.size()), 10 * BOOLEAN_SCALE) ; - // Carico le curve per concatenarle + // Recupero le curve ( gli estremi dei tratti lineari) per concatenarle for ( int nCv = 0 ; nCv < int( it->second.size()); ++ nCv) { Point3d ptSt = it->second[nCv].ptSt ; Point3d ptEn = it->second[nCv].ptEn ; @@ -278,15 +293,14 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT CHAINVECTOR vChain ; while ( LoopCreator.GetChainFromNear( ptNearStart, false, vIds)) { Chain chTemp ; - for ( auto i : vIds) { - // Aggiungo la linea alla curva composta. + for ( auto i : vIds) // Aggiungo la linea alla curva composta chTemp.emplace_back( it->second[i - 1]) ; - } + vChain.emplace_back( chTemp) ; } // Lavoro su loop e catene per regolarizzarle int nChainCnt = int( vChain.size()) ; - // unisco eventuali catene estreme che sono parte di una stessa catena + // Unisco eventuali catene estreme che sono parte di una stessa catena if ( nChainCnt > 1) { if ( AreSamePointApprox( vChain[0].front().ptSt, vChain[nChainCnt - 1].back().ptEn)) { vChain[0].insert( vChain[0].begin(), vChain[nChainCnt - 1].begin(), vChain[nChainCnt - 1].end()) ; @@ -299,7 +313,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT -- nChainCnt ; } } - // semplifico catene formate da punti degeneri + // Semplifico catene formate da punti degeneri for ( int nCh = 0 ; nCh < nChainCnt ; ++ nCh) { if ( vChain[nCh].size() == 2 && ( vChain[nCh][0].bDegenerate || vChain[nCh][1].bDegenerate)) { vChain[nCh][0].ptEn = vChain[nCh][1].ptEn ; @@ -378,6 +392,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT } } } + // Chiudo i loop costruiti a partire dalle catene for ( int nC = 0 ; nC < nChainCnt ; ++ nC) { int nChainLastSegPos = int( vChain[nC].size()) - 1 ; @@ -464,7 +479,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT Surf.m_vTria[nNewAloneTriaNum].nETempFlag[0] = 0 ; Surf.m_vTria[nNewAloneTriaNum].nETempFlag[1] = 0 ; Surf.m_vTria[nNewAloneTriaNum].nETempFlag[2] = 0 ; - Surf.m_vTria[nNewAloneTriaNum].nTempPart = nDist[nAloneVert] ; + Surf.m_vTria[nNewAloneTriaNum].nTempPart = nDist[nAloneVert] ; bModif = true ; } int nNewCoupleId1[3] = { Surf.AddVertex( ptIntSt), Surf.AddVertex( trTria.GetP( ( nAloneVert + 1) % 3)), Surf.AddVertex( trTria.GetP( ( nAloneVert + 2) % 3)) } ; @@ -473,7 +488,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT Surf.m_vTria[nNewCoupleTriaNum1].nETempFlag[0] = 0 ; Surf.m_vTria[nNewCoupleTriaNum1].nETempFlag[1] = 0 ; Surf.m_vTria[nNewCoupleTriaNum1].nETempFlag[2] = 0 ; - Surf.m_vTria[nNewCoupleTriaNum1].nTempPart = - nDist[nAloneVert] ; + Surf.m_vTria[nNewCoupleTriaNum1].nTempPart = - nDist[nAloneVert] ; bModif = true ; } int nNewCoupleId2[3] = { Surf.AddVertex( ptIntSt), Surf.AddVertex( trTria.GetP( ( nAloneVert + 2) % 3)), Surf.AddVertex( ptIntEn) } ; @@ -482,27 +497,32 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT Surf.m_vTria[nNewCoupleTriaNum2].nETempFlag[0] = 0 ; Surf.m_vTria[nNewCoupleTriaNum2].nETempFlag[1] = 0 ; Surf.m_vTria[nNewCoupleTriaNum2].nETempFlag[2] = 0 ; - Surf.m_vTria[nNewCoupleTriaNum2].nTempPart = - nDist[nAloneVert] ; + Surf.m_vTria[nNewCoupleTriaNum2].nTempPart = - nDist[nAloneVert] ; bModif = true ; } continue ; } } } + // ------------------------------------------------------------------------------------------- - // 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. + + // 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. PNTVECTOR cvFirstLoop ; cvFirstLoop.emplace_back( trTria.GetP( 0)) ; cvFirstLoop.emplace_back( trTria.GetP( 1)) ; cvFirstLoop.emplace_back( trTria.GetP( 2)) ; - PNTMATRIX cvBoundClosedLoopVec; + // creo una matrice di punti ; ogni riga corrisponde ad una sequenza di punti che indentificano un loop + PNTMATRIX cvBoundClosedLoopVec ; cvBoundClosedLoopVec.emplace_back( cvFirstLoop) ; + + // vettore per indicare se il loop è interno/esterno all'altra superficie BOOLVECTOR vbInOut ; vbInOut.push_back( true) ; + // Divido il loop usando le catene if ( ! DecomposeLoop( cvOpenChain, vnDegVec, cvBoundClosedLoopVec, vbInOut)) { if ( cvBoundClosedLoopVec.size() == 1 && cvOpenChain.size() == 2) { @@ -557,7 +577,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT Surf.m_vTria[it->first].nTempPart = 0 ; continue ; } - } + } // Rimuovo il triangolo corrente int nOldTriaCol = Surf.m_vTria[it->first].nTFlag ; Surf.RemoveTriangle( it->first) ; @@ -565,14 +585,14 @@ 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) { + for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) ; ++ nLine) vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][nLine]) ; - } + vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][0]) ; // 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 nodi corrispondente a un // loop è figlio del nodo corrispondente al loop che lo contiene. INTVECTOR vInnerLoop ; for ( int nCLI = 0 ; nCLI < int( cvClosedChain.size()) ; ++ nCLI) { @@ -693,7 +713,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT break ; } } - + if ( vInnerLoop.size() == 0 || bDouble) { // Eseguo triangolazione PNTVECTOR vPt ; @@ -711,7 +731,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT Surf.m_vTria[nNewTriaNum].nETempFlag[1] = 0 ; Surf.m_vTria[nNewTriaNum].nETempFlag[2] = 0 ; if ( vbInOut[nLoop]) - Surf.m_vTria[nNewTriaNum].nTempPart = 1 ; + Surf.m_vTria[nNewTriaNum].nTempPart = 1 ; else Surf.m_vTria[nNewTriaNum].nTempPart = - 1 ; bModif = true ; @@ -720,33 +740,32 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT } } else { + // 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 ; - for ( int nV = 0 ; nV < int( cvClosedChain[vInnerLoop[nL]].size()) ; ++ nV) { + for ( int nV = 0 ; nV < int( cvClosedChain[vInnerLoop[nL]].size()) ; ++ nV) CurLoop.AddUPoint( 0., cvClosedChain[vInnerLoop[nL]][nV].ptSt) ; - } + CurLoop.AddUPoint( 0., cvClosedChain[vInnerLoop[nL]][0].ptSt) ; vPolygons.emplace_back( CurLoop) ; } + // poligono Polygon3d pgPol ; pgPol.FromPolyLine( vPolygons[1]) ; + // controllo direzioni delle normali bool bCodirectedNormals = trTria.GetN() * pgPol.GetVersN() > 0. ; - //if ( bCodirectedNormals) { - // for ( int nL = 1 ; nL < int( vPolygons.size()) ; ++ nL) { - // vPolygons[nL].Invert() ; - // } - //} pizza // Aggiungo al loop esterno i punti dei loop interni che si trovano su di esso PNTULIST& ExternLoopList = vPolygons[0].GetUPointList() ; // Ciclo sui segmenti del loop esterno auto itSt = ExternLoopList.begin() ; auto itEn = itSt ; - ++ itEn ; + ++ itEn ; for ( ; itSt != ExternLoopList.end() && itEn != ExternLoopList.end() ; ++ itSt, ++ itEn) { // Estremi del segmento corrente del loop esterno e scorrispondente vettore Point3d ptSt = itSt->first ; @@ -762,7 +781,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT Point3d ptInnPoint ; bool bIsFirst = true ; bool bContinue = vPolygons[nInnPoly].GetFirstPoint( ptInnPoint) ; - while ( bContinue) { + while ( bContinue) { DistPointLine DistCalculator( ptInnPoint, ptSt, ptEn) ; double dDist ; DistCalculator.GetDist( dDist) ; @@ -794,8 +813,9 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT PNTVECTOR vPt ; INTVECTOR vTr ; + // classifico i loop e ricavo la triangolazione di essi mediante classificazione if ( Triangulate().MakeAdvanced( vPolygons, vPt, vTr)) { - // Inserisco i nuovi triangoli + // Inserisco i nuovi 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] = { Surf.AddVertex( vPt[nNewTriaVertId[0]]), @@ -818,7 +838,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT // Divido i loop che si autointercettano int nInitialLoopNum = int( vPolygons.size()) ; for ( int nL = 1 ; nL < nInitialLoopNum ; ++ nL) { - // Lista dei punti della PolyLine Loop corrente + // Lista dei punti della PolyLine Loop corrente PNTULIST& LoopPointList = vPolygons[nL].GetUPointList() ; // Ciclo sui segmenti auto itSt2 = LoopPointList.begin() ; @@ -929,31 +949,27 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT } } } - // pizza - //for ( int nL = 1 ; nL < int( vPolygons.size()) ; ++ nL) { - // vPolygons[nL].Invert() ; - vPolygons.erase( vPolygons.begin()) ; - if ( Triangulate().MakeAdvanced( vPolygons, vPt, vTr)) { - // Inserisco i nuovi 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] = { Surf.AddVertex( vPt[nNewTriaVertId[0]]), - Surf.AddVertex( vPt[nNewTriaVertId[1]]), - Surf.AddVertex( vPt[nNewTriaVertId[2]])} ; - int nNewTriaNum = Surf.AddTriangle( nNewId, nOldTriaCol) ; - if ( IsValidSvt( nNewTriaNum)) { - Surf.m_vTria[nNewTriaNum].nETempFlag[0] = 0 ; - Surf.m_vTria[nNewTriaNum].nETempFlag[1] = 0 ; - Surf.m_vTria[nNewTriaNum].nETempFlag[2] = 0 ; - if ( bCodirectedNormals) - Surf.m_vTria[nNewTriaNum].nTempPart = 1 ; - else - Surf.m_vTria[nNewTriaNum].nTempPart = -1 ; - bModif = true ; - } + vPolygons.erase( vPolygons.begin()) ; + if ( Triangulate().MakeAdvanced( vPolygons, vPt, vTr)) { + // Inserisco i nuovi 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] = { Surf.AddVertex( vPt[nNewTriaVertId[0]]), + Surf.AddVertex( vPt[nNewTriaVertId[1]]), + Surf.AddVertex( vPt[nNewTriaVertId[2]])} ; + int nNewTriaNum = Surf.AddTriangle( nNewId, nOldTriaCol) ; + if ( IsValidSvt( nNewTriaNum)) { + Surf.m_vTria[nNewTriaNum].nETempFlag[0] = 0 ; + Surf.m_vTria[nNewTriaNum].nETempFlag[1] = 0 ; + Surf.m_vTria[nNewTriaNum].nETempFlag[2] = 0 ; + if ( bCodirectedNormals) + Surf.m_vTria[nNewTriaNum].nTempPart = 1 ; + else + Surf.m_vTria[nNewTriaNum].nTempPart = -1 ; + bModif = true ; } } - //} + } } vInnerLoop.resize( 0) ; } @@ -1091,18 +1107,23 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) { bool bModif = false ; SurfTriMesh& SurfB = Other ; + // Le superfici devono essere valide if ( m_nStatus != OK || ! SurfB.IsValid()) return false ; + // Unordered map dei segmenti di intersezione CHAINMAP LineMapA ; CHAINMAP LineMapB ; + // Unordered map dei triangoli ambigui (intersezione edge-edge) TRIA3DVECTORMAP AmbiguosA ; TRIA3DVECTORMAP AmbiguosB ; + // Ciclo sui triangoli delle mesh int nTriaNumA = GetTriangleSize() ; int nTriaNumB = SurfB.GetTriangleSize() ; + // Setto il triangolo come né fuori né dentro for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) { m_vTria[nTA].nTempPart = 0 ; @@ -1116,55 +1137,58 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) SurfB.m_vTria[nTB].nETempFlag[1] = 0 ; SurfB.m_vTria[nTB].nETempFlag[2] = 0 ; } + // Resetto e ricalcolo la HashGrid della superficie B SurfB.ResetHashGrids3d() ; + + // Scorro i triangoli della superficie A for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) { + // Se il triangolo A non è valido, continuo Triangle3d trTriaA ; if ( ! GetTriangle( nTA, trTriaA) || ! trTriaA.Validate( true)) continue ; + // Box del triangolo A BBox3d b3dTriaA ; trTriaA.GetLocalBBox( b3dTriaA) ; + // Recupero i triangoli di B che interferiscono col box del triangolo di A INTVECTOR vNearTria ; SurfB.GetAllTriaOverlapBox( b3dTriaA, vNearTria) ; + + // I scorro tutti i triangoli di B che intersecano il box di A for ( int nTB = 0 ; nTB < int( vNearTria.size()) ; ++ nTB) { + // Se il triangolo B non è valido, continuo Triangle3d trTriaB ; if ( ! SurfB.GetTriangle( vNearTria[nTB], trTriaB) || ! trTriaB.Validate( true)) continue ; + // Interseco i triangoli Point3d ptSegSt, ptSegEn ; TRIA3DVECTOR vTria ; int nIntType = IntersTriaTria( trTriaA, trTriaB, ptSegSt, ptSegEn, vTria) ; - if ( nIntType == ITTT_EDGE_EDGE_SEG || - nIntType == ITTT_EDGE_INT || - nIntType == ITTT_INT_EDGE || - nIntType == ITTT_INT_INT_SEG) { - // Assegno i dati di intersezione + + // se l'intersezione è identificabile con un segmento... + if ( nIntType == ITTT_EDGE_EDGE_SEG || nIntType == ITTT_EDGE_INT || + nIntType == ITTT_INT_EDGE || nIntType == ITTT_INT_INT_SEG) { + + // Assegno i dati di intersezione per la superficie A IntSegment CurInters ; - if ( nIntType == ITTT_EDGE_EDGE_SEG || nIntType == ITTT_EDGE_INT || - nIntType == ITTT_INT_EDGE || nIntType == ITTT_INT_INT_SEG) { - CurInters.ptSt = ptSegSt ; - CurInters.ptEn = ptSegEn ; - CurInters.bDegenerate = false ; - } - else { - CurInters.ptSt = ptSegSt ; - CurInters.ptEn = ptSegSt ; - CurInters.bDegenerate = true ; - } - CurInters.vtOuter = trTriaB.GetN() ; + CurInters.ptSt = ptSegSt ; // punto iniziale del segmento + CurInters.ptEn = ptSegEn ; // punto finale del segmento + CurInters.bDegenerate = false ; // segmento non degenere + CurInters.vtOuter = trTriaB.GetN() ; // perpendicolare alla tangente ( oritentata ) CurInters.vtOuter -= ( ( CurInters.vtOuter * trTriaA.GetN()) * trTriaA.GetN()) ; CurInters.vtOuter.Normalize() ; // Salvo intersezione per superficie A bool bIntOnEndgeA = false ; if ( nIntType != ITTT_EDGE_EDGE_SEG && nIntType != ITTT_EDGE_INT) { + // controllo se tale segmento non è già contenuto auto itA = LineMapA.find( nTA) ; - if ( itA != LineMapA.end()) { + if ( itA != LineMapA.end()) itA->second.emplace_back( CurInters) ; - } else { Chain chTemp ; chTemp.emplace_back( CurInters) ; @@ -1174,6 +1198,7 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) else bIntOnEndgeA = true ; + // Inverto i dati del segmento per intersezione con superficie B swap( CurInters.ptSt, CurInters.ptEn) ; CurInters.vtOuter = trTriaA.GetN() ; CurInters.vtOuter -= ( ( CurInters.vtOuter * trTriaB.GetN()) * trTriaB.GetN()) ; @@ -1182,10 +1207,10 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) // Salvo intersezione per superficie B bool bIntOnEndgeB = false ; if ( nIntType != ITTT_EDGE_EDGE_SEG && nIntType != ITTT_INT_EDGE) { + // controllo se tale segmento non è già contenuto auto itB = LineMapB.find( vNearTria[nTB]) ; - if ( itB != LineMapB.end()) { + if ( itB != LineMapB.end()) itB->second.emplace_back( CurInters) ; - } else { Chain chTemp ; chTemp.emplace_back( CurInters) ; @@ -1194,8 +1219,10 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) } else bIntOnEndgeB = true ; - // Intersezione edge-interno + + // caso di Intersezione edge-interno ( per superificie A con B) if ( bIntOnEndgeA && ! bIntOnEndgeB) { + // calcolo la massima distanza e il tratto ad essa associato double dMaxDist = 0. ; int nSegMaxDist = - 1 ; for ( int nVA = 0 ; nVA < 3 ; ++ nVA) { @@ -1206,7 +1233,7 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) } } if ( nSegMaxDist >= 0) { - // Cerco qual'è il segmento di contatto per dichiararlo come invalicabile + // Cerco qual è il segmento di contatto per dichiararlo come invalicabile int nVA ; for ( nVA = 0 ; nVA < 3 ; ++ nVA) { if ( abs( ( trTriaA.GetP( nVA) - trTriaB.GetP( 0)) * trTriaB.GetN()) < EPS_SMALL && @@ -1218,8 +1245,9 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) m_vTria[nTA].nETempFlag[nVA] = m_vTria[nTA].nTempPart ; } } - // Intersezione interno-edge + // caso di Intersezione interno-edge ( per superficie A con B) else if ( ! bIntOnEndgeA && bIntOnEndgeB) { + // calcolo la massima distanza e il tratto ad essa associato double dMaxDist = 0. ; int nSegMaxDist = - 1 ; for ( int nVB = 0 ; nVB < 3 ; ++ nVB) { @@ -1230,7 +1258,7 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) } } if ( nSegMaxDist >= 0) { - // Cerco qual'è il segmento di contatto per dichiararlo come invalicabile + // Cerco qual è il segmento di contatto per dichiararlo come invalicabile int nVB ; for ( nVB = 0 ; nVB < 3 ; ++ nVB) { if ( abs( ( trTriaB.GetP( nVB) - trTriaA.GetP(0)) * trTriaA.GetN()) < EPS_SMALL && @@ -1269,11 +1297,14 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) } } } - + // Ritriangolarizzo i triangoli delle superfici RetriangulationForBooleanOperation( LineMapA, AmbiguosA, *this, bModif) ; RetriangulationForBooleanOperation( LineMapB, AmbiguosB, SurfB, bModif) ; - + + SaveGeoObj( this->Clone(), "C:\\Users\\riccardo.elitropi\\Desktop\\SurfA.nge") ; + SaveGeoObj( SurfB.Clone(), "C:\\Users\\riccardo.elitropi\\Desktop\\SurfB.nge") ; + // Se i triangoli delle superfici non si intersecano, una delle due è totalmente interna o esterna all'altra. // non mi basta fare un controllo sulle bbox perché non so come sono orientate le superfici e che potrebbero anche non essere chiuse bool bRetriangulated = true ; @@ -1312,7 +1343,7 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) if ( ( ptFirstV - trTriaB.GetP(0)) * trTriaB.GetN() < - EPS_SMALL) { if ( nInOutNum == 0) nInOutNum = 1 ; - else if (nInOutNum == -1) { + else if ( nInOutNum == -1) { bSame = false ; break ; } @@ -1320,7 +1351,7 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) else if ( ( ptFirstV - trTriaB.GetP(0)) * trTriaB.GetN() > EPS_SMALL) { if ( nInOutNum == 0) nInOutNum = -1 ; - else if (nInOutNum == 1) { + else if ( nInOutNum == 1) { bSame = false ; break ; } @@ -1328,23 +1359,23 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) } // se le informazioni date dalle normali dei triangoli non sono concordi valuto il triangolo più vicino // e ricalcolo l'informazione che mi dà la sua normale - if ( ! bSame ) { + if ( ! bSame) { Point3d ptBar_tot ; for (int nTriaNum : vnTriaNum) { SurfB.GetTriangle( nTriaNum, trTriaB) ; ptBar_tot += trTriaB.GetCentroid(); } - ptBar_tot /= (int)vnTriaNum.size() ; - for (int nTriaNum : vnTriaNum) { + ptBar_tot /= int( vnTriaNum.size()) ; + for ( int nTriaNum : vnTriaNum) { SurfB.GetTriangle( nTriaNum, trTriaB) ; Point3d ptInters1, ptInters2 ; - int nInters = IntersLineTria(ptFirstV, ptBar_tot, trTriaB, ptInters1, ptInters2, true) ; - if (nInters == ILTT_NO) + int nInters = IntersLineTria( ptFirstV, ptBar_tot, trTriaB, ptInters1, ptInters2, true) ; + if ( nInters == ILTT_NO) continue ; - else if ( nInters == ILTT_IN ) { - if ( ( ptFirstV - trTriaB.GetP(0)) * trTriaB.GetN() < - EPS_SMALL) + else if ( nInters == ILTT_IN) { + if ( ( ptFirstV - trTriaB.GetP( 0)) * trTriaB.GetN() < - EPS_SMALL) nInOutNum = 1 ; - else if ( ( ptFirstV - trTriaB.GetP(0)) * trTriaB.GetN() > EPS_SMALL) + else if ( ( ptFirstV - trTriaB.GetP( 0)) * trTriaB.GetN() > EPS_SMALL) nInOutNum = -1 ; break ; } @@ -1358,9 +1389,10 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) ++ nVertNum ; } } - for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) { + + for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) m_vTria[nTA].nTempPart = nInOutNum ; - } + nVertNum = 0 ; nCurVert = SurfB.GetFirstVertex( ptFirstV) ; nInOutNum = 0 ; @@ -1377,7 +1409,7 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) DistCalculator.GetDist( dDist) ; // potrei trovare più triangolo equidistanti, li salvo tutti if ( DistPointTriangle( ptFirstV, trTriaA).GetDist( dDist)) { - if ( abs(dDist - dMinDist) < EPS_SMALL) + if ( abs( dDist - dMinDist) < EPS_SMALL) vnTriaNum.push_back( nTA) ; else if ( dDist < dMinDist){ vnTriaNum.clear() ; @@ -1395,7 +1427,7 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) if ( ( ptFirstV - trTriaA.GetP(0)) * trTriaA.GetN() < - EPS_SMALL) { if ( nInOutNum == 0) nInOutNum = 1 ; - else if (nInOutNum == -1) { + else if ( nInOutNum == -1) { bSame = false ; break ; } @@ -1403,7 +1435,7 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) else if ( ( ptFirstV - trTriaA.GetP(0)) * trTriaA.GetN() > EPS_SMALL) { if ( nInOutNum == 0) nInOutNum = -1 ; - else if (nInOutNum == 1) { + else if ( nInOutNum == 1) { bSame = false ; break ; } @@ -1411,17 +1443,17 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) } // se le informazioni date dalle normali dei triangoli non sono concordi valuto il triangolo più vicino // e ricalcolo l'informazione che mi dà la sua normale - if ( ! bSame ) { + if ( ! bSame) { Point3d ptBar_tot ; for (int nTriaNum : vnTriaNum) { GetTriangle( nTriaNum, trTriaA) ; ptBar_tot += trTriaA.GetCentroid(); } ptBar_tot /= (int)vnTriaNum.size() ; - for (int nTriaNum : vnTriaNum) { + for ( int nTriaNum : vnTriaNum) { GetTriangle( nTriaNum, trTriaA) ; Point3d ptInters1, ptInters2 ; - int nInters = IntersLineTria(ptFirstV, ptBar_tot, trTriaA, ptInters1, ptInters2, true) ; + int nInters = IntersLineTria( ptFirstV, ptBar_tot, trTriaA, ptInters1, ptInters2, true) ; if (nInters == ILTT_NO) continue ; else if ( nInters == ILTT_IN ) { @@ -1441,9 +1473,8 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) ++ nVertNum ; } } - for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) { + for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) SurfB.m_vTria[nTB].nTempPart = nInOutNum ; - } } // Se c'è stata una ritriangolazione di almeno un triangolo, NON siamo nel caso di tutto dentro o tutto fuori. @@ -1452,12 +1483,11 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) AmbiguosTriangleManager( AmbiguosA, *this) ; AmbiguosTriangleManager( AmbiguosB, SurfB) ; } - + bool bContinue = true ; // Se avvenuta modifica, aggiorno tutto if ( bModif) bContinue = ( AdjustVertices() && DoCompacting() && SurfB.AdjustVertices() && SurfB.DoCompacting()) ; - SaveGeoObj( this, "C:\\Users\\riccardo.elitropi\\Desktop\\PocketingVolumi\\a.nge") ; // Triangoli sovrapposti if ( bContinue) { int nTriaNum2A = GetTriangleSize() ; @@ -1495,7 +1525,9 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) } return true ; } - + SaveGeoObj( this, "C:\\Users\\riccardo.elitropi\\Desktop\\SurfA.nge") ; + SaveGeoObj( SurfB.Clone(), "C:\\Users\\riccardo.elitropi\\Desktop\\SurfB.nge") ; + return true ; } @@ -1641,6 +1673,7 @@ SurfTriMesh::Intersect( const ISurfTriMesh& Other) if ( m_vTria[nTA].nTempPart == - 1 || m_vTria[nTA].nTempPart == - 2) RemoveTriangle( nTA) ; } + int nPrevMaxTFlag = m_nMaxTFlag ; int nTriaNumB = SurfB.GetTriangleSize() ; for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) { diff --git a/SurfTriMeshUtilities.cpp b/SurfTriMeshUtilities.cpp index c09cf0a..99999fb 100644 --- a/SurfTriMeshUtilities.cpp +++ b/SurfTriMeshUtilities.cpp @@ -531,7 +531,7 @@ SurfTriMesh::AddChainToChain( const Chain& ChainToAdd, PNTVECTOR& OrigChain) if ( AreSamePointApprox( OrigChain[nLastOrig], ChainToAdd[0].ptSt)) { for ( int nPt = 1 ; nPt <= nLastToAdd ; ++ nPt) { if ( nPt == nLastToAdd) { - if ( ! AreSamePointApprox(OrigChain[0], ChainToAdd[nPt].ptSt)) + if ( ! AreSamePointApprox( OrigChain[0], ChainToAdd[nPt].ptSt)) OrigChain.emplace_back( ChainToAdd[nPt].ptSt) ; } else if ( nPt == 1) { diff --git a/Triangulate.cpp b/Triangulate.cpp index 2eea13d..ca36794 100644 --- a/Triangulate.cpp +++ b/Triangulate.cpp @@ -328,7 +328,7 @@ Triangulate::MakeAdvanced( const POLYLINEVECTOR& vPLORIG, PNTVECTOR& vPt, INTVEC vnPLIndMat.back().push_back( j) ; m_vArea[i].first = -1 ; // inverto se necessario - if ( m_vArea[i].second > - EPS_SMALL) { + if (( m_vArea[i].second * m_vArea[vnPLIndMat.back().front()].second) > 0.) { vPL[j].Invert() ; vCrvCompo[j]->Invert() ; }