From 7cf933ec482d380538b899ffcba206ee126d0c20 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Wed, 7 Jun 2023 17:43:23 +0200 Subject: [PATCH] EgtGeomKernel : - risolti i problemi di trim su superfici di bezier Problemi noti: - mancano ancora delle celle - si formano delle crack --- SurfBezier.cpp | 2 +- Tree.cpp | 226 ++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 177 insertions(+), 51 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index cca23c6..fe54cf4 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -1501,7 +1501,7 @@ SurfBezier::GetAuxSurf( void) const Tree Tree( this, true) ; //Tree.BuildTree_test() ; - Tree.BuildTree() ; + Tree.BuildTree( 0.2, 25) ; vector vvPL ; Tree.GetPolygons( vvPL) ; PtrOwner pSrfTm( CreateBasicSurfTriMesh()) ; diff --git a/Tree.cpp b/Tree.cpp index ec0d431..bbbe40c 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -1561,8 +1561,6 @@ Tree::TraceLoopLabelCell( void) } else { nId = nCells.back() ; - // qui devo scegliere da quale cella partire!! /////////////////////////////////////////////////////////////////////////////////////////////////// - // fatto } // trovo quali punti della polyline sono nella cella e l'intersezione PNTVECTOR vptInters ; @@ -1669,15 +1667,26 @@ Tree::TraceLoopLabelCell( void) // categorizzo la cella m_mTree[nCell].m_nFlag2 = 1 ; CategorizeCell( nCell) ; - + bool bDone = false ; + int nInProcessing = -1 ; + int c = 0 ; + int nDisplay = -1 ; // fintanto che la cella ha tra i vicini a destra una cella non elaborata mi sposto a destra // definisco una cella Processed se tutto il ramo a destra è categorizzato - while ( (int)vNeigh.size() > 0 || ! m_mTree[nCell].IsProcessed()) { + while ( ((int)vNeigh.size() > 0 && ! bDone) || ! m_mTree[nCell].IsProcessed()) { + // per debug + if ( nInProcessing != nCell) { + nInProcessing = nCell ; + c = 0 ; + } + else + ++ c ; // verso la cella a destra più in basso da cui non sono ancora passato bool bProceeded = false ; for ( int i = 0 ; i < (int)vNeigh.size(); ++ i) { if ( m_mTree[vNeigh[i]].m_nFlag2 == 0 ) { nCell = vNeigh[i] ; + nDisplay = m_mTree[nCell].m_nFlag ; bProceeded = true ; break ; } @@ -1694,14 +1703,33 @@ Tree::TraceLoopLabelCell( void) // guardo i vicini a destra per passare alla prossima cella vNeigh.clear() ; GetRightNeigh( nCell, vNeigh) ; + bDone = true ; + // controllo che tra i vicini di destra ce ne sia almeno uno non processato + for ( int t: vNeigh) { + if ( ! m_mTree[t].IsProcessed()) { + bDone = false ; + break ; + } + } } + // per debug + if ( c > 3) + break ; } vNeigh.clear() ; GetRightNeigh( nCell, vNeigh) ; // se non ho vicini a destra o se i vicini sono già tutti categorizzati // torno indietro a sinistra alla cella già categorizzata più bassa //bDone = true ; + c = 0 ; while ( (int) vNeigh.size() == 0 || m_mTree[nCell].IsProcessed()) { + // per debug + if ( nInProcessing != nCell) { + nInProcessing = nCell ; + c = 0 ; + } + else + ++ c ; // trovo il vicino a sinistra, già categorizzato, più basso vNeigh.clear() ; GetLeftNeigh( nCell, vNeigh) ; @@ -1738,8 +1766,16 @@ Tree::TraceLoopLabelCell( void) break ; } } - if ( bDone) + if ( bDone) { m_mTree[nCell].SetProcessed( bDone) ; + if ( m_mTree[nCell].m_nFlag2 == 0) { + m_mTree[nCell].m_nFlag2 = 1 ; + CategorizeCell( nCell) ; + } + } + // per debug + if ( c > 3) + break ; } vNeigh.clear() ; GetRightNeigh( nCell, vNeigh) ; @@ -1883,11 +1919,22 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert else ptInters = aInfo.IciA[0].ptI ; } + // devo controllare se l'intersezione è in un vertice ed eventualmente correggere nEdge + if ( nEdge < 4) { + if ( AreSamePointExact( ptInters, ptTl)) + nEdge = 4 ; + else if ( AreSamePointExact( ptInters, ptBL)) + nEdge = 5 ; + else if ( AreSamePointExact( ptInters, ptBr)) + nEdge = 6 ; + else if ( AreSamePointExact( ptInters, ptTR)) + nEdge = 7 ; + } m_mTree[nId].m_vInters.back().nOut = nEdge ; vptInters.push_back( ptInters) ; // salvo il vettore intersezione per la cella e capisco in quale altra cella passare if ( (int)vptInters.size() == 1) - m_mTree[nId].m_vInters.back().vpt.push_back( vptInters[0]) ; // al posto di .vpt = vptInters metto un push_back //////////////////////////////////////////////// + m_mTree[nId].m_vInters.back().vpt.push_back( vptInters[0]) ; else m_mTree[nId].m_vInters.back().vpt = vptInters ; vptInters.clear() ; @@ -1987,13 +2034,27 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert if ( ! nPossible.empty()) { nId = nPossible[0] ; m_mTree[nId].m_vInters.emplace_back() ; - m_mTree[nId].m_vInters.back().nIn = 2 ; + // controllo se entro in un vertice o a metà lato + Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + if ( AreSamePointExact( ptInters, ptBr)) + m_mTree[nId].m_vInters.back().nIn = 6 ; + else if ( AreSamePointExact( ptInters, m_mTree[nId].GetBottomLeft())) + m_mTree[nId].m_vInters.back().nIn = 5 ; + else + m_mTree[nId].m_vInters.back().nIn = 2 ; } // ingresso da destra else if ( ! nPossible1.empty()) { nId = nPossible1.back() ; m_mTree[nId].m_vInters.emplace_back() ; - m_mTree[nId].m_vInters.back().nIn = 3 ; + // controllo se entro in un vertice o a metà lato + Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + if ( AreSamePointExact( ptInters, ptBr)) + m_mTree[nId].m_vInters.back().nIn = 6 ; + else if ( AreSamePointExact( ptInters, m_mTree[nId].GetTopRight())) + m_mTree[nId].m_vInters.back().nIn = 7 ; + else + m_mTree[nId].m_vInters.back().nIn = 3 ; } // ingresso in diagonale else { @@ -2022,13 +2083,27 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert if ( ! nPossible.empty()) { nId = nPossible[0] ; m_mTree[nId].m_vInters.emplace_back() ; - m_mTree[nId].m_vInters.back().nIn = 3 ; + // controllo se entro in un vertice o a metà lato + Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + if ( AreSamePointExact( ptInters, ptBr)) + m_mTree[nId].m_vInters.back().nIn = 6 ; + else if ( AreSamePointExact( ptInters, m_mTree[nId].GetTopRight())) + m_mTree[nId].m_vInters.back().nIn = 7 ; + else + m_mTree[nId].m_vInters.back().nIn = 3 ; } // ingresso dall'alto else if ( ! nPossible1.empty()) { nId = nPossible1[0] ; m_mTree[nId].m_vInters.emplace_back() ; - m_mTree[nId].m_vInters.back().nIn = 0 ; + // controllo se entro in un vertice o a metà lato + Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + if ( AreSamePointExact( ptInters, ptTl)) + m_mTree[nId].m_vInters.back().nIn = 4 ; + else if ( AreSamePointExact( ptInters, m_mTree[nId].GetTopRight())) + m_mTree[nId].m_vInters.back().nIn = 7 ; + else + m_mTree[nId].m_vInters.back().nIn = 0 ; } // ingresso in diagonale else { @@ -2057,13 +2132,27 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert if ( ! nPossible.empty()) { nId = nPossible.back() ; m_mTree[nId].m_vInters.emplace_back() ; - m_mTree[nId].m_vInters.back().nIn = 0 ; + // controllo se entro in un vertice o a metà lato + Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + if ( AreSamePointExact( ptInters, ptTl)) + m_mTree[nId].m_vInters.back().nIn = 4 ; + else if ( AreSamePointExact( ptInters, m_mTree[nId].GetTopRight())) + m_mTree[nId].m_vInters.back().nIn = 7 ; + else + m_mTree[nId].m_vInters.back().nIn = 0 ; } // ingresso da sinistra else if ( ! nPossible1.empty()) { nId = nPossible1[0] ; m_mTree[nId].m_vInters.emplace_back() ; - m_mTree[nId].m_vInters.back().nIn = 1 ; + // controllo se entro in un vertice o a metà lato + Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + if ( AreSamePointExact( ptInters, ptTl)) + m_mTree[nId].m_vInters.back().nIn = 4 ; + else if ( AreSamePointExact( ptInters, m_mTree[nId].GetBottomLeft())) + m_mTree[nId].m_vInters.back().nIn = 5 ; + else + m_mTree[nId].m_vInters.back().nIn = 1 ; } // ingresso in diagonale else { @@ -2093,13 +2182,27 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert if ( ! nPossible.empty()) { nId = nPossible.back() ; m_mTree[nId].m_vInters.emplace_back() ; - m_mTree[nId].m_vInters.back().nIn = 1 ; + // controllo se entro in un vertice o a metà lato + Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + if ( AreSamePointExact( ptInters, ptTl)) + m_mTree[nId].m_vInters.back().nIn = 4 ; + else if ( AreSamePointExact( ptInters, m_mTree[nId].GetBottomLeft())) + m_mTree[nId].m_vInters.back().nIn = 5 ; + else + m_mTree[nId].m_vInters.back().nIn = 1 ; } // ingresso dal basso else if ( ! nPossible1.empty()) { nId = nPossible1.back() ; m_mTree[nId].m_vInters.emplace_back() ; - m_mTree[nId].m_vInters.back().nIn = 2 ; + // controllo se entro in un vertice o a metà lato + Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + if ( AreSamePointExact( ptInters, ptBr)) + m_mTree[nId].m_vInters.back().nIn = 6 ; + else if ( AreSamePointExact( ptInters, m_mTree[nId].GetBottomLeft())) + m_mTree[nId].m_vInters.back().nIn = 5 ; + else + m_mTree[nId].m_vInters.back().nIn = 2 ; } // ingresso in diagonale else { @@ -2311,8 +2414,6 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I else if ( nEdge == 3) ptVert = m_mTree[nId].GetTopRight() ; AddVertex( nId, vEdgeVertex, plTrimmedPoly, c, ptVert) ; - //plTrimmedPoly.AddUPoint( c, ptVert) ; - //++c ; if ( nEdge > 3 && nEdge != 7) nEdge = nEdge - 4 ; else if ( nEdge < 3 ) @@ -2371,6 +2472,17 @@ Tree::CreateIslandAndHoles( int nLeafId, std::vector& vPolygons, // numero dei loop interni passati int n = 0 ; Inters inA = m_mTree[nId].m_vInters[n] ; + // se ho almeno un loop CW che non è contenuto in un altro poligono o in un loop interno CCW + bool bAllCW = true ; + for ( Inters inB : m_mTree[nId].m_vInters) { + if ( inB.nIn == -1){ + if ( inB.bCCW) { + bAllCW = false ; + break ; + } + } + } + // la seconda condizione è da cambiareeeeeeeeeeeeeeeeeeeee//////////////////////////////////////////////////////////////////////////////////////////// if ( m_mTree[nId].m_nFlag == 2 && ! inA.bCCW) { // i loop esterni sono CW, quindi prima dei loop di trim aggiungo il bordo cella Point3d ptVert = m_mTree[nId].GetTopRight() ; @@ -2395,7 +2507,7 @@ Tree::CreateIslandAndHoles( int nLeafId, std::vector& vPolygons, // numero di vertici aggiunti al nuovo poligono int k = 0 ; for ( Point3d ptInt : inA.vpt) { - plInLoop.AddUPoint( c, ptInt) ; + plInLoop.AddUPoint( k, ptInt) ; ++ k ; } plInLoop.Close(); @@ -2463,12 +2575,6 @@ Tree::CheckIfBefore( Inters& inA) const int nEdge1 = inA.nIn ; int nEdge2 = inA.nOut ; PolyLine pl ; - //int c = 0 ; - //for ( int p = 0 ; p < (int)inA.vpt.size(); ++p ) { - // Point3d ptToAdd = inA.vpt[p] ; - // pl.AddUPoint( c, ptToAdd) ; - // ++ c ; - //} pl.AddUPoint( 0, inA.vpt.back()) ; pl.AddUPoint( 1, inA.vpt[0]) ; INTVECTOR vEdges = { 7, 0, 4, 1, 5, 2, 6} ; @@ -2791,17 +2897,28 @@ Tree::SetRightEdgeIn( int nId) int nPass = (int) m_mTree[nId].m_vInters.size() ; bool bDone = false ; for ( int k = 0 ; k < nPass ; ++ k) { - if ( m_mTree[nId].m_vInters[k].nIn == 3 || m_mTree[nId].m_vInters[k].nOut == 3 ) { + if ( m_mTree[nId].m_vInters[k].nIn == 3 || m_mTree[nId].m_vInters[k].nOut == 3) { m_mTree[nId].m_nRightEdgeIn = 2 ; bDone = true ; break ; } // considero anche ingressi/ uscite dai vertici 6 e 7 - if ( AreSameEdge( m_mTree[nId].m_vInters[k].nIn, 3) || AreSameEdge( m_mTree[nId].m_vInters[k].nOut, 3) ) { - m_mTree[nId].m_nRightEdgeIn = 2 ; + // controllo nei vertici + if ( m_mTree[nId].m_vInters[k].nOut == 6 && m_mTree[nId].m_vInters[k].nIn == 7) { + m_mTree[nId].m_nRightEdgeIn = 1 ; bDone = true ; break ; } + if ( m_mTree[nId].m_vInters[k].nOut == 7 && m_mTree[nId].m_vInters[k].nIn == 6 ) { + m_mTree[nId].m_nRightEdgeIn = 0 ; + bDone = true ; + break ; + } + /*if ( AreSameEdge( m_mTree[nId].m_vInters[k].nIn, 3) || AreSameEdge( m_mTree[nId].m_vInters[k].nOut, 3) ) { + m_mTree[nId].m_nRightEdgeIn = 2 ; + bDone = true ; + break ; + }*/ } // se non ho inters sul lato destro devo verificare se è tutto dentro o tutto fuori if ( ! bDone) { @@ -2859,7 +2976,17 @@ Tree::CategorizeCell( int& nId) if ( m_mTree[vNeigh[0]].m_nRightEdgeIn == 1) m_mTree[nId].m_nFlag = 4 ; else if ( m_mTree[vNeigh[0]].m_nRightEdgeIn == 0) - m_mTree[nId].m_nFlag = 0 ; + // devo verificare se la cella è intersecata + if ( m_mTree[vNeigh[0]].m_nFlag == 1 || m_mTree[vNeigh[0]].m_nFlag == 3) + m_mTree[nId].m_nFlag = 0 ; + else { + if ( m_mTree[vNeigh[0]].m_nFlag == 4) { + m_mTree[nId].m_nFlag = 4 ; + } + else if ( m_mTree[vNeigh[0]].m_nFlag == 0) { + m_mTree[nId].m_nFlag = 0 ; + } + } // se solo parte del right edge del vicino è compreso, allora devo verificare se la cella è contenuta o no // guardando nFlag del vicino bottom, che è già categorizzato! else if ( m_mTree[vNeigh[0]].m_nRightEdgeIn == 2 ) { @@ -2888,16 +3015,28 @@ Tree::CategorizeCell( int& nId) for ( int r = 0 ; r < nPass; ++ r ) { // trovo il loop che ha l'ingresso o l'uscita più in alto sul lato destro // verifico che o l'ingresso o l'uscita siano sul lato destro e che sia l'intersezione più alta su quel lato - if ( ( AreSameEdge( m_mTree[nNeigh].m_vInters[r].nIn, 3) && ! CheckIfBefore( m_mTree[nNeigh].m_vInters[r].nIn, m_mTree[nNeigh].m_vInters[r].vpt[0], nEdgeIn, ptInters))) { + if ( m_mTree[nNeigh].m_vInters[r].nIn == 3 && ! CheckIfBefore( m_mTree[nNeigh].m_vInters[r].nIn, m_mTree[nNeigh].m_vInters[r].vpt[0], ptInters)) { nLoop = r ; ptInters = m_mTree[nNeigh].m_vInters[r].vpt[0] ; bFound = true ; } - if ( AreSameEdge(m_mTree[nNeigh].m_vInters[r].nOut, 3) && ! CheckIfBefore( m_mTree[nNeigh].m_vInters[r].nOut, m_mTree[nNeigh].m_vInters[r].vpt.back(), nEdgeOut, ptInters)) { + if ( m_mTree[nNeigh].m_vInters[r].nOut == 3 && ! CheckIfBefore( m_mTree[nNeigh].m_vInters[r].nOut, m_mTree[nNeigh].m_vInters[r].vpt.back(), ptInters)) { nLoop = r ; ptInters = m_mTree[nNeigh].m_vInters[r].vpt.back() ; bFound = true ; } + // controllo nei vertici + if ( m_mTree[nNeigh].m_vInters[r].nOut == 7 || m_mTree[nNeigh].m_vInters[r].nIn == 7) { + nLoop = r ; + ptInters = m_mTree[nNeigh].GetTopRight() ; + bFound = true ; + break ; + } + if ( m_mTree[nNeigh].m_vInters[r].nOut == 6 || m_mTree[nNeigh].m_vInters[r].nIn == 6 ) { + nLoop = r ; + ptInters = ptBr ; + bFound = true ; + } } if ( bFound && CheckIfBefore( m_mTree[nNeigh].m_vInters[nLoop])) { bTopMost = true ; @@ -2909,7 +3048,7 @@ Tree::CategorizeCell( int& nId) else m_mTree[nId].m_nFlag = 0 ; } - else if ( AreSameEdge(m_mTree[nId].m_vInters[nLoop].nOut, 3)) + else if ( AreSameEdge(m_mTree[nNeigh].m_vInters[nLoop].nOut, 3)) m_mTree[nId].m_nFlag = 4 ; else if ( AreSameEdge(m_mTree[nNeigh].m_vInters[nLoop].nIn, 3) ) { // devo verificare se il l'uscita è più a sinistra o più a destra della cella @@ -2949,11 +3088,6 @@ Tree::CheckIfBetween( Inters& inA, Inters& inB) const // ( dall'end di A percorro i bordi della cella fino a tornare allo start e devo incontrare In e Out di B) INTVECTOR vEdges ; int nEdge = inA.nOut ; - //vEdges.push_back( nEdge) ; - //if ( nEdge == 3) - // nEdge = 0 ; - //else - // ++ nEdge ; while ( nEdge != inA.nIn || (int) vEdges.size() == 0) { vEdges.push_back( nEdge) ; if ( nEdge == 3) @@ -2965,8 +3099,8 @@ Tree::CheckIfBetween( Inters& inA, Inters& inB) const vEdges.push_back( nEdge) ; bool bFound = false ; for ( int i : vEdges) { - if ( inB.nIn == i) { - if ( inB.nIn == inA.nIn && inA.nIn == inA.nOut ) { + if ( AreSameEdge(inB.nIn, i)) { + if ( AreSameEdge(inB.nIn, inA.nIn) && AreSameEdge(inA.nIn, inA.nOut)) { nEdge = inA.nIn ; //se l'inizio di A è prima della fine, allora devo controllare che B sia compreso tra Out e In (esterno) if ( CheckIfBefore( nEdge, inA.vpt[0], inA.vpt.back()) ) { @@ -2978,36 +3112,28 @@ Tree::CheckIfBetween( Inters& inA, Inters& inB) const if ( CheckIfBefore( nEdge, inA.vpt.back(), inB.vpt[0]) && CheckIfBefore( nEdge, inB.vpt[0], inA.vpt[0])) bFound = true ; } - - // alternativa - // percorrendo il lato in modo ciclico ( con condizioni al contorno che dalla fine mi riportano all'inizio) - // partendo da OutA devo incontrare InB e poi InA - //if ( CheckIfBefore( nEdge, inA.vpt.back(), nEdge, inB.vpt[0]) && CheckIfBefore( nEdge, inA.vpt.back(), nEdge, inB.vpt[0])) { - // bFound = true ; - //} - // mancano gli altri due casi da aggiungere alla ( condizione) || ( ) || ( ) } - else if ( inB.nIn == inA.nOut) { + else if ( AreSameEdge(inB.nIn, inA.nOut)) { PolyLine pl ; pl.AddUPoint( 0, inA.vpt[0]) ; pl.AddUPoint( 1, inA.vpt.back()) ; if ( CheckIfAfter( pl, inB.vpt[0], i)) bFound = true ; } - else if ( inB.nIn == inA.nIn ) { + else if ( AreSameEdge(inB.nIn, inA.nIn)) { //devo controllare il loop b sia prima dell'inizio di A if ( CheckIfBefore(inA.nIn, inB.vpt[0], inA.nIn, inA.vpt[0])) bFound = true ; } else // devo controllare che inB sia prima di OutB - if ( inB.nOut == inB.nIn && CheckIfBefore( inB.nOut, inB.vpt[0], inB.vpt.back())) { + if ( AreSameEdge(inB.nOut, inB.nIn) && CheckIfBefore( inB.nOut, inB.vpt[0], inB.vpt.back())) { bFound = true ; } - else if ( inB.nOut != inB.nIn) + else if ( ! AreSameEdge(inB.nOut,inB.nIn)) bFound = true ; } - if ( inB.nOut == i && ! bFound) + if ( AreSameEdge(inB.nOut, i) && ! bFound && CheckIfBefore(i, inA.vpt[0], inB.vpt.back()) && CheckIfBefore(i, inA.vpt.back(), inB.vpt.back())) break ; } return bFound ;