From 419d325409f779d4f023d4b2c7a72cb4be752d71 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 12 Sep 2023 14:49:43 +0200 Subject: [PATCH] EgtGeomKernel : - correzione di bug nel trim di sup di Bezier chiuse - correzione di bug nella conversione di NURBS in sup di Bezier --- CurveAux.cpp | 2 +- SurfAux.cpp | 141 +++------------------------------ SurfBezier.cpp | 2 + Tree.cpp | 207 ++++++++++++++++++++++++++++++++++++++----------- Tree.h | 14 +++- 5 files changed, 190 insertions(+), 176 deletions(-) diff --git a/CurveAux.cpp b/CurveAux.cpp index 795c6e4..0eec93f 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -558,7 +558,7 @@ NurbsToBezierCurve( const CNurbsData& cnData) } if ( ! bOk) return nullptr ; - + // se 1 solo intervallo, la Nurbs è già una curva di Bezier if ( nInt == 1) { // creo la curva di Bezier diff --git a/SurfAux.cpp b/SurfAux.cpp index 88db54c..ff75ed0 100644 --- a/SurfAux.cpp +++ b/SurfAux.cpp @@ -147,6 +147,10 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } bool bRef = false ; + // se la superficie è lineare nel parametro U allora è già in forma di Bezier in questo parametro + if ( b == nU - 1 ) { + nb = 1 ; + } while ( b < nU - 1) { // qui correggo un probabile errore, mettendo nU anziché nCPV, come indicato nell'algoritmo int i = b ; while ( b < nU - 1 && abs( cnData.vU[b+1] - cnData.vU[b]) < EPS_ZERO) @@ -270,7 +274,7 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } } // devo vedere quante patch ci stanno prendendo i punti che ci sono - nb = (cnData.nCPU - 1) / cnData.nDegU ; + //nb = (cnData.nCPU - 1) / cnData.nDegU ; } else nCPU_ref = cnData.nDegU * nb + 1 ; // numero dei punti di controllo in U dopo il raffinamento @@ -308,7 +312,11 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } bRef = false ; - while ( b < nV - 1) { // qui correggo un probabile errore, mettendo nU anziché nCPV, come indicato nell'algoritmo + // se la superficie è lineare nel parametro V allora è già in forma di Bezier in questo parametro + if ( b == nV - 1 ) { + nc = 1 ; + } + while ( b < nV - 1) { int i = b ; while ( b < nV - 1 && abs( cnData.vV[b+1] - cnData.vV[b]) < EPS_ZERO) ++ b ; @@ -440,7 +448,7 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } } // devo vedere quante patch ci stanno prendendo i punti che ci sono - nc = (cnData.nCPV - 1) / cnData.nDegV ; + //nc = (cnData.nCPV - 1) / cnData.nDegV ; } else nCPV_ref = cnData.nDegV * nc + 1 ; @@ -465,129 +473,4 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } } return Release( pSrfBz) ; -} - -//// algoritmo per le curve, da usare come reference/////////////////////////////////////////////////////////////////////////////// -// -// -// // vettore dei punti di controllo della curva di Bezier -// PNTVECTOR vBC ; -// vBC.resize( cnData.nDeg + 1) ; -// DBLVECTOR vBW ; -// vBW.resize( cnData.nDeg + 1) ; -// if ( ! cnData.bRat) { -// for ( int i = 0 ; i <= cnData.nDeg ; ++ i) -// vBC[i] = cnData.vCP[i] ; -// } -// else { -// for ( int i = 0 ; i <= cnData.nDeg ; ++ i) { -// vBC[i] = cnData.vCP[i] * cnData.vW[i] ; -// vBW[i] = cnData.vW[i] ; -// } -// } -// // primi coefficienti della successiva -// PNTVECTOR vNextBC ; -// vNextBC.resize( cnData.nDeg - 1) ; -// DBLVECTOR vNextBW ; -// vNextBW.resize( cnData.nDeg - 1) ; -// // ... -// DBLVECTOR vAlfa ; -// vAlfa.resize( cnData.nDeg - 1) ; -// int a = cnData.nDeg - 1 ; -// int b = cnData.nDeg ; -// bool bPrevRejected = false ; -// // ciclo -// while ( b < nU - 1) { -// int i = b ; -// while ( b < nU - 1 && abs( cnData.vU[b+1] - cnData.vU[b]) < EPS_ZERO) -// ++ b ; -// int mult = min( b - i + 1, cnData.nDeg) ; -// if ( mult < cnData.nDeg) { -// // numeratore di alfa -// double numer = cnData.vU[b] - cnData.vU[a] ; -// // calcola e salva gli alfa -// for ( int j = cnData.nDeg ; j > mult ; -- j) -// vAlfa[j-mult-1] = numer / ( cnData.vU[a+j] - cnData.vU[a]) ; -// // inserisco il nodo r volte -// int r = cnData.nDeg - mult ; -// for ( int j = 1 ; j <= r ; ++ j) { -// int save = r - j ; -// int s = mult + j ; -// for ( int k = cnData.nDeg ; k >= s ; -- k) -// vBC[k] = vAlfa[k-s] * vBC[k] + ( 1 - vAlfa[k-s]) * vBC[k-1] ; -// if ( cnData.bRat) { -// for ( int k = cnData.nDeg ; k >= s ; -- k) -// vBW[k] = vAlfa[k-s] * vBW[k] + ( 1 - vAlfa[k-s]) * vBW[k-1] ; -// } -// if ( b < nU - 1) { -// vNextBC[save] = vBC[cnData.nDeg] ; -// if ( cnData.bRat) -// vNextBW[save] = vBW[cnData.nDeg] ; -// } -// } -// } -// -// // costruisco la curva di Bezier e la inserisco nella curva composita -// PtrOwner pCrvBez( CreateCurveBezier()) ; -// if ( IsNull( pCrvBez)) -// return nullptr ; -// // se precedente saltata -// if ( bPrevRejected) { -// // prendo l'ultimo punto della curva composita per garantire la continuità -// Point3d ptEnd ; -// if ( pCrvCompo->GetEndPoint( ptEnd)) -// vBC[0] = ptEnd ; -// } -// // la inizializzo -// if ( ! pCrvBez->Init( cnData.nDeg, cnData.bRat)) -// return nullptr ; -// if ( ! cnData.bRat) { -// for ( int i = 0 ; i <= cnData.nDeg ; ++ i) { -// if ( ! pCrvBez->SetControlPoint( i, vBC[i])) -// return nullptr ; -// } -// } -// else { -// for ( int i = 0 ; i <= cnData.nDeg ; ++ i) { -// if ( ! pCrvBez->SetControlPoint( i, vBC[i] / vBW[i], vBW[i])) -// return nullptr ; -// } -// } -// // se è una vera curva, la aggiungo alla curva composita -// if ( ! pCrvBez->IsAPoint()) { -// if ( ! pCrvCompo->AddCurve( Release( pCrvBez))) -// return nullptr ; -// bPrevRejected = false ; -// } -// // altrimenti è un punto, la cancello -// else { -// pCrvBez.Reset() ; -// bPrevRejected = true ; -// } -// -// // inizializzazioni per la prossima curva di Bezier -// if ( b < nU - 1) { -// if ( ! cnData.bRat) { -// for ( int i = 0 ; i < cnData.nDeg - 1 ; ++ i) -// vBC[i] = vNextBC[i] ; -// for ( int i = cnData.nDeg - mult ; i <= cnData.nDeg ; ++ i) -// vBC[i] = cnData.vCP[b-cnData.nDeg+i+1] ; -// } -// else { -// for ( int i = 0 ; i < cnData.nDeg - 1 ; ++ i) { -// vBC[i] = vNextBC[i] ; -// vBW[i] = vNextBW[i] ; -// } -// for ( int i = cnData.nDeg - mult ; i <= cnData.nDeg ; ++ i) { -// vBC[i] = cnData.vCP[b-cnData.nDeg+i+1] * cnData.vW[b-cnData.nDeg+i+1] ; -// vBW[i] = cnData.vW[b-cnData.nDeg+i+1] ; -// } -// } -// a = b ; -// ++ b ; -// } -// } -// -// // restituisco la curva composita -// return Release( pCrvCompo) ; -//} \ No newline at end of file +} \ No newline at end of file diff --git a/SurfBezier.cpp b/SurfBezier.cpp index c1c91ff..6c7588a 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -1507,6 +1507,7 @@ SurfBezier::GetAuxSurf( void) const Point3d ptMin = std::get<0>( vTrees[i]) ; Point3d ptMax = std::get<1>( vTrees[i]) ; Tree.SetSurf( this, true, ptMin, ptMax) ; + //Tree.BuildTree_test() ; Tree.BuildTree( 5 * LIN_TOL_FINE, 1) ; Tree.GetPolygons( vvPL) ; } @@ -1559,6 +1560,7 @@ SurfBezier::GetLeaves( std::vector>& vLeaves) Point3d ptMin = std::get<0>( vTrees[i]) ; Point3d ptMax = std::get<1>( vTrees[i]) ; Tree.SetSurf( this, true, ptMin, ptMax) ; + //Tree.BuildTree_test() ; Tree.BuildTree( 5 * LIN_TOL_FINE, 1) ; Tree.GetLeaves( vCells) ; for (int k = 0 ; k < (int)vCells.size(); ++ k ) { diff --git a/Tree.cpp b/Tree.cpp index 4eeaec8..4ae1f9c 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -29,7 +29,8 @@ //---------------------------------------------------------------------------- Cell::Cell( void) : m_nId( -1),m_nTop ( -2), m_nBottom( -2), m_nLeft( -2), m_nRight ( -2), m_nParent( -2), m_nDepth( 0), - m_nChild1( -2), m_nChild2( -2), m_nFlag( -1), m_nFlag2( 0), m_nRightEdgeIn( -1), m_ptPbl( ORIG), m_ptPtr(), m_bProcessed( false), m_bSplitVert( true) + m_nChild1( -2), m_nChild2( -2), m_nFlag( -1), m_nFlag2( 0), m_nRightEdgeIn( -1), m_bOnLeftEdge( false), + m_ptPbl( ORIG), m_ptPtr(), m_bProcessed( false), m_bSplitVert( true) { Point3d ptTr ( 1 * SBZ_TREG_COEFF, 1 * SBZ_TREG_COEFF) ; m_ptPtr = ptTr ; @@ -39,7 +40,8 @@ Cell::Cell( void) //---------------------------------------------------------------------------- Cell::Cell( const Point3d& ptBL, const Point3d& ptTR) : m_nId( -1),m_nTop ( -2), m_nBottom( -2), m_nLeft( -2), m_nRight ( -2), m_nParent( -2), m_nDepth( 0), - m_nChild1( -2), m_nChild2( -2), m_nFlag( -1), m_nFlag2( 0), m_nRightEdgeIn( -1), m_ptPbl( ptBL), m_ptPtr( ptTR), m_bProcessed( false), m_bSplitVert( true) + m_nChild1( -2), m_nChild2( -2), m_nFlag( -1), m_nFlag2( 0), m_nRightEdgeIn( -1), m_bOnLeftEdge( false), + m_ptPbl( ptBL), m_ptPtr( ptTR), m_bProcessed( false), m_bSplitVert( true) {} @@ -200,8 +202,18 @@ Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches, const Point3d m_mVert.insert( std::pair( -1, vVert)) ; // se richiesto divido preliminarmente le patches m_vnParents.clear() ; - if ( bSplitPatches && ( nSpanU > 1 || nSpanV > 1)) { + if ( m_bSplitPatches && ( nSpanU > 1 || nSpanV > 1)) { int nId = -1 ; + // se la superficie è chiusa lungo il parametro U, sistemo le adiacenze al bordo + if ( AreSamePointApprox(ptP00, ptP10) && AreSamePointApprox(ptP01, ptP11) ) { + m_mTree[-1].m_nLeft = -1 ; + m_mTree[-1].m_nRight = -1 ; + } + // se la superficie è chiusa lungo il parametro V, sistemo le adiacenze al bordo + if ( ( AreSamePointApprox(ptP00, ptP01) && AreSamePointApprox(ptP10, ptP11) ) ) { + m_mTree[-1].m_nTop = -1 ; + m_mTree[-1].m_nBottom = -1 ; + } for ( int i = 1 ; i < nSpanU ; ++i) { if ( i * SBZ_TREG_COEFF > ptMin.x && i * SBZ_TREG_COEFF < ptTop.x){ m_mTree[nId].SetSplitDirVert( true) ; @@ -225,17 +237,20 @@ Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches, const Point3d GetHeightLeaves( -1, vLeaves) ; m_vnParents = vLeaves ; } - // controllo se la superficie è chiusa. In tal caso la splitto sul parametro su cui è chiusa - // verifico se la superficie è chiusa ed eventualmente sistemo le adiacenze + // controllo se la superficie è chiusa. + // se è chiusa e non ho già fatto split preliminare, splitto sul parametro su cui è chiusa + // e sistemo le adiacenze if ( ( AreSamePointApprox( ptP00, ptP01) || AreSamePointApprox( ptP10, ptP11)) || ( AreSamePointApprox( ptP00, ptP10) || AreSamePointApprox( ptP01, ptP11))) { m_bClosed = true ; - if ( AreSamePointApprox( ptP00, ptP01)) { - m_mTree[-1].m_nTop = -1 ; - m_mTree[-1].m_nBottom = -1 ; + if ( ( AreSamePointApprox( ptP00, ptP01) || AreSamePointApprox( ptP10, ptP11)) && (int) m_mTree.size() == 1) { + if ( AreSamePointApprox( ptP00, ptP01) && AreSamePointApprox( ptP10, ptP11)) { + m_mTree[-1].m_nTop = -1 ; + m_mTree[-1].m_nBottom = -1 ; + } m_mTree[-1].SetSplitDirVert( false) ; Split( -1) ; - // qui devo fare il controllo capped + // qui devo fare il controllo capped ( chiusura a semisfera) // devo controllare se i punti ai parametri U=0 e U=1 sono tutti coincidenti // in caso devo fare uno split nell'altra direzione bool bOk = false ; @@ -255,10 +270,13 @@ Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches, const Point3d Split( 1) ; } } - if ( AreSamePointApprox( ptP00, ptP10)) { + // nella condizione di questo if non controllo eventuali divisioni preliminari, perché ne tengo conto dopo + if ( AreSamePointApprox( ptP00, ptP10) || AreSamePointApprox( ptP01, ptP11)) { if( (int) m_mTree.size() == 1) { - m_mTree[-1].m_nLeft = -1 ; - m_mTree[-1].m_nRight = -1 ; + if ( AreSamePointApprox( ptP00, ptP10) && AreSamePointApprox( ptP01, ptP11)) { + m_mTree[-1].m_nLeft = -1 ; + m_mTree[-1].m_nRight = -1 ; + } m_mTree[-1].SetSplitDirVert( true) ; Split( -1) ; // devo controllare se i punti ai parametri V=0 e V=1 sono tutti coincidenti @@ -280,7 +298,8 @@ Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches, const Point3d Split( 1) ; } } - else if ( (int) m_mTree.size() > 1 && (int) m_mTree.size() < 4) { + // se ho fatto solo 1 split e ho due celle foglie nId = 0 e nId = 1 + else if ( (int) m_mTree.size() > 1 && (int) m_mTree.size() < 4) { // si può mettere anche < 5 m_mTree[0].m_nLeft = -1 ; m_mTree[0].m_nRight = -1 ; m_mTree[1].m_nLeft = -1 ; @@ -295,13 +314,29 @@ Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches, const Point3d // calcolo e salvo la lunghezza reale delle curve di bezier di bordo PtrOwner pCrvV0( m_pSrfBz->GetCurveOnU( 0)) ; - PtrOwner pCrvV1( m_pSrfBz->GetCurveOnU( 1)) ; + PtrOwner pCrvV1( m_pSrfBz->GetCurveOnU( double(nSpanV))) ; PtrOwner pCrvU0( m_pSrfBz->GetCurveOnV( 0)) ; - PtrOwner pCrvU1( m_pSrfBz->GetCurveOnV( 1)) ; + PtrOwner pCrvU1( m_pSrfBz->GetCurveOnV( double(nSpanU))) ; double dLen0 ; pCrvV0->GetApproxLength( dLen0) ; double dLen1 ; pCrvU1->GetApproxLength( dLen1) ; double dLen2 ; pCrvV1->GetApproxLength( dLen2) ; double dLen3 ; pCrvU0->GetApproxLength( dLen3) ; + if ( dLen0 < EPS_ZERO && dLen2 < EPS_ZERO ) { + PtrOwner pCrvV( m_pSrfBz->GetCurveOnU( double(nSpanV) / 2)) ; + pCrvV->GetApproxLength( dLen0) ; + if ( dLen0 < EPS_ZERO ) { + pCrvV.Set( m_pSrfBz->GetCurveOnU( double(nSpanV) / 4)) ; + pCrvV->GetApproxLength( dLen0) ; + } + } + if ( dLen1 < EPS_ZERO && dLen3 < EPS_ZERO ) { + PtrOwner pCrvU( m_pSrfBz->GetCurveOnV( double(nSpanU) / 2)) ; + pCrvU->GetApproxLength( dLen1) ; + if ( dLen1 < EPS_ZERO ) { + pCrvU.Set( m_pSrfBz->GetCurveOnV( double(nSpanU) / 4)) ; + pCrvU->GetApproxLength( dLen1) ; + } + } m_vDim.clear() ; m_vDim.push_back( ( dLen0 > EPS_ZERO ? dLen0 : 1)) ; m_vDim.push_back( ( dLen1 > EPS_ZERO ? dLen1 : 1)) ; @@ -491,6 +526,11 @@ Tree::Split( const int& nId) bool Tree::BuildTree_test( const double& dLinTol, const double& dSideMin, const double& dSideMax) { + // per poter usare questa funzione, anziché quella normale, bisogna: + // - commentare la parte di funzione di SetSurf dove si fanno gli split preliminare + // - se si usa anche la funzione GetLeaves, bisogna anche lì usare BuildTree_test al posto di BuildTree + + //int nCToSplit = -1 ; //celle 0,1 m_mTree[-1].SetSplitDirVert( true) ; @@ -638,17 +678,33 @@ Tree::BuildTree( const double& dLinTol, const double& dSideMin, const double& dS double dLen1 = Dist( ptP10, ptP11) ; double dLen2 = Dist( ptP01, ptP11) ; double dLen3 = Dist( ptP00, ptP01) ; + if ( dLen0 < EPS_ZERO && dLen2 < EPS_ZERO ) { + double dV = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 / SBZ_TREG_COEFF ; + PtrOwner pCrvV( m_pSrfBz->GetCurveOnU( dV)) ; + double dLenU0, dLenU1 ; + pCrvV->GetLengthAtParam( m_mTree[nCToSplit].GetBottomLeft().x / SBZ_TREG_COEFF, dLenU0) ; + pCrvV->GetLengthAtParam( m_mTree[nCToSplit].GetTopRight().x / SBZ_TREG_COEFF, dLenU1) ; + dLen0 = abs( dLenU1 - dLenU0) ; + } + if ( dLen1 < EPS_ZERO && dLen3 < EPS_ZERO ) { + double dU = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 / SBZ_TREG_COEFF ; + PtrOwner pCrvU( m_pSrfBz->GetCurveOnV( dU)) ; + double dLenV0, dLenV1 ; + pCrvU->GetLengthAtParam( m_mTree[nCToSplit].GetBottomLeft().y / SBZ_TREG_COEFF, dLenV0) ; + pCrvU->GetLengthAtParam( m_mTree[nCToSplit].GetTopRight().y / SBZ_TREG_COEFF, dLenV1) ; + dLen1 = abs( dLenV1 - dLenV0) ; + } // verifico che la cella sia da splittare e che eventualmente sia abbastanza grande da poterlo fare double dSideMinVal = 0, dSideMaxVal = 0 ; if ( bVert) { - if ( dLen0 != 0 && dLen2 != 0) - dSideMinVal = std::max( dLen0, dLen2) ; + if ( dLen0 > EPS_ZERO && dLen2 > EPS_ZERO) + dSideMinVal = std::min( dLen0, dLen2) ; else dSideMinVal = std::max( dLen0, dLen2) ; } else { - if ( dLen1 != 0 && dLen3 != 0) - dSideMinVal = std::max( dLen1, dLen3) ; + if ( dLen1 > EPS_ZERO && dLen3 > EPS_ZERO) + dSideMinVal = std::min( dLen1, dLen3) ; else dSideMinVal = std::max( dLen1, dLen3) ; } @@ -657,11 +713,13 @@ Tree::BuildTree( const double& dLinTol, const double& dSideMin, const double& dS // se la cella è abbastanza grande da poter essere divisa ancora, calcolo l'errore di approssimazione bool bSplit = false ; - if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && ( dCurvV > dLinTol || dCurvU > dLinTol)) { + // dSideMinVal potrebbe essere zero se entrambi i lati che dovrei splittare sono collassati in un punto, ma questo non vuol + // dire che non dovrei eseguire lo split + if ( (dSideMinVal / 2 >= dSideMin || dSideMinVal < EPS_SMALL) && dSideMaxVal < dSideMax && ( dCurvV > dLinTol || dCurvU > dLinTol)) { CurveLine cl0010, cl0001, cl1011, cl0111 ; - // U=0 + // V=0 cl0010.Set( ptP00, ptP10) ; - // U=1 + // V=1 cl0111.Set( ptP01, ptP11) ; Point3d pt0010, pt0111, ptBz0, ptBz1, ptBzV ; int nFlag ; @@ -680,10 +738,22 @@ Tree::BuildTree( const double& dLinTol, const double& dSideMin, const double& dS if ( ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetBottomLeft().y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz0) || ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetTopRight().y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz1)) return false ; - DistPointCurve dpc0010( ptBz0, cl0010) ; - DistPointCurve dpc0111( ptBz1, cl0111) ; - dpc0010.GetMinDistPoint( 0, pt0010, nFlag) ; - dpc0111.GetMinDistPoint( 0, pt0111, nFlag) ; + // verifico che la cella non sia uno spicchio in verticale, cioè con ptP00 == ptP01 && ptP10 == ptP11 + // ( vedi disegno sotto per uno spicchio verticale) + // sennò i punti che cerco sono semplicemente i vertici + if ( cl0010.IsValid()) { + DistPointCurve dpc0010( ptBz0, cl0010) ; + dpc0010.GetMinDistPoint( 0, pt0010, nFlag) ; + } + else + pt0010 = ptP00 ; + if ( cl0111.IsValid()) { + DistPointCurve dpc0111( ptBz1, cl0111) ; + dpc0111.GetMinDistPoint( 0, pt0111, nFlag) ; + } + else + pt0111 = ptP01 ; + // curva a parametro U fisso, con V che scorre clV.Set( pt0010, pt0111) ; for ( int v = 0 ; v < nStepsV ; ++ v) { double dV = double ( v) / double ( nStepsV - 1) ; @@ -694,6 +764,20 @@ Tree::BuildTree( const double& dLinTol, const double& dSideMin, const double& dS // distanza di approssimazione locale double dDist ; dpc.GetDist( dDist) ; + // se la cella è uno spicchio, quindi con due lati collassati, devo calcolare in modo diverso dist + // ptP00 == ptP01 + // / \ + // / \ + // / \ + // ( ) + // \ / + // \ / + // \ / + // ptP10 == ptP11 + if ( ! clV.IsValid() && AreSamePointApprox( ptP00, ptP01) && AreSamePointApprox( ptP10, ptP11)) { + DistPointCurve dpcSlice( ptBzV, cl0010) ; + dpcSlice.GetDist( dDist) ; + } if ( dDist > dLinTol) { bSplit = true ; break ; @@ -1726,11 +1810,16 @@ Tree::TraceLoopLabelCell( void) ResetTree() ; INTVECTOR vNeigh, vFirst ; GetRootNeigh( 1, vFirst) ; + for ( int k : vFirst) { + m_mTree[k].m_bOnLeftEdge = true ; + } int nLastLeft = vFirst.back() ; int nCell = vFirst[0] ; GetRightNeigh( nCell, vNeigh) ; // proseguo finché non sono sull'elemento più alto di vFirst e tutti i suoi vicini sono processati/categorizzati bool bAllDone = false ; + // mentre scorro a destra mi basta trovare un vicino da cui non sono passato + // mentre torno indietro a sinistra, mi fermo quando trovo una cella non processata ( con vicini a destra da cui non sono passato) while ( ! bAllDone) { // categorizzo la cella m_mTree[nCell].m_nFlag2 = 1 ; @@ -1738,7 +1827,7 @@ Tree::TraceLoopLabelCell( void) bool bDone = false ; // 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 && ! bDone) || ! m_mTree[nCell].IsProcessed()) { + while ( ! m_mTree[nCell].IsProcessed()) { // 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) { @@ -1762,20 +1851,31 @@ Tree::TraceLoopLabelCell( void) vNeigh.clear() ; GetRightNeigh( nCell, vNeigh) ; bDone = true ; - // controllo che tra i vicini di destra ce ne sia almeno uno non processato + //controllo che tra i vicini di destra ce ne sia almeno uno da cui non sono passato + // ( e controllo che non sia una cella sul lato sinistro ( adiacenza in caso di superficie chiusa)) for ( int t: vNeigh) { - if ( ! m_mTree[t].IsProcessed()) { - bDone = false ; - break ; + if ( m_mTree[t].m_nFlag2 == 0 ) { + if ( ! m_bClosed) { + bDone = false ; + break ; + } + else { + // controllo che non sia sul lato sinistro + if ( ! m_mTree[t].m_bOnLeftEdge) { + bDone = false ; + break ; + } + } } } + m_mTree[nCell].SetProcessed( bDone) ; } } 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 - while ( (int) vNeigh.size() == 0 || m_mTree[nCell].IsProcessed()) { + while ( m_mTree[nCell].IsProcessed()) { // trovo il vicino a sinistra, già categorizzato, più basso vNeigh.clear() ; GetLeftNeigh( nCell, vNeigh) ; @@ -1785,21 +1885,36 @@ Tree::TraceLoopLabelCell( void) break ; } } - // se non ho vicini a sinistra sono tornato sul lato sinistro e quindi devo procedere alla cella più bassa non processata sul lato sinistro - if ( vNeigh.empty()) { - for ( int p = 0 ; p < (int)vFirst.size() ; ++ p) { - if ( m_mTree[vFirst[p]].m_nFlag2 == 0) { - nCell = vFirst[p] ; + if ( ! m_bClosed) { + // se non ho vicini a sinistra sono tornato sul lato sinistro e quindi devo procedere alla cella più bassa non processata sul lato sinistro + if ( vNeigh.empty()) { + for ( int p = 0 ; p < (int)vFirst.size() ; ++ p) { + if ( m_mTree[vFirst[p]].m_nFlag2 == 0) { + nCell = vFirst[p] ; + break ; + } + } + if ( nCell == nLastLeft && m_mTree[nCell].IsProcessed()) { + bAllDone = true ; break ; } } - if ( nCell == nLastLeft && m_mTree[nCell].IsProcessed()) { - // categorizzo - m_mTree[nCell].m_nFlag2 = 1 ; - CategorizeCell( nCell) ; - bAllDone = true ; - break ; + } + else { + // verifico se sono tornato sul lato sinistro, in questo caso procedo con la prima cella di vFirst non processata + if ( m_mTree[nCell].m_bOnLeftEdge) { + for ( int p = 0 ; p < (int) vFirst.size(); ++ p) { + if ( nCell == vFirst[p] && nCell != nLastLeft) { + nCell = vFirst[p + 1] ; + break ; + } + else if ( nCell == nLastLeft && m_mTree[nCell].IsProcessed()){ + bAllDone = true ; + } + } } + if ( bAllDone) + break ; } // controllo se tutti i vicini di destra sono categorizzati vNeigh.clear() ; @@ -2887,7 +3002,7 @@ Tree::AddVertex( const int& nId, const std::vector& vEdgeVertex, Poly return true ; } -//usando i poligoni +//usando i poligoni // deprecato e non funzionante ////---------------------------------------------------------------------------- //bool //Tree::SetRightEdgeIn( int nId, std::vector& vEdgeVertex, PolyLine& plTrimmedPoly) @@ -2959,6 +3074,10 @@ Tree::SetRightEdgeIn( const int& nId) // categorizzo la cella in base a quanta parte del lato destro è conenuta all'interno delle curve di trim // RightEdgeIn -> 0 non contenuto ; 1 contenuto ; 2 in parte contenuto int nPass = (int) m_mTree[nId].m_vInters.size() ; + if ( nPass == 0 ) { + m_mTree[nId].m_nRightEdgeIn = 0 ; + return true ; + } bool bDone = false ; // se ho solo loop interni devo controllare se il più esterno è CCW ( lato destro esterno) o CW ( lato destro interno) if ( m_mTree[nId].m_nFlag == 2) { diff --git a/Tree.h b/Tree.h index f2d6b74..90e42a5 100644 --- a/Tree.h +++ b/Tree.h @@ -76,6 +76,15 @@ struct Inters { //---------------------------------------------------------------------------- class Cell { + // Edge 0 ( Top) + // Edge 4 ( NW) __________________ Edge 7 ( NE) + // | | + // | | + // Edge 1 ( Left) | | Edge 3 ( Right) + // | | + // | | + // |_________________| + // Edge 5 ( SW) Edge 2 (Bottom) Edge 6 ( SE) public : ~Cell( void) ; Cell( void) ; @@ -110,7 +119,8 @@ class Cell // 0 esterna, 1 intersecata, 2 contiene un loop, 3 intersecata e contenente un loop, 4 contenuta in un loop int m_nFlag2 ; // falg che indica se la cella è stata attraversata durante l'ultima fase del labelling int m_nRightEdgeIn ; // 0 right edge fuori, 1 right edge dentro, 2 metà e metà - std::vector m_vInters ; // vettore delle intersezioni della cella con i loop di trim + bool m_bOnLeftEdge ; // flag che indica se la cella è sul lato sinistro ( per superfici chiuse) + std::vector m_vInters ; // vettore delle intersezioni della cella con i loop di trim // ogni elemento del vettore è l'insieme dei punti che caratterizza un atrtaversamento della cella private : @@ -128,7 +138,7 @@ public : Tree( void) ; Tree ( const SurfBezier* pSrfBz, const bool bSplitPatches = true, const Point3d ptMin = ORIG, const Point3d ptMax = ORIG) ; void SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches = true, const Point3d ptMin = ORIG, const Point3d ptMax = ORIG) ; - bool GetIndependentTrees( std::vector>& vTrees) ; + bool GetIndependentTrees( std::vector>& vTrees) ; // calcolo la suddivisione della superficie solo sulle singole bbox dei loop di trim ( unendo quelli vicini) bool BuildTree( const double& dLinTol = LIN_TOL_STD, const double& dSideMin = 1, const double& dSideMax = INFINITO) ; // dSideMax è il massimo per la dimensione maggiore di un triangolo della trimesh // dSideMin è lunghezza minima del lato di una cella nello spazio reale bool BuildTree_test( const double& dLinTol = LIN_TOL_STD, const double& dSideMin = 1, const double& dSideMax = INFINITO) ;