From 9b87de9fa284c86ac4fae0b50f03db00262a03e4 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Thu, 25 Jul 2024 16:25:05 +0200 Subject: [PATCH] EgtGeomKernel : - correzioni e migliorie alla triangolazione con le bezier. --- SurfBezier.cpp | 63 ++++++-- SurfBezier.h | 1 + Tree.cpp | 418 +++++++++++++++---------------------------------- 3 files changed, 178 insertions(+), 304 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index e0c2bf9..b1316f7 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -88,6 +88,7 @@ SurfBezier::Init( int nDegU, int nDegV, int nSpanU, int nSpanV, bool bIsRational else m_vWeCtrl.clear() ; m_nStatus = TO_VERIFY ; + m_nIsPlanar = NOT_CALCULATED ; // imposto ricalcolo della grafica ResetAuxSurf() ; @@ -1583,7 +1584,6 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin) const if ( ! Tri.Make( vPL, vPnt, vTria)) return nullptr ; - //vedo se la polyline 3d che passo io corrisponde a quella che usavo prima POLYLINEVECTOR vPL3d = vvPL3d[c] ; // porto i punti in 3d @@ -1598,6 +1598,17 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin) const } } + // se ho ottenuto meno triangoli di quelli che avrei dovuto avere allora potrei aver avuto un problema in prossimità di un polo + // se comunque ho corrispondenza tra vPnt e vPnt3d allora eseguo la trinagolazione in 3d + if ( ( vPnt.size() - 2 ) != ( vTria.size() ) / 3 && vPnt.size() == vPnt3d.size() ) { + if ( ! Tri.Make( vPL3d, vPnt, vTria)) + return nullptr ; + if ( ( vPnt.size() - 2 ) == ( vTria.size() ) / 3 ) + LOG_INFO( GetEGkLogger(), "Info : Last problem in MakeByEC23(1) RESOLVED") + else + LOG_INFO( GetEGkLogger(), "Info : Last problem in MakeByEC23(1) is the same as the previous one") + } + // controllo per ogni polyline se è stato invertito il vettore dei punti int nCurrPoint = 0 ; for( int i = 0 ; i < int( vPL.size()) ; ++i) { @@ -3197,6 +3208,7 @@ SurfBezier::GetSingleEdge3D( bool bLineOrBezier, int nEdge) const else pCrvBz0->SetControlPoint( p, GetControlPoint( nIndex, nullptr), GetControlWeight( nIndex, nullptr)) ; } + pCrvBz0->Invert() ; pCrvCompo->AddCurve( Release( pCrvBz0)) ; } } @@ -3218,6 +3230,7 @@ SurfBezier::GetSingleEdge3D( bool bLineOrBezier, int nEdge) const else pCrvBz1->SetControlPoint( p, GetControlPoint( nIndex, nullptr), GetControlWeight( nIndex, nullptr)) ; } + pCrvBz1->Invert() ; pCrvCompo->AddCurve( Release( pCrvBz1)) ; } } @@ -3272,19 +3285,40 @@ SurfBezier::GetSingleEdge3D( bool bLineOrBezier, int nEdge) const bool SurfBezier::IsPlanar( void) const { - // costruisco il contorno della superficie unendo gli edge e chiedo se la polyline è piana. - PtrOwner pCCEdge( GetSingleEdge3D( false, 0)) ; - pCCEdge->AddCurve( GetSingleEdge3D( false, 1)) ; - pCCEdge->AddCurve( GetSingleEdge3D( false, 2)) ; - pCCEdge->AddCurve( GetSingleEdge3D( false, 3)) ; + if ( m_nIsPlanar != NOT_CALCULATED) { + switch ( m_nIsPlanar ) { + case PLANAR_SURF : return true ; break ; + case NOT_PLANAR_SURF : return false ; break ; + } + } + PolyLine plApprox ; - pCCEdge->ApproxWithLines( 0.01, 15, 0, plApprox) ; Plane3d plPlane ; - if ( ! plApprox.IsFlat( plPlane, 2 * EPS_SMALL)) - return false ; - // in questo caso se è grado 1 in U e V e ho un unica Patch allora sono sicuro sia piana - if ( m_nDegU == 1 && m_nSpanU == 1 && m_nDegV == 1 && m_nSpanV == 1) // questa condizione da sola non è sufficiente ( posso avere superfici torte anche se i lati sono segmenti) - return true ; + if( ! m_bTrimmed) { + // costruisco il contorno della superficie unendo gli edge e chiedo se la polyline è piana. + PtrOwner pCCEdge( GetSingleEdge3D( false, 0)) ; + pCCEdge->AddCurve( GetSingleEdge3D( false, 1)) ; + pCCEdge->AddCurve( GetSingleEdge3D( false, 2)) ; + pCCEdge->AddCurve( GetSingleEdge3D( false, 3)) ; + pCCEdge->ApproxWithLines( 0.01, 15, 0, plApprox) ; + if ( ! plApprox.IsFlat( plPlane, 2 * EPS_SMALL)){ + m_nIsPlanar = 0 ; + return false ; + } + // in questo caso se è grado 1 in U e V e ho un unica Patch allora sono sicuro sia piana + if ( m_nDegU == 1 && m_nSpanU == 1 && m_nDegV == 1 && m_nSpanV == 1) { + m_nIsPlanar = 1 ; + return true ; + } + } + else { + Point3d ptCtrl ; + bool bOk = true ; + plApprox.AddUPoint( 0, GetControlPoint(0, &bOk)) ; + plApprox.AddUPoint( 1, GetControlPoint(m_nDegU * m_nSpanU, &bOk)) ; + plApprox.AddUPoint( 2, GetControlPoint(( m_nDegU * m_nSpanU + 1) * ( m_nDegV * m_nSpanV + 1), &bOk)) ; + plApprox.AddUPoint( 3, GetControlPoint(( m_nDegU * m_nSpanU + 1) * ( m_nDegV * m_nSpanV), &bOk)) ; + } double dULast ; plApprox.GetLastU( dULast) ; ++ dULast ; @@ -3299,10 +3333,13 @@ SurfBezier::IsPlanar( void) const } } plPlane.Reset() ; - if ( plApprox.IsFlat( plPlane, 2 * EPS_SMALL)) + if ( plApprox.IsFlat( plPlane, 2 * EPS_SMALL)) { + m_nIsPlanar = 1 ; return true ; + } // nel dubbio restituisco false + m_nIsPlanar = 0 ; return false ; } diff --git a/SurfBezier.h b/SurfBezier.h index 86f5b54..9285813 100644 --- a/SurfBezier.h +++ b/SurfBezier.h @@ -224,6 +224,7 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW double m_dTempParam[2] ; // vettore parametri temporanei mutable vector m_mCCEdge ;// vettore dei vettori che contengono le curve compo degli edge della superficie nello spazio 3D mutable ICRVCOMPOPOVECTOR m_vCCLoop ; // vettore dei loop della superficie trimmata + mutable int m_nIsPlanar ; // enum che indica se la superficie è piana ( -1, non è stato calcolato) } ; //----------------------------------------------------------------------------- diff --git a/Tree.cpp b/Tree.cpp index 1e19fe5..de68f01 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -68,43 +68,6 @@ Tree::Tree( const Point3d ptBl, const Point3d ptTr) bool Tree::LimitLoop( PolyLine& pl, POLYLINEVECTOR& vPl, BOOLVECTOR& vbOrientation) const { - // //questo metodo NON VA BENE perchè tiene anche parte dei loop che stanno fuori dal parametrico e quindi il FINDCELL può fallire - // - //// creo la flat region di trim, quella del parametrico e li interseco - //PtrOwner pSfrTrim( GetSurfFlatRegionFromPolyLine( pl)) ; - //bool bInverted = false ; - //if ( ! pSfrTrim->GetNormVersor().IsZplus()) { - // pSfrTrim->Invert() ; - // bInverted = true ; - //} - //PtrOwner pParamTrim( GetSurfFlatRegionRectangle( SBZ_TREG_COEFF * m_nSpanU, SBZ_TREG_COEFF * m_nSpanV)) ; - //if ( ! pParamTrim->Intersect( *pSfrTrim) || ! pParamTrim->IsValid()) { - // if ( ! pParamTrim->Offset( 10 * EPS_SMALL, ICurve::OFF_EXTEND)) - // return false ; - // if ( ! pParamTrim->Intersect( *pSfrTrim) || ! pParamTrim->IsValid()) - // return false ; - // if ( ! pParamTrim->Offset( -10 * EPS_SMALL, ICurve::OFF_EXTEND)) - // return false ; - //} - - //// ricostruisco la curva tenendo solo le parti dentro lo spazio parametrico - //// devo recuperare la polyline dei bordi dei vari chunk creati - //for ( int c = 0 ; c < int( pParamTrim->GetChunkCount()) ; ++c) { - // for ( int l = 0 ; l < pParamTrim->GetLoopCount(c) ; ++l) { - // PtrOwner pCrv ( pParamTrim->GetLoop( c, l)) ; - // if ( bInverted) - // pCrv->Invert() ; - // PolyLine plApprox ; - // double dLinTol = 10 * EPS_SMALL, dAngTolDeg = 5 ; - // int nType = 0 ; - // pCrv->ApproxWithLines( dLinTol, dAngTolDeg, nType, plApprox) ; - // // aggiungo la polyline del chunk - // vPl.push_back( plApprox) ; - // } - //} - - - //// CON LE CURVE ( INTERSEZIONI CON BORDO PARAMETRICO) PtrOwner pCCEdge( CreateCurveComposite()) ; pCCEdge->AddPoint( m_mTree.at(-1).GetTopRight()) ; @@ -321,121 +284,124 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi m_mVert.insert( pair( -1, vVert)) ; // se richiesto divido preliminarmente le patches m_vnParents.clear() ; - 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 ; - m_bClosedU = true ; - } - // 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 ; - m_bClosedV = true ; - } - for ( int i = 1 ; i < nSpanU ; ++i) { - // chiedo che il taglio disti dal bordo almeno il 2% della singola patch (1000 x 1000) - if ( i * SBZ_TREG_COEFF > ptMin.x + 5 && i * SBZ_TREG_COEFF < ptTop.x - 5){ - m_mTree[nId].SetSplitDirVert( true) ; - if ( Split( nId, i * SBZ_TREG_COEFF)) { - ++ nId ; - ++ nId ; - } + bool bIsPlanar = m_pSrfBz->IsPlanar() ; + if( ! bIsPlanar) { + 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 ; + m_bClosedU = true ; } - } - INTVECTOR vLeaves ; - GetHeightLeaves( -1, vLeaves) ; - for ( int nId : vLeaves) { - for ( int j = nSpanV - 1 ; j > 0 ; --j) { - // chiedo che il taglio disti dal bordo almeno il 2% della singola patch (1000 x 1000) - if ( j * SBZ_TREG_COEFF > ptMin.y + 5 && j * SBZ_TREG_COEFF < ptTop.y - 5){ - m_mTree[nId].SetSplitDirVert( false) ; - if ( Split( nId, j * SBZ_TREG_COEFF)) - nId = m_mTree[nId].m_nChild2 ; - } - } - } - vLeaves.clear() ; - } - // 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) || AreSamePointApprox( ptP10, ptP11)) && (int) m_mTree.size() == 1) { - if ( AreSamePointApprox( ptP00, ptP01) && AreSamePointApprox( ptP10, ptP11)) { + // 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 ; m_bClosedV = true ; } - m_mTree[-1].SetSplitDirVert( false) ; - Split( -1) ; - // 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 ; - bool bPole0 = true, bPole1 = true ; - Point3d ptU0, ptU1 ; - // controllo se tutti i punti di controllo sull'isoparametrica sono uguali - for ( int i = 1 ; i < nDegV * nSpanV + 1 ; ++ i) { - ptU0 = m_pSrfBz->GetControlPoint( i * ( nDegU * nSpanU + 1), &bOk) ; - bPole0 = bPole0 && AreSamePointApprox( ptP00, ptU0) ; - ptU1 = m_pSrfBz->GetControlPoint( ( i + 1) * ( nDegU * nSpanU + 1) - 1, &bOk) ; - bPole1 = bPole1 && AreSamePointApprox( ptP10, ptU1) ; - } - m_vbPole[1] = bPole0 ; - m_vbPole[3] = bPole1 ; - if ( bPole0 && bPole1) { - m_mTree[0].SetSplitDirVert( true) ; - Split( 0) ; - m_mTree[1].SetSplitDirVert( true) ; - Split( 1) ; - } - } - // nella condizione di questo if non controllo eventuali divisioni preliminari, perché ne tengo conto dopo - if ( AreSamePointApprox( ptP00, ptP10) || AreSamePointApprox( ptP01, ptP11)) { - if ( m_mTree.size() == 1) { - if ( AreSamePointApprox( ptP00, ptP10) && AreSamePointApprox( ptP01, ptP11)) { - m_mTree[-1].m_nLeft = -1 ; - m_mTree[-1].m_nRight = -1 ; - m_bClosedU = true ; + for ( int i = 1 ; i < nSpanU ; ++i) { + // chiedo che il taglio disti dal bordo almeno il 2% della singola patch (1000 x 1000) + if ( i * SBZ_TREG_COEFF > ptMin.x + 5 && i * SBZ_TREG_COEFF < ptTop.x - 5){ + m_mTree[nId].SetSplitDirVert( true) ; + if ( Split( nId, i * SBZ_TREG_COEFF)) { + ++ nId ; + ++ nId ; + } } - m_mTree[-1].SetSplitDirVert( true) ; + } + INTVECTOR vLeaves ; + GetHeightLeaves( -1, vLeaves) ; + for ( int nId : vLeaves) { + for ( int j = nSpanV - 1 ; j > 0 ; --j) { + // chiedo che il taglio disti dal bordo almeno il 2% della singola patch (1000 x 1000) + if ( j * SBZ_TREG_COEFF > ptMin.y + 5 && j * SBZ_TREG_COEFF < ptTop.y - 5){ + m_mTree[nId].SetSplitDirVert( false) ; + if ( Split( nId, j * SBZ_TREG_COEFF)) + nId = m_mTree[nId].m_nChild2 ; + } + } + } + vLeaves.clear() ; + } + // 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) || 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_bClosedV = true ; + } + m_mTree[-1].SetSplitDirVert( false) ; Split( -1) ; - // devo controllare se i punti ai parametri V=0 e V=1 sono tutti coincidenti + // 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 ; bool bPole0 = true, bPole1 = true ; - Point3d ptV0, ptV1 ; - // controllo se tutti i punti sull'isoparametrica sono uguali - for ( int i = 1 ; i < nDegU * nSpanU + 1 ; ++ i) { - ptV0 = m_pSrfBz->GetControlPoint( i, &bOk) ; - bPole0 = bPole0 && AreSamePointApprox( ptP00, ptV0) ; - ptV1 = m_pSrfBz->GetControlPoint( i + ( nDegU * nSpanU + 1) * ( nDegV * nSpanV), &bOk) ; - bPole1 = bPole1 && AreSamePointApprox( ptP01, ptV1) ; + Point3d ptU0, ptU1 ; + // controllo se tutti i punti di controllo sull'isoparametrica sono uguali + for ( int i = 1 ; i < nDegV * nSpanV + 1 ; ++ i) { + ptU0 = m_pSrfBz->GetControlPoint( i * ( nDegU * nSpanU + 1), &bOk) ; + bPole0 = bPole0 && AreSamePointApprox( ptP00, ptU0) ; + ptU1 = m_pSrfBz->GetControlPoint( ( i + 1) * ( nDegU * nSpanU + 1) - 1, &bOk) ; + bPole1 = bPole1 && AreSamePointApprox( ptP10, ptU1) ; } - m_vbPole[0] = bPole0 ; - m_vbPole[2] = bPole1 ; + m_vbPole[1] = bPole0 ; + m_vbPole[3] = bPole1 ; if ( bPole0 && bPole1) { - m_mTree[0].SetSplitDirVert( false) ; + m_mTree[0].SetSplitDirVert( true) ; Split( 0) ; - m_mTree[1].SetSplitDirVert( false) ; + m_mTree[1].SetSplitDirVert( true) ; Split( 1) ; } } - // se ho fatto solo 1 split orizzontale e ho due celle foglie nId = 0 e nId = 1 - else if ( (int) m_mTree.size() > 1 && (int) m_mTree.size() < 4 && ! m_mTree.at(-1).IsSplitVert()) { // si può mettere anche < 5 - m_mTree[0].m_nLeft = -1 ; - m_mTree[0].m_nRight = -1 ; - m_mTree[1].m_nLeft = -1 ; - m_mTree[1].m_nRight = -1 ; - m_mTree[0].SetSplitDirVert( true) ; - Split( 0) ; - m_mTree[1].SetSplitDirVert( true) ; - Split( 1) ; + // nella condizione di questo if non controllo eventuali divisioni preliminari, perché ne tengo conto dopo + if ( AreSamePointApprox( ptP00, ptP10) || AreSamePointApprox( ptP01, ptP11)) { + if ( m_mTree.size() == 1) { + if ( AreSamePointApprox( ptP00, ptP10) && AreSamePointApprox( ptP01, ptP11)) { + m_mTree[-1].m_nLeft = -1 ; + m_mTree[-1].m_nRight = -1 ; + m_bClosedU = true ; + } + m_mTree[-1].SetSplitDirVert( true) ; + Split( -1) ; + // devo controllare se i punti ai parametri V=0 e V=1 sono tutti coincidenti + // in caso devo fare uno split nell'altra direzione + bool bOk = false ; + bool bPole0 = true, bPole1 = true ; + Point3d ptV0, ptV1 ; + // controllo se tutti i punti sull'isoparametrica sono uguali + for ( int i = 1 ; i < nDegU * nSpanU + 1 ; ++ i) { + ptV0 = m_pSrfBz->GetControlPoint( i, &bOk) ; + bPole0 = bPole0 && AreSamePointApprox( ptP00, ptV0) ; + ptV1 = m_pSrfBz->GetControlPoint( i + ( nDegU * nSpanU + 1) * ( nDegV * nSpanV), &bOk) ; + bPole1 = bPole1 && AreSamePointApprox( ptP01, ptV1) ; + } + m_vbPole[0] = bPole0 ; + m_vbPole[2] = bPole1 ; + if ( bPole0 && bPole1) { + m_mTree[0].SetSplitDirVert( false) ; + Split( 0) ; + m_mTree[1].SetSplitDirVert( false) ; + Split( 1) ; + } + } + // se ho fatto solo 1 split orizzontale e ho due celle foglie nId = 0 e nId = 1 + else if ( (int) m_mTree.size() > 1 && (int) m_mTree.size() < 4 && ! m_mTree.at(-1).IsSplitVert()) { // si può mettere anche < 5 + m_mTree[0].m_nLeft = -1 ; + m_mTree[0].m_nRight = -1 ; + m_mTree[1].m_nLeft = -1 ; + m_mTree[1].m_nRight = -1 ; + m_mTree[0].SetSplitDirVert( true) ; + Split( 0) ; + m_mTree[1].SetSplitDirVert( true) ; + Split( 1) ; + } } } } @@ -1003,6 +969,8 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) } // bilineare else { + bool bIsPlanar = m_pSrfBz->IsPlanar() ; + while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { if ( m_mTree[nCToSplit].IsLeaf()) { // vertici della cella @@ -1079,7 +1047,7 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) } } } - else { + else if ( ! bIsPlanar){ dErr = 1. / 4. * ( ( ptP00 - ptP01) + ( ptP11 - ptP10)).Len() ; //int dErr2 = 1. / 4. * ( ( ptP10 - ptP01) + ( ptP11 - ptP00)).Len() ; //correzione che mi verrebbe intuitiva, ma che fa dividere la superficie molto di più ( probabilmente troppo)!! quindi probabilmente sbagliata } @@ -1557,16 +1525,6 @@ Tree::GetDepth( int nId, int nRef = -2) const return i ; } -////---------------------------------------------------------------------------- -//struct generator -//{ -// int value ; -// generator( void) -// { value = -1 ; } -// int operator() () -// { return ++value ; } -//} ; - //---------------------------------------------------------------------------- bool Tree::GetPolygons( POLYLINEMATRIX& vvPolygons) @@ -1792,7 +1750,7 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygonsBasic, POLYLINEVECTOR& vPolygon if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1){ // se la superficie è chiusa lungo il parametro U e le celle vicine right sono sul lato Left // devo aggiungere i vertici tenendo conto della periodicità dello spazio parametrico. - vnVert.push_back( int(vVertices.size())) ; + vnVert.push_back( int(vVertices.size() - 1)) ; if ( m_bClosedU && m_mTree.at( vNeigh[0]).m_bOnLeftEdge ) { for ( int j : vNeigh) { Point3d pt( m_mTree.at( nId).GetTopRight().x, m_mTree.at(j).GetBottomLeft().y) ; @@ -1825,7 +1783,7 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygonsBasic, POLYLINEVECTOR& vPolygon if ( ! vNeigh.empty() && vNeigh.size() != 1) { // se la superficie è chiusa lungo il parametro V e la cella è sul lato top // devo aggiungere i vertici tenendo conto della periodicità dello spazio parametrico. - vnVert.push_back( int(vVertices.size())) ; + vnVert.push_back( int(vVertices.size() - 1)) ; if ( m_bClosedV && m_mTree.at( nId).m_bOnTopEdge) { for ( int j : vNeigh) { Point3d pt( m_mTree.at( j).GetBottomLeft().x, m_mTree.at( nId).GetTopRight().y) ; @@ -1851,7 +1809,7 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygonsBasic, POLYLINEVECTOR& vPolygon if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) { // se la superficie è chiusa lungo il parametro U e la cella è sul lato left // devo aggiungere i vertici tenendo conto della periodicità dello spazio parametrico. - vnVert.push_back( int(vVertices.size())) ; + vnVert.push_back( int(vVertices.size() - 1)) ; if ( m_bClosedU && m_mTree.at( nId).m_bOnLeftEdge) { for ( int j : vNeigh) { Point3d pt( m_mTree.at( nId).GetBottomLeft().x, m_mTree.at(j).GetTopRight().y) ; @@ -2236,40 +2194,6 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& cl, INTVECTOR vCells } // rilancio la rigida ricerca nCells = FindCell( ptIntersPlus, cl, vCells, true) ; - - /////////////////////////// questa versione funziona, ma forse potrebbe fallire in alcuni casi/// - // for ( int nCell : vCells) { - // if ( ptToAssign.x > m_mTree.at( nCell).GetBottomLeft().x - EPS_SMALL && ptToAssign.x < m_mTree.at( nCell).GetTopRight().x + EPS_SMALL && - // ptToAssign.y > m_mTree.at( nCell).GetBottomLeft().y - EPS_SMALL && ptToAssign.y < m_mTree.at( nCell).GetTopRight().y + EPS_SMALL) { - // nId = nCell ; - // nCells.push_back( nId) ; - // } - // } - // if ( (int)nCells.size() == 1) - // return nCells ; - // // sono su vertice o un lato, quindi avanzo con il parametro lungo la curva - // else if ( (int)nCells.size() > 1 ) { - // // la CurveLine è il segmento di trim su cui giace ptToAssign - // Point3d ptIntersPlus ; - // Vector3d vtDir ; - // cl.GetStartDir( vtDir) ; - // // mi sposto appena più avanti di ptToAssign - // // se la curva è orientata come l'asse x o y mi sto muovendo su un lato e sarò ancora sul lato, quindi dovrei ruotare il vettore a destra prima di spostarmi - // if ( abs( vtDir.x) >= 1 - EPS_SMALL || abs( vtDir.y) >= 1 - EPS_SMALL) - // vtDir.Rotate( Z_AX, -45) ; - // ptIntersPlus = ptToAssign + vtDir * EPS_SMALL ; - // // se sono finito fuori dallo spazio parametrico giro invece a sinistra - // if ( ptIntersPlus.x < m_mTree.at( -1).GetBottomLeft().x - EPS_SMALL || ptIntersPlus.x > m_mTree.at( -1).GetTopRight().x + EPS_SMALL|| - // ptIntersPlus.y < m_mTree.at( -1).GetBottomLeft().y - EPS_SMALL || ptIntersPlus.y > m_mTree.at( -1).GetTopRight().y + EPS_SMALL) { - // vtDir.Rotate( Z_AX, 90) ; - // ptIntersPlus = ptToAssign + vtDir * EPS_SMALL ; - // } - // nCells = FindCell( ptIntersPlus, cl, vCells) ; - // } - //// se vuoto allora il punto non è in nessuna delle celle passate in input - // else - // return nCells ; - ////////////////////////////////////////////////////////////////////////// } return nCells ; @@ -2405,19 +2329,13 @@ Tree::TraceLoopLabelCell( const POLYLINEVECTOR& vplPolygons) // aggiorno la polyline splittata UpdateSplitLoop( plLoopSplit, nPtLoopSplit, vptInters.back()) ; } - // VERSIONE NUOVA // controllo di aggiungere un punto abbastanza distante dal precedente - if( ! AreSamePointEpsilon( vptInters.back(), ptCurr, 2 * EPS_SMALL)) { + if( ! AreSamePointEpsilon( vptInters.back(), ptCurr, 10 * EPS_SMALL)) { // aggiungo la fine del segmento nel vettore delle intersezioni vptInters.push_back( ptCurr) ; // aggiorno la polyline splittata UpdateSplitLoop( plLoopSplit, nPtLoopSplit, ptCurr) ; } - ////VECCHIA VERSIONE - //// aggiungo la fine del segmento nel vettore delle intersezioni - //vptInters.push_back( ptCurr) ; - //// aggiorno la polyline splittata - //UpdateSplitLoop( plLoopSplit, nPtLoopSplit, ptCurr) ; } if ( nId == nFirstCell) vptInters.pop_back() ; @@ -2626,91 +2544,6 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, const PolyLine& plPolygon, int nEdge ; // flag che indica il lato su cui ho l'intersezione a partire dal lato top in senso antiorario Point3d ptInters ; - //CurveLine clEdge , clEdge2 ; - //Point3d ptStart , ptEnd ; - //clTrim.GetStartPoint( ptStart) ; - //clTrim.GetEndPoint( ptEnd) ; - //// trovo da quale lato sto uscendo - ////int nEdge ; // flag che indica il lato su cui ho l'intersezione a partire dal lato top in senso antiorario - //// oltre il 3 sono le celle adiacenti in diagonale al vertice-> 4 corrisponde al ptTl e da lì in senso antiorario - //// -1 se la curva è sempre dentro la cella - ////int nEdge2 ; - //if ( ptEnd.y >= ptTR.y && ptEnd.x <= ptTR.x) { - // //nEdge = 0 ; - // // lato sopra - // clEdge.Set( ptTR, ptTl) ; - // // lato sinistro - // if ( ptEnd.x < ptBL.x) { - // //nEdge2 = 1 ; - // clEdge2.Set( ptTl, ptBL) ; - // } - //} - //else if ( ptEnd.x <= ptBL.x && ptEnd.y <= ptTR.y) { - // nEdge = 1 ; - // // lato sinistro - // clEdge.Set( ptTl, ptBL) ; - // // lato sotto - // if ( ptEnd.y < ptBL.y) { - // //nEdge2 = 2 ; - // clEdge2.Set( ptBL, ptBr) ; - // } - //} - //else if ( ptEnd.y <= ptBL.y && ptEnd.x >= ptBL.x) { - // nEdge = 2 ; - // // lato sotto - // clEdge.Set( ptBL, ptBr) ; - // // lato destro - // if ( ptEnd.x > ptTR.x) { - // //nEdge2 = 3 ; - // clEdge2.Set( ptBr, ptTR) ; - // } - //} - //else if ( ptEnd.x >= ptTR.x && ptEnd.y >= ptBL.y) { - // nEdge = 3 ; - // // lato desto - // clEdge.Set( ptBr, ptTR) ; - // // lato sopra - // if ( ptEnd.y > ptTR.y) { - // //nEdge2 = 0 ; - // clEdge2.Set( ptTR, ptTl) ; - // } - //} - //else - // return false ; - - //bool bIntersFound = false ; - //// intersezione e controlli - //IntersLineLine illExit( clTrim, clEdge, true) ; - //IntCrvCrvInfo aInfo, aInfo2 ; - //if ( ! illExit.GetIntCrvCrvInfo( aInfo)) { - // bIntersFound = false ; - // if ( ! clEdge2.IsValid()) - // return false ; - //} - //else { - // bIntersFound = true ; - // if ( aInfo.bOverlap) - // ptInters = aInfo.IciA[1].ptI ; - // else - // ptInters = aInfo.IciA[0].ptI ; - //} - //if ( clEdge2.IsValid() && ! bIntersFound){ - // IntersLineLine illExit2( clTrim, clEdge2, true) ; - // // verifico su quale dei due lati ho l'intersezione - // if ( ! illExit2.GetIntCrvCrvInfo( aInfo2)) - // bIntersFound = false ; - // else { - // bIntersFound = true ; - // //// solo intersezione sul lato 2 - // if ( aInfo2.bOverlap) - // ptInters = aInfo2.IciA[1].ptI ; - // else - // ptInters = aInfo2.IciA[0].ptI ; - // } - //} - //if ( ! bIntersFound) - // return false ; - PtrOwner pCC( CreateCurveComposite()) ; PolyLine plSimplePolygon ; plSimplePolygon = plPolygon ; @@ -2765,7 +2598,7 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, const PolyLine& plPolygon, else if ( nEdge == 7) ptInters = ptTR ; // aggiungo il nuovo punto al vettore delle intersezioni - if ( (int)vptInters.size() == 0 || ! AreSamePointEpsilon( ptInters , vptInters.back(), 2 * EPS_SMALL)) + if ( (int)vptInters.size() == 0 || ! AreSamePointEpsilon( ptInters , vptInters.back(), 10 * EPS_SMALL)) vptInters.push_back( ptInters) ; else { // se l'ultimo punto del vettore delle intersezioni è quasi uguale al punto che devo aggiungere allora lo sostituisco con quest'ultimo @@ -3140,15 +2973,13 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX } else { double dPar = 0 ; - bool bAdvanced = false ; while ( plCell.GetNextUPoint( &dPar, &ptToAdd) && ! AreSamePointExact( ptToAdd, ptNextVert)) { vEdgeVertex[j].push_back( ptToAdd) ; if ( dPar > 0) plCell3d.GetNextPoint( pt3d) ; vEdgeVertex3d[j].push_back( pt3d) ; - bAdvanced = true ; } - if ( ! bAdvanced && dPar > 0) + if ( dPar > 0) plCell3d.GetNextPoint( pt3d) ; } } @@ -3198,7 +3029,9 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX Vector3d vEdge ; // estendo: se l'ultimo tratto è sovrapposto e controverso allora elimino l'ultimo punto bool bNotEquiverseOverlap = false ; - if ( nEdge == 0 || nEdge == 7 ) { + int nEdgeLast = -1 ; + OnWhichEdge(nId,ptLast, nEdgeLast) ; + if ( (nEdge == 0 || nEdge == 7) && nEdge == nEdgeLast) { vEdge.Set( 1,0,0) ; if ( AreOppositeVectorApprox( vLast, vEdge)) { plTrimmedPoly.EraseLastUPoint() ; @@ -3207,7 +3040,7 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX bNotEquiverseOverlap = true ; } } - else if ( nEdge == 1 || nEdge == 4 ) { + else if ( ( nEdge == 1 || nEdge == 4 ) && nEdge == nEdgeLast) { vEdge.Set( 0,-1,0) ; if ( AreOppositeVectorApprox( vLast, vEdge)) { plTrimmedPoly.EraseLastUPoint() ; @@ -3216,7 +3049,7 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX bNotEquiverseOverlap = true ; } } - else if ( nEdge == 2 || nEdge == 5 ) { + else if ( ( nEdge == 2 || nEdge == 5) && nEdge == nEdgeLast) { vEdge.Set( -1,0,0) ; if ( AreOppositeVectorApprox( vLast, vEdge)) { plTrimmedPoly.EraseLastUPoint() ; @@ -3225,7 +3058,7 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX bNotEquiverseOverlap = true ; } } - else if ( nEdge == 3 || nEdge == 6 ) { + else if ( ( nEdge == 3 || nEdge == 6) && nEdge == nEdgeLast) { vEdge.Set( 0,1,0) ; if ( AreOppositeVectorApprox( vLast, vEdge)) { plTrimmedPoly.EraseLastUPoint() ; @@ -3313,8 +3146,9 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX else if ( ! bNotCameBack){ Point3d ptStart ; plTrimmedPoly.GetFirstPoint( ptStart) ; + Point3d ptLast ; plTrimmedPoly.GetLastPoint( ptLast) ; for ( int p = 1 ; p < (int) vEdgeVertex[nEdge].size() ; ++ p) { - if ( CheckIfBefore( nEdge, vEdgeVertex[nEdge][p], ptStart)) { + if ( CheckIfBefore( nEdge, vEdgeVertex[nEdge][p], ptStart) && CheckIfBefore( nEdge, ptLast, vEdgeVertex[nEdge][p])) { plTrimmedPoly.AddUPoint( c, vEdgeVertex[nEdge][p]) ; plTrimmedPoly3d.AddUPoint( c, vEdgeVertex3d[nEdge][p]) ; ++ c ; @@ -3348,8 +3182,9 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX // aggiorno le condizioni per il while bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ; } + Point3d ptLast ; plTrimmedPoly.GetLastPoint( ptLast) ; for ( int p = 1 ; p < (int) vEdgeVertex[nEdge].size() ; ++ p) { - if ( CheckIfBefore( nEdge, vEdgeVertex[nEdge][p], ptStart)) { + if ( CheckIfBefore( nEdge, vEdgeVertex[nEdge][p], ptStart) && CheckIfBefore( nEdge, ptLast, vEdgeVertex[nEdge][p])) { plTrimmedPoly.AddUPoint( c, vEdgeVertex[nEdge][p]) ; plTrimmedPoly3d.AddUPoint( c, vEdgeVertex3d[nEdge][p]) ; ++ c ; @@ -3458,10 +3293,11 @@ Tree::CreateIslandAndHoles( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATR vPolygons.push_back( vCellPolygons) ; ++ nPoly ; if ( bForTriangulation) { - plInLoop3d.AddUPoint( 0, m_mVert[nId][2]); - plInLoop3d.AddUPoint( 1, m_mVert[nId][3]); - plInLoop3d.AddUPoint( 2, m_mVert[nId][0]); - plInLoop3d.AddUPoint( 3, m_mVert[nId][1]); + plInLoop3d.AddUPoint( 0, m_mVert[nId][2]) ; + plInLoop3d.AddUPoint( 1, m_mVert[nId][3]) ; + plInLoop3d.AddUPoint( 2, m_mVert[nId][0]) ; + plInLoop3d.AddUPoint( 3, m_mVert[nId][1]) ; + plInLoop3d.Close() ; vCellPolygons3d.push_back( plInLoop3d) ; vPolygons3d.push_back( vCellPolygons3d) ; vCellPolygons3d.clear() ; @@ -3884,7 +3720,7 @@ Tree::AddVertex( int nId, const PNTMATRIX& vEdgeVertex, const PNTMATRIX& vEdgeVe bool Tree::SetRightEdgeIn( int nId) { - // categorizzo la cella in base a quanta parte del lato destro è conenuta all'interno delle curve di trim + // categorizzo la cella in base a quanta parte del lato destro è contenuta 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) {