//---------------------------------------------------------------------------- // 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 "/EgtDev/Include/EGkGeoCollection.h" #include using namespace std ; //---------------------------------------------------------------------------- // Struttura segmento di intersezione struct IntSegment { Point3d ptSt ; Point3d ptEn ; Vector3d vtOuter ; bool bDegenerate ; } ; // Tipo chain typedef vector Chain ; // Tipo vettore di Chain typedef vector CHAINVECTOR ; //---------------------------------------------------------------------------- int IntersRectangleTriangle( const Point3d& ptP, const Vector3d& vtL1, const Vector3d& vtL2, const Triangle3d& trTria, Point3d& ptStSeg, Point3d& ptEnSeg) { // Definisco i due triangoli formanti il rettangolo Triangle3d trTriaA ; trTriaA.Set( ptP, ptP + vtL1, ptP + vtL2) ; if ( ! trTriaA.Validate()) return -1 ; Triangle3d trTriaB ; trTriaB.Set( ptP + vtL1, ptP + vtL1 + vtL2, ptP + vtL2) ; if ( ! trTriaB.Validate()) return -1 ; // Interseco il triangolo con il primo dei due triangoli del rettangolo int nIntA = 0 ; Point3d ptIntA1, ptIntA2 ; TRIA3DVECTOR vTriaA ; int nIntTypeA = IntersTriaTria( trTria, trTriaA, ptIntA1, ptIntA2, vTriaA) ; if ( nIntTypeA == ITTT_PNT || nIntTypeA == ITTT_VERT) nIntA = 1 ; else if ( nIntTypeA == ITTT_YES || nIntTypeA == ITTT_EDGE) { nIntA = 2 ; } // Interseco il triangolo con il secondo dei due triangoli del rettangolo int nIntB = 0 ; Point3d ptIntB1, ptIntB2 ; TRIA3DVECTOR vTriaB ; int nIntTypeB = IntersTriaTria( trTria, trTriaB, ptIntB1, ptIntB2, vTriaB) ; if ( nIntTypeB == ITTT_PNT || nIntTypeB == ITTT_VERT) nIntB = 1 ; else if ( nIntTypeB == ITTT_YES || nIntTypeB == ITTT_EDGE) { nIntB = 2 ; } // Unisco le due intersezioni int nIntTot = nIntA + nIntB ; if ( nIntTot == 4) { if ( AreSamePointApprox( ptIntA2, ptIntB1)) { ptStSeg = ptIntA1 ; ptEnSeg = ptIntB2 ; } else { ptStSeg = ptIntB1 ; ptEnSeg = ptIntA2 ; } return 2 ; } else if ( nIntTot == 3) { if ( nIntA == 2) { ptStSeg = ptIntA1 ; ptEnSeg = ptIntA2 ; } else { ptStSeg = ptIntB1 ; ptEnSeg = ptIntB2 ; } return 2 ; } else if ( nIntTot == 2) { if ( nIntA == 2) { ptStSeg = ptIntA1 ; ptEnSeg = ptIntA2 ; } else if ( nIntA == 1) { ptStSeg = ptIntA1 ; ptEnSeg = ptIntB1 ; } else { ptStSeg = ptIntB1 ; ptEnSeg = ptIntB2 ; } return 2 ; } else if ( nIntTot == 1) { if ( nIntA == 1) ptStSeg = ptIntA1 ; else ptStSeg = ptIntB1 ; return 1 ; } else return 0 ; } //---------------------------------------------------------------------------- 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) || vtExtr.IsSmall() || ! cvCurve.IsClosed()) return false ; // Approssimo la curva con segmenti CurveComposite cvCompo ; PolyLine PL ; if ( ! cvCurve.ApproxWithLines( LIN_TOL_FINE, ANG_TOL_STD_DEG, ICurve::APL_STD, PL) || ! cvCompo.FromPolyLine( PL)) return false ; // Appiattisco la polilinea nel piano perpendicolare all'estrusione Frame3d frCurve ; Point3d ptStart ; cvCompo.GetStartPoint( ptStart) ; frCurve.Set( ptStart, vtExtr) ; cvCompo.ToLoc( frCurve) ; if ( ! cvCompo.Scale( GLOB_FRM, 1, 1, 0)) return false ; double dArea ; cvCompo.GetAreaXY( dArea) ; BBox3d b3Crv ; cvCompo.GetLocalBBox( b3Crv) ; cvCompo.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 ; if ( ! GetTriangle( nT, trTria)) continue ; // Ne calcolo una copia proiettata sul piano della curva // Box del triangolo nel riferimento locale della curva BBox3d b3Tria ; trTria.GetLocalBBox( b3Tria) ; b3Tria.ToLoc( frCurve) ; // Se il box del triangolo non interseca quello locale della curva if ( ! b3Crv.OverlapsXY( b3Tria)) { // Se la parte da conservare è quella all'interno della curva, elimino il triangolo if ( bCCW) { RemoveTriangle( nT) ; bModif = true ; } continue ; } // Determino il numero di vertici del triangolo che cadono all'interno della curva int nVertInside = 0 ; for ( int nV = 0 ; nV < 3 ; ++ nV) { // Determino se il vertice cade dentro la curva DistPointCurve dstPC( trTria.GetP( nV), cvCompo) ; int nSide ; dstPC.GetSideAtMinDistPoint( 0, vtExtr, nSide) ; if ( nSide == MDS_LEFT || nSide == MDS_ON) ++ nVertInside ; } // Vettore di catene di punti CHAINVECTOR vChain ; // Ciclo sui segmenti bool bStartInside = false ; int nChainCnt = 0 ; bool bChain = false ; Point3d ptChSt, ptChEn ; const ICurve* pCrv = cvCompo.GetFirstCurve() ; while ( pCrv != nullptr) { // estremi del segmento Point3d ptSt ; pCrv->GetStartPoint( ptSt) ; Point3d ptEn ; pCrv->GetEndPoint( ptEn) ; // Intersezione fra il rettangolo (ottenuto dall'estrusione del segmento corrente) e il triangolo Point3d ptSegSt, ptSegEn ; int nInt = IntersRectangleTriangle( ptSt + vtMin, ptEn - ptSt, vtMax - vtMin, trTria, ptSegSt, ptSegEn) ; if ( nInt != 0) { // Creo nuova catena se non c'è già o se discontinuità if ( ! bChain || ( ! AreSamePointApprox( ptSegSt, ptChEn) && ! AreSamePointApprox( ptSegEn, ptChSt))) { ++ nChainCnt ; vChain.resize( nChainCnt) ; bChain = false ; } // Assegno i dati di intersezione IntSegment CurInters ; if ( nInt == 2) { CurInters.ptSt = ptSegSt ; CurInters.ptEn = ptSegEn ; CurInters.bDegenerate = false ; } else { CurInters.ptSt = ptSegSt ; CurInters.ptEn = ptSegSt ; CurInters.bDegenerate = true ; } CurInters.vtOuter = ( ptEn - ptSt) ^ vtExtr ; CurInters.vtOuter.Normalize() ; // Inserisco nella catena if ( ! bChain) { vChain[nChainCnt - 1].emplace_back( CurInters) ; ptChSt = CurInters.ptSt ; ptChEn = CurInters.ptEn ; } else if ( AreSamePointApprox( ptSegSt, ptChEn)) { vChain[nChainCnt - 1].emplace_back( CurInters) ; ptChEn = CurInters.ptEn ; } else { vChain[nChainCnt - 1].insert( vChain[nChainCnt - 1].begin(), CurInters) ; ptChSt = CurInters.ptSt ; } bChain = true ; } else { bChain = false ; } pCrv = cvCompo.GetNextCurve() ; } // 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()) ; vChain.pop_back() ; -- nChainCnt ; } else if ( AreSamePointApprox( vChain[0].back().ptEn, vChain[nChainCnt-1].front().ptSt)) { vChain[0].insert( vChain[0].end(), vChain[nChainCnt-1].begin(), vChain[nChainCnt-1].end()) ; vChain.pop_back() ; -- nChainCnt ; } } // 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 ; vChain[nCh][0].vtOuter = ( vChain[nCh][0].bDegenerate ? vChain[nCh][1].vtOuter : vChain[nCh][0].vtOuter) ; vChain[nCh][0].bDegenerate = AreSamePointApprox( vChain[nCh][0].ptSt, vChain[nCh][0].ptEn) ; vChain[nCh].resize( 1) ; } } // Elimino la seconda copia di catene doppie for ( int nI = 0 ; nI < nChainCnt ; ++ nI) { for ( int nJ = nI + 1 ; nJ < nChainCnt ; ++ nJ) { if ( vChain[nI].size() == vChain[nJ].size()) { bool bSame = true ; for ( int nK = 0 ; nK < int( vChain[nI].size()) ; ++ nK) { if ( ! AreSamePointApprox( vChain[nI][nK].ptSt, vChain[nJ][nK].ptSt) || ! AreSamePointApprox( vChain[nI][nK].ptEn, vChain[nJ][nK].ptEn)) { bSame = false ; break ; } } if ( bSame) { vChain.erase( vChain.begin() + nJ) ; -- nChainCnt ; -- nJ ; } } } } // Fra le catene trovate separo le aperte dalle chiuse int nDegenerateChainNum = 0 ; INTVECTOR vnDegVec ; CHAINVECTOR cvClosedChain ; CHAINVECTOR cvOpenChain ; for ( int nL = 0 ; nL < int( vChain.size()) ; ++ nL) { bool bChainDegenerate = false ; if ( vChain[nL].size() == 1 && AreSamePointApprox( vChain[nL][0].ptSt, vChain[nL][0].ptEn)) { bChainDegenerate = true ; } if ( bChainDegenerate) ++ nDegenerateChainNum ; int nCurLoopLast = max( int( vChain[nL].size()) - 1, 0) ; if ( ( ! bChainDegenerate) && AreSamePointApprox( vChain[nL][0].ptSt, vChain[nL][nCurLoopLast].ptEn)) cvClosedChain.emplace_back( vChain[nL]) ; else { cvOpenChain.emplace_back( vChain[nL]) ; if ( bChainDegenerate) vnDegVec.emplace_back( 0) ; else vnDegVec.emplace_back( 1) ; } } // Se più di una catena chiusa oppure catene chiuse e aperte, errore if ( cvClosedChain.size() > 1 || ( cvClosedChain.size() > 0 && int( cvOpenChain.size()) > nDegenerateChainNum)) return false ; // Se c'è una catena chiusa if ( cvClosedChain.size() == 1) { // Ne ricavo una PolyLine PolyLine plInLoop ; for ( int nLine = 0 ; nLine < int( cvClosedChain[0].size()) ; ++ nLine) { plInLoop.AddUPoint( 0., cvClosedChain[0][nLine].ptSt) ; plInLoop.AddUPoint( 0., cvClosedChain[0][nLine].ptEn) ; } // I tre vertici sono dalla parte interna della curva (triangolo con buco) if ( ! bCCW) { // Rimuovo il triangolo corrente RemoveTriangle( nT) ; // Definisco il loop esterno (è il triangolo) PolyLine plExtLoop ; plExtLoop.AddUPoint( 0., trTria.GetP( 0)) ; plExtLoop.AddUPoint( 0., trTria.GetP( 1)) ; plExtLoop.AddUPoint( 0., trTria.GetP( 2)) ; plExtLoop.AddUPoint( 0., trTria.GetP( 0)) ; // Eseguo triangolazione POLYLINEVECTOR vPL ; vPL.emplace_back( plExtLoop) ; vPL.emplace_back( plInLoop) ; PNTVECTOR vPt ; INTVECTOR vTr ; if ( Triangulate().Make( vPL, 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] = { AddVertex( vPt[nNewTriaVertId[0]]), AddVertex( vPt[nNewTriaVertId[1]]), AddVertex( vPt[nNewTriaVertId[2]]) } ; AddTriangle( nNewId) ; bModif = true ; } } } // Se nessun vertice dalla parte interna della curva (rimane solo l'area della curva) else { // Rimuovo il triangolo corrente RemoveTriangle( nT) ; // Eseguo triangolazione PNTVECTOR vPt ; INTVECTOR vTr ; if ( Triangulate().Make( plInLoop, 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] = { AddVertex(vPt[nNewTriaVertId[0]]), AddVertex(vPt[nNewTriaVertId[1]]), AddVertex(vPt[nNewTriaVertId[2]]) } ; AddTriangle( nNewId) ; bModif = true ; } } } } // Loop aperti, devo chiuderli else if ( cvOpenChain.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. PNTVECTOR cvFirstLoop ; cvFirstLoop.emplace_back( trTria.GetP( 0)) ; cvFirstLoop.emplace_back( trTria.GetP( 1)) ; cvFirstLoop.emplace_back( trTria.GetP( 1)) ; cvFirstLoop.emplace_back( trTria.GetP( 2)) ; cvFirstLoop.emplace_back( trTria.GetP( 2)) ; cvFirstLoop.emplace_back( trTria.GetP( 0)) ; vector cvBoundClosedLoopVec ; cvBoundClosedLoopVec.emplace_back(cvFirstLoop); vector vbInOut ; vbInOut.push_back( true) ; // Divido il loop di partenza in sotto-loop while ( cvOpenChain.size() > 0) { int nLastOpenLoopN = int( cvOpenChain.size()) - 1 ; if ( vnDegVec[nLastOpenLoopN] == 1) { for ( int nLoop = 0 ; nLoop < int( cvBoundClosedLoopVec.size()) ; ++ nLoop) { // Estremi del loop aperto int nLastOpenLoopPoint = max( int( cvOpenChain[nLastOpenLoopN].size()) - 1, 0) ; Point3d ptOpenLoopStP = cvOpenChain[nLastOpenLoopN][0].ptSt ; Point3d ptOpenLoopEnP = cvOpenChain[nLastOpenLoopN][nLastOpenLoopPoint].ptEn ; // Cerco se esistono dei tratti del loop chiuso corrente che sono // toccati dagli estremi del loop aperto corrente int nCvSt = -1 ; int nCvEn = -1 ; for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) - 1 && ( nCvSt == -1 || nCvEn == -1) ; nLine += 2) { // Estremi del segmento corrente del loop chiuso corrente Point3d ptSegSt = cvBoundClosedLoopVec[nLoop][nLine] ; Point3d ptSegEn = cvBoundClosedLoopVec[nLoop][nLine + 1] ; // 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 ( dSqDistSt < SQ_EPS_SMALL) { nCvSt = nLine ; } double dSqDistEn ; dEnDistCalc.GetSqDist(dSqDistEn) ; if ( dSqDistEn < SQ_EPS_SMALL) { nCvEn = nLine ; } } // Se entrambi gli estremi del loop aperto sono su un segmento del loop chiuso devo dividere il loop in due if ( nCvSt != - 1 && nCvEn != - 1) { // Entrambi gli estremi del loop aperto sono su uno stesso segmento del loop chiuso if ( nCvSt == nCvEn) { bool bFirstInside ; bool bFirstSt ; PNTVECTOR cvSplitLoop1, cvSplitLoop2 ; // Creo primo loop for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) - 1 ; nLine += 2) { // Segmenti loop chiuso if ( nLine != nCvSt && nLine != nCvEn) { cvSplitLoop1.emplace_back( cvBoundClosedLoopVec[nLoop][nLine]) ; cvSplitLoop1.emplace_back( cvBoundClosedLoopVec[nLoop][nLine+1]) ; } // Dal chiuso all'aperto else if ( nLine == nCvSt) { // Distanze degli estremi del loop aperto dal punto iniziale del segmento corrente Point3d ptSegSt, ptSegEn ; ptSegSt = cvBoundClosedLoopVec[nLoop][nLine] ; 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 ; cvSplitLoop1.emplace_back( ptSegSt) ; cvSplitLoop1.emplace_back( ptSegEn) ; // Loop aperto for ( int nOpenLine = 0 ; nOpenLine < int( cvOpenChain[nLastOpenLoopN].size()) ; ++ nOpenLine) { Point3d ptOpenSt = cvOpenChain[nLastOpenLoopN][nOpenLine].ptSt ; Point3d ptOpenEn = cvOpenChain[nLastOpenLoopN][nOpenLine].ptEn ; cvSplitLoop1.emplace_back( ptOpenSt) ; cvSplitLoop1.emplace_back( ptOpenEn) ; if ( nOpenLine == 0) { Vector3d vtLast = ptSegSt - ptSegEn ; vtLast.Normalize() ; bFirstInside = vtLast * cvOpenChain[nLastOpenLoopN][nOpenLine].vtOuter < 0. ; } } // Dalla fine del loop aperto alla fine del segmento corrente ptSegSt = ptOpenLoopEnP ; ptSegEn = cvBoundClosedLoopVec[nLoop][nLine+1] ; cvSplitLoop1.emplace_back( ptSegSt) ; cvSplitLoop1.emplace_back( ptSegEn) ; 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 ; cvSplitLoop1.emplace_back( ptSegSt) ; cvSplitLoop1.emplace_back( ptSegEn) ; // Loop aperto for ( int nOpenLine = int( cvOpenChain[nLastOpenLoopN].size()) - 1 ; nOpenLine >= 0 ; -- nOpenLine) { Point3d ptOpenSt = cvOpenChain[nLastOpenLoopN][nOpenLine].ptEn ; Point3d ptOpenEn = cvOpenChain[nLastOpenLoopN][nOpenLine].ptSt ; cvSplitLoop1.emplace_back( ptOpenSt) ; cvSplitLoop1.emplace_back( ptOpenEn) ; if ( nOpenLine == int( cvOpenChain[nLastOpenLoopN].size()) - 1) { Vector3d vtLast = ptSegSt - ptSegEn ; vtLast.Normalize() ; bFirstInside = vtLast * cvOpenChain[nLastOpenLoopN][nOpenLine].vtOuter < 0. ; } } // Dall'inizio del loop aperto fino alla fine del segmento corrente ptSegSt = ptOpenLoopStP ; ptSegEn = cvBoundClosedLoopVec[nLoop][nLine+1] ; cvSplitLoop1.emplace_back( ptSegSt) ; cvSplitLoop1.emplace_back( ptSegEn) ; bFirstSt = false ; } } } // Creo secondo loop if ( bFirstSt) { // Tratto segmento ove cadono gli estremi del loop aperto cvSplitLoop2.emplace_back( ptOpenLoopStP) ; cvSplitLoop2.emplace_back( ptOpenLoopEnP) ; // Loop aperto for ( int nOpenLine = int( cvOpenChain[nLastOpenLoopN].size()) - 1 ; nOpenLine >= 0 ; -- nOpenLine) { Point3d ptOpenSt = cvOpenChain[nLastOpenLoopN][nOpenLine].ptEn ; Point3d ptOpenEn = cvOpenChain[nLastOpenLoopN][nOpenLine].ptSt ; cvSplitLoop2.emplace_back( ptOpenSt) ; cvSplitLoop2.emplace_back( ptOpenEn) ; } } else { // Tratto segmento ove cadono gli estremi del loop aperto cvSplitLoop2.emplace_back( ptOpenLoopEnP) ; cvSplitLoop2.emplace_back( ptOpenLoopStP) ; // Loop aperto for ( int nOpenLine = 0 ; nOpenLine < int( cvOpenChain[nLastOpenLoopN].size()) ; ++ nOpenLine) { Point3d ptOpenSt = cvOpenChain[nLastOpenLoopN][nOpenLine].ptSt ; Point3d ptOpenEn = cvOpenChain[nLastOpenLoopN][nOpenLine].ptEn ; cvSplitLoop2.emplace_back( ptOpenSt) ; cvSplitLoop2.emplace_back( ptOpenEn) ; } } // Aggiungo i nuovi loop nel vettore int nCurSize = int(cvBoundClosedLoopVec.size()); cvBoundClosedLoopVec.resize(nCurSize + 1); vbInOut.resize(nCurSize + 1); for (int nCL = nCurSize - 1; nCL > nLoop; --nCL) { cvBoundClosedLoopVec[nCL + 1] = cvBoundClosedLoopVec[nCL]; vbInOut[nCL + 1] = vbInOut[nCL]; } cvBoundClosedLoopVec[nLoop] = cvSplitLoop1 ; cvBoundClosedLoopVec[nLoop + 1] = cvSplitLoop2; vbInOut[nLoop] = bFirstInside; vbInOut[nLoop + 1] = !bFirstInside; ++ nLoop ; } // Estremi dell'aperto su due diversi segmenti del chiuso else { bool bFirstInside ; bool bFirstSt ; PNTVECTOR cvSplitLoop1, cvSplitLoop2 ; for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) - 1 ; nLine += 2) { // Segmento su cui non incide nessun estremo del loop aperto if ( nLine != nCvSt && nLine != nCvEn) { cvSplitLoop1.emplace_back( cvBoundClosedLoopVec[nLoop][nLine]) ; cvSplitLoop1.emplace_back( cvBoundClosedLoopVec[nLoop][nLine + 1]) ; } // Segmento su cui incide l'estremo iniziale del loop aperto else if ( nLine == nCvSt) { // Dall'inizio del segmento corrente fino all'inizio del loop aperto Point3d ptSegSt = cvBoundClosedLoopVec[nLoop][nLine] ; Point3d ptSegEn = ptOpenLoopStP ; cvSplitLoop1.emplace_back( ptSegSt) ; cvSplitLoop1.emplace_back( ptSegEn) ; // Loop aperto for ( int nOpenLine = 0 ; nOpenLine < int( cvOpenChain[nLastOpenLoopN].size()) ; ++ nOpenLine) { // Valuto se cvSplitLoop1 è interno o esterno Point3d ptOpenSt = cvOpenChain[nLastOpenLoopN][nOpenLine].ptSt ; Point3d ptOpenEn = cvOpenChain[nLastOpenLoopN][nOpenLine].ptEn ; cvSplitLoop1.emplace_back( ptOpenSt) ; cvSplitLoop1.emplace_back( ptOpenEn) ; if ( nOpenLine == 0) { Vector3d vtLast = ptSegSt - ptOpenLoopStP ; if ( vtLast.Normalize()) { bFirstInside = vtLast * cvOpenChain[nLastOpenLoopN][nOpenLine].vtOuter < 0. ; } else { vtLast = cvBoundClosedLoopVec[nLoop][nLine + 1] - ptOpenLoopStP ; vtLast.Normalize() ; bFirstInside = vtLast * cvOpenChain[nLastOpenLoopN][nOpenLine].vtOuter > 0. ; } } } // Dalla fine del loop aperto fino alla fine del segmento ove arriva il loop aperto nLine = nCvEn ; ptSegEn = cvBoundClosedLoopVec[nLoop][nLine+1] ; cvSplitLoop1.emplace_back( ptOpenLoopEnP) ; cvSplitLoop1.emplace_back( ptSegEn) ; 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 = cvBoundClosedLoopVec[nLoop][nLine] ; cvSplitLoop1.emplace_back( ptSegSt) ; cvSplitLoop1.emplace_back( ptOpenLoopEnP) ; // Loop aperto for ( int nOpenLine = int( cvOpenChain[nLastOpenLoopN].size()) - 1 ; nOpenLine >= 0 ; -- nOpenLine) { Point3d ptOpenSt = cvOpenChain[nLastOpenLoopN][nOpenLine].ptEn ; Point3d ptOpenEn = cvOpenChain[nLastOpenLoopN][nOpenLine].ptSt ; cvSplitLoop1.emplace_back( ptOpenSt) ; cvSplitLoop1.emplace_back( ptOpenEn) ; if ( nOpenLine == int( cvOpenChain[nLastOpenLoopN].size()) - 1) { Vector3d vtLast = ptSegSt - ptOpenLoopEnP ; if ( vtLast.Normalize()) { bFirstInside = vtLast * cvOpenChain[nLastOpenLoopN][nOpenLine].vtOuter < 0. ; } else { bFirstInside = vtLast * cvOpenChain[nLastOpenLoopN][nOpenLine].vtOuter > 0. ; } } } // Dalla fine del loop aperto fino alla fine del segmento ove arriva il loop aperto nLine = nCvSt ; Point3d ptSegEn = cvBoundClosedLoopVec[nLoop][nLine + 1] ; cvSplitLoop1.emplace_back( ptOpenLoopStP) ; cvSplitLoop1.emplace_back( ptSegEn) ; bFirstSt = false; } } // Creo secondo loop if ( bFirstSt) { // Dall'estremo inizinale del loop aperto alla fine del segmento su cui giace Point3d ptSegSt, ptSegEn ; ptSegSt = ptOpenLoopStP ; ptSegEn = cvBoundClosedLoopVec[nLoop][nCvSt+1] ; cvSplitLoop2.emplace_back( ptSegSt) ; cvSplitLoop2.emplace_back( ptSegEn) ; // Loop chiuso fino a segmento ove cade l'estremo finale dell'aperto for (int nLine = (nCvSt + 2) % int(cvBoundClosedLoopVec[nLoop].size()); nLine != nCvEn; nLine += 2) { ptSegSt = cvBoundClosedLoopVec[nLoop][nLine % int(cvBoundClosedLoopVec[nLoop].size())]; ptSegEn = cvBoundClosedLoopVec[nLoop][(nLine + 1) % int(cvBoundClosedLoopVec[nLoop].size())]; cvSplitLoop2.emplace_back(ptSegSt); cvSplitLoop2.emplace_back(ptSegEn); } // Dall'inizio del segmento del loop chiuso ove cade l'estremo finale del loop aperto // a quest'ultimo ptSegSt = cvBoundClosedLoopVec[nLoop][nCvEn] ; ptSegEn = ptOpenLoopEnP ; cvSplitLoop2.emplace_back( ptSegSt) ; cvSplitLoop2.emplace_back( ptSegEn) ; // Loop aperto for ( int nOpenLine = int( cvOpenChain[nLastOpenLoopN].size()) - 1 ; nOpenLine >= 0 ; -- nOpenLine) { Point3d ptOpenSt = cvOpenChain[nLastOpenLoopN][nOpenLine].ptEn ; Point3d ptOpenEn = cvOpenChain[nLastOpenLoopN][nOpenLine].ptSt ; cvSplitLoop2.emplace_back( ptOpenSt) ; cvSplitLoop2.emplace_back( ptOpenEn) ; } } else { // Dall'estremo finale del loop aperto alla fine del segmento su cui giace Point3d ptSegSt = ptOpenLoopEnP ; Point3d ptSegEn = cvBoundClosedLoopVec[nLoop][nCvEn+1] ; cvSplitLoop2.emplace_back( ptSegSt) ; cvSplitLoop2.emplace_back( ptSegEn) ; // Loop chiuso fino al segmento ove cade l'inizio del loop aperto for (int nLine = (nCvEn + 2) % int(cvBoundClosedLoopVec[nLoop].size()); nLine != nCvSt; nLine += 2) { ptSegSt = cvBoundClosedLoopVec[nLoop][nLine % int(cvBoundClosedLoopVec[nLoop].size())]; ptSegEn = cvBoundClosedLoopVec[nLoop][(nLine + 1) % int(cvBoundClosedLoopVec[nLoop].size())]; cvSplitLoop2.emplace_back(ptSegSt); cvSplitLoop2.emplace_back(ptSegEn); } // Dall'inizio del segmento del loop chiuso ove cade l'estremo iniziale del loop aperto // a quest'ultimo ptSegSt = cvBoundClosedLoopVec[nLoop][nCvSt] ; ptSegEn = ptOpenLoopStP ; cvSplitLoop2.emplace_back( ptSegSt) ; cvSplitLoop2.emplace_back( ptSegEn) ; // Loop aperto for ( int nOpenLoop = 0 ; nOpenLoop < int( cvOpenChain[nLastOpenLoopN].size()) ; ++ nOpenLoop) { Point3d ptOpenSt = cvOpenChain[nLastOpenLoopN][nOpenLoop].ptSt ; Point3d ptOpenEn = cvOpenChain[nLastOpenLoopN][nOpenLoop].ptEn ; cvSplitLoop2.emplace_back( ptOpenSt) ; cvSplitLoop2.emplace_back( ptOpenEn) ; } } // Aggiungo i nuovi loop nel vettore int nCurSize = int( cvBoundClosedLoopVec.size()) ; cvBoundClosedLoopVec.resize( nCurSize + 1) ; vbInOut.resize( nCurSize + 1) ; for ( int nCL = nCurSize - 1 ; nCL > nLoop ; -- nCL) { cvBoundClosedLoopVec[nCL + 1] = cvBoundClosedLoopVec[nCL] ; vbInOut[nCL + 1] = vbInOut[nCL] ; } cvBoundClosedLoopVec[nLoop] = cvSplitLoop1 ; cvBoundClosedLoopVec[nLoop + 1] = cvSplitLoop2 ; vbInOut[nLoop] = bFirstInside ; vbInOut[nLoop + 1] = ! bFirstInside ; ++ nLoop ; } } } } // Degenere else { Point3d ptProva = 0.5 * ( cvOpenChain[nLastOpenLoopN][0].ptSt + cvOpenChain[nLastOpenLoopN][0].ptEn) ; Vector3d vtVecProva = cvOpenChain[nLastOpenLoopN][0].vtOuter ; vtVecProva.Normalize( EPS_ZERO) ; for ( int nLoop = 0 ; nLoop < int( cvBoundClosedLoopVec.size()) ; ++ nLoop) { // Estremi del loop aperto int nLastOpenLoopPoint = max(int(cvOpenChain[nLastOpenLoopN].size()) - 1, 0) ; Point3d ptOpenLoopStP = cvOpenChain[nLastOpenLoopN][0].ptSt ; Point3d ptOpenLoopEnP = cvOpenChain[nLastOpenLoopN][0].ptEn ; // Cerco se esistono dei tratti del loop chiuso corrente che sono // toccati dagli estremi del loop aperto corrente int nCvFirst = -1 ; int nCvSecond = -1 ; for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) - 1 && nCvSecond == -1 ; nLine += 2) { // Estremi del segmento corrente del loop chiuso corrente Point3d ptSegSt = cvBoundClosedLoopVec[nLoop][nLine] ; Point3d ptSegEn = cvBoundClosedLoopVec[nLoop][nLine + 1] ; // Vettore congiungente i su definiti punti Vector3d vtClosedLoopSeg = ptSegEn - ptSegSt ; vtClosedLoopSeg.Normalize() ; // Vedo se gli estremi del loop aperto stanno su un segmento del chiuso DistPointLine DistCalc( ptProva, ptSegSt, ptSegEn) ; double dSqDist ; DistCalc.GetSqDist( dSqDist) ; if ( dSqDist < 2 * SQ_EPS_SMALL) { if ( nCvFirst == -1) nCvFirst = nLine ; else nCvSecond = nLine ; } } if ( nCvFirst != nCvSecond && nCvSecond != -1) { // li ordino in senso crescente if ( nCvFirst > nCvSecond) swap( nCvFirst, nCvSecond) ; // punto medio tra primo e secondo int nCount = 0 ; Point3d ptM12 ; for ( int i = nCvFirst + 1 ; i < nCvSecond ; i += 2) { ptM12 += cvBoundClosedLoopVec[nLoop][i] ; ++ nCount ; } ptM12 /= nCount ; // verifico se questo punto è dalla parte valida o no bool bC12 = ( ( ptM12 - ptProva) * vtVecProva < 0) ; // numero totale di punti int nPntTot = int( cvBoundClosedLoopVec[nLoop].size()) ; // elimino i punti dalla parte non valida if ( bC12) { // assegno i nuovi valori cvBoundClosedLoopVec[nLoop][nCvFirst] = ptProva ; cvBoundClosedLoopVec[nLoop][nCvSecond+1] = ptProva ; // elimino i punti superflui dopo for ( int i = nPntTot - 1 ; i > nCvSecond+1 ; -- i) cvBoundClosedLoopVec[nLoop].pop_back() ; // elimino i punti superflui prima for ( int i = 0 ; i < nCvFirst ; ++ i) cvBoundClosedLoopVec[nLoop].erase( cvBoundClosedLoopVec[nLoop].begin()) ; } else { // assegno i nuovi valori cvBoundClosedLoopVec[nLoop][nCvFirst+1] = ptProva ; cvBoundClosedLoopVec[nLoop][nCvSecond] = ptProva ; // elimino i punti superflui intermedi for ( int i = nCvFirst+2 ; i < nCvSecond ; ++ i) cvBoundClosedLoopVec[nLoop].erase( cvBoundClosedLoopVec[nLoop].begin()+nCvFirst+2) ; } vbInOut[nLoop] = true ; // PNTVECTOR cvSplitLoop; // for (int nLine = 0; nLine < nCvFirst; nLine += 2) { // cvSplitLoop.emplace_back(cvBoundClosedLoopVec[nLoop][nLine]); // cvSplitLoop.emplace_back(cvBoundClosedLoopVec[nLoop][nLine + 1]); // } // cvSplitLoop.emplace_back(cvBoundClosedLoopVec[nLoop][nCvFirst]); // cvSplitLoop.emplace_back(ptProva); // cvSplitLoop.emplace_back(ptProva); // cvSplitLoop.emplace_back(cvBoundClosedLoopVec[nLoop][nCvSecond + 1]); // for (int nLine = nCvSecond + 2; nLine < int(cvBoundClosedLoopVec[nLoop].size()) - 1; nLine += 2) { // cvSplitLoop.emplace_back(cvBoundClosedLoopVec[nLoop][nLine]); // cvSplitLoop.emplace_back(cvBoundClosedLoopVec[nLoop][nLine + 1]); // } // cvBoundClosedLoopVec[nLoop] = cvSplitLoop; // if ((cvBoundClosedLoopVec[nLoop][nCvFirst] - ptProva) * vtVecProva < 0.) // vbInOut[nLoop] = true; // else // vbInOut[nLoop] = false; } } } vnDegVec.resize( nLastOpenLoopN) ; cvOpenChain.resize( nLastOpenLoopN) ; } // Rimuovo il triangolo corrente RemoveTriangle( nT) ; // Trasformo i loop compositi in loop polyline POLYLINEVECTOR vplPolyVec ; vplPolyVec.resize( cvBoundClosedLoopVec.size()) ; for ( int nLoop = 0 ; nLoop < int( vplPolyVec.size()) ; ++ nLoop) { for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) - 1 ; nLine += 2) { vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][nLine]) ; vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][nLine + 1]) ; } if ( vbInOut[nLoop]) { // Eseguo triangolazione Triangulate CreateTriangulation ; PNTVECTOR vPt ; INTVECTOR vTr ; if ( Triangulate().Make( vplPolyVec[nLoop], 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] = { AddVertex( vPt[nNewTriaVertId[0]]), AddVertex( vPt[nNewTriaVertId[1]]), AddVertex( vPt[nNewTriaVertId[2]]) } ; AddTriangle( nNewId) ; bModif = true ; } } } } } else if ( nVertInside == 0) RemoveTriangle( nT) ; } // Se avvenuta modifica, aggiorno tutto if ( bModif) return ( AdjustVertices() && DoCompacting()) ; return true ; }