diff --git a/SurfBezier.cpp b/SurfBezier.cpp index bbf3689..26339b9 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -1498,15 +1498,18 @@ SurfBezier::GetAuxSurf( void) const return m_pSTM ; // costruttore della superficie - - Tree Tree( this, true) ; - //Tree.BuildTree_test() ; - Tree.BuildTree( 0.05, 1) ; - //Tree.BuildTree( 0.2, 5) ; - //Tree.BuildTree( 0.5, 10) ; - //Tree.BuildTree( 1, 25) ; vector vvPL ; - Tree.GetPolygons( vvPL) ; + Tree Tree( this, true) ; + std::vector> vTrees ; + Tree.GetIndependentTrees( vTrees) ; + for ( int i = 0 ; i < (int) vTrees.size() ; ++ i) { + Point3d ptMin = std::get<0>( vTrees[i]) ; + Point3d ptMax = std::get<1>( vTrees[i]) ; + Tree.SetSurf( this, true, ptMin, ptMax) ; + Tree.BuildTree( 5 * LIN_TOL_FINE, 1) ; + Tree.GetPolygons( vvPL) ; + } + PtrOwner pSrfTm( CreateBasicSurfTriMesh()) ; StmFromTriangleSoup stmSoup ; if ( ! stmSoup.Start()) @@ -1547,18 +1550,21 @@ SurfBezier::GetAuxSurf( void) const bool SurfBezier::GetLeaves( std::vector>& vLeaves) const { - Tree Tree( this, true) ; - //Tree.BuildTree_test() ; - Tree.BuildTree( 0.05, 1) ; - //Tree.BuildTree( 0.2, 5) ; - //Tree.BuildTree( 0.5, 10) ; - //Tree.BuildTree( 1, 25) ; std::vector vCells ; - Tree.GetLeaves( vCells) ; - for (int k = 0 ; k < (int)vCells.size(); ++ k ) { - std::tuple tCell ; - tCell = make_tuple( vCells[k].m_nId, vCells[k].GetBottomLeft(), vCells[k].GetTopRight()) ; - vLeaves.push_back( tCell) ; + Tree Tree( this, true) ; + std::vector> vTrees ; + Tree.GetIndependentTrees( vTrees) ; + for ( int i = 0 ; i < (int) vTrees.size() ; ++ i) { + Point3d ptMin = std::get<0>( vTrees[i]) ; + Point3d ptMax = std::get<1>( vTrees[i]) ; + Tree.SetSurf( this, true, ptMin, ptMax) ; + Tree.BuildTree( 5 * LIN_TOL_FINE, 1) ; + Tree.GetLeaves( vCells) ; + for (int k = 0 ; k < (int)vCells.size(); ++ k ) { + std::tuple tCell ; + tCell = make_tuple( vCells[k].m_nId, vCells[k].GetBottomLeft(), vCells[k].GetTopRight()) ; + vLeaves.push_back( tCell) ; + } } return true ; } diff --git a/Tree.cpp b/Tree.cpp index 6017b2e..ce186fa 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -24,6 +24,7 @@ #include "/EgtDev/Include/EGkPolyLine.h" #include "/EgtDev/Include/EGkDistPointCurve.h" #include "/EgtDev/Include/EGkCurve.h" +#include "DistPointCrvComposite.h" //---------------------------------------------------------------------------- Cell::Cell( void) @@ -77,10 +78,10 @@ Tree::Tree( void) } //---------------------------------------------------------------------------- -Tree::Tree( const SurfBezier* pSrfBz, const bool bSplitPatches) - : m_bBilinear( false), m_bMulti( false), m_bClosed( false), m_bSplitPatches( bSplitPatches) +Tree::Tree( const SurfBezier* pSrfBz, const bool bSplitPatches, const Point3d ptMin, const Point3d ptMax) + : m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosed( false), m_bSplitPatches( true) { - SetSurf( pSrfBz, m_bSplitPatches) ; + SetSurf( pSrfBz, bSplitPatches, ptMin, ptMax) ; } //---------------------------------------------------------------------------- @@ -90,8 +91,20 @@ Tree::~Tree( void) //---------------------------------------------------------------------------- void -Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches) +Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches, const Point3d ptMin, const Point3d ptMax) { + // pulisco i vettori membri + m_vnLeaves.clear() ; + m_vnParents.clear() ; + m_mVert.clear() ; + m_vLoop.clear() ; + m_mChunk.clear() ; + m_vPlApprox.clear() ; + m_vChunk.clear() ; + m_vPolygons.clear() ; + + + m_pSrfBz = pSrfBz ; m_bSplitPatches = bSplitPatches ; // le coordinate delle celle sono nello spazio parametrico @@ -113,9 +126,8 @@ Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches) INTVECTOR vChunk ; // recupero la superficie di trim per avere accesso diretto ai loop e mantenendo le informazioni sui chunk - Frame3d frSurf ; PtrOwner pTrimReg( m_pSrfBz->GetTrimRegion()->Clone()) ; - double dLinTol = 0.01 ; // questo è riferito allo spazio parametrico perché le curve di loop sono già state riscalate!!!!!! + double dLinTol = 0.01 ; // questo è riferito allo spazio parametrico double dAngTolDeg = 5 ; for ( int i = 0 ; i < pTrimReg->GetChunkCount() ; ++ i) { PtrOwner pChunk( pTrimReg->CloneChunk( i)) ; @@ -157,125 +169,225 @@ Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches) return dArea1 > dArea2 ;}) ; } // salvo i vertici 3d della cella root - Point3d ptBottom ( 0, 0) ; Point3d ptTop( nSpanU * SBZ_TREG_COEFF, nSpanV * SBZ_TREG_COEFF) ; - Cell cRoot( ptBottom, ptTop) ; + bool bLimited = false ; + if ( ! AreSamePointExact( ptMax,ORIG) && ! AreSamePointExact( ptMax,ptTop)) { + ptTop = ptMax ; + bLimited = true ; + } + m_mTree.clear() ; + Cell cRoot( ptMin, ptTop) ; m_mTree.insert( std::pair< int, Cell>( -1, cRoot)) ; Point3d ptP00, ptP10, ptP11, ptP01 ; bool bOk = false ; + if ( ! bLimited) { + ptP00 = m_pSrfBz->GetControlPoint( 0, &bOk) ; + ptP10 = m_pSrfBz->GetControlPoint( nDegU * nSpanU, &bOk) ; + ptP11 = m_pSrfBz->GetControlPoint( ( nDegU * nSpanU + 1) * ( nDegV * nSpanV + 1) - 1, &bOk) ; + ptP01 = m_pSrfBz->GetControlPoint( ( nDegU * nSpanU + 1) * ( nDegV * nSpanV), &bOk) ; + } + else { + m_pSrfBz->GetPointD1D2( ptMin.x / SBZ_TREG_COEFF, ptMin.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00) ; + m_pSrfBz->GetPointD1D2( ptMax.x / SBZ_TREG_COEFF, ptMin.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10) ; + m_pSrfBz->GetPointD1D2( ptMax.x / SBZ_TREG_COEFF, ptMax.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11) ; + m_pSrfBz->GetPointD1D2( ptMin.x / SBZ_TREG_COEFF, ptMax.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01) ; + } PNTVECTOR vVert ; - ptP00 = m_pSrfBz->GetControlPoint( 0, &bOk) ; vVert.push_back( ptP00) ; - ptP10 = m_pSrfBz->GetControlPoint( nDegU * nSpanU, &bOk) ; vVert.push_back( ptP10) ; - ptP11 = m_pSrfBz->GetControlPoint( ( nDegU * nSpanU + 1) * ( nDegV * nSpanV + 1) - 1, &bOk) ; vVert.push_back( ptP11) ; - ptP01 = m_pSrfBz->GetControlPoint( ( nDegU * nSpanU + 1) * ( nDegV * nSpanV), &bOk) ; vVert.push_back( ptP01) ; m_mVert.insert( std::pair( -1, vVert)) ; // se richiesto divido preliminarmente le patches + m_vnParents.clear() ; if ( bSplitPatches && ( nSpanU > 1 || nSpanV > 1)) { int nId = -1 ; for ( int i = 1 ; i < nSpanU ; ++i) { - m_mTree[nId].SetSplitDirVert( true) ; - Split( nId, i * SBZ_TREG_COEFF) ; - ++ nId ; - ++ nId ; + if ( i * SBZ_TREG_COEFF > ptMin.x && i * SBZ_TREG_COEFF < ptTop.x){ + m_mTree[nId].SetSplitDirVert( true) ; + Split( nId, i * SBZ_TREG_COEFF) ; + ++ nId ; + ++ nId ; + } } INTVECTOR vLeaves ; GetHeightLeaves( -1, vLeaves) ; for ( int nId : vLeaves) { for ( int j = nSpanV - 1 ; j > 0 ; --j) { - m_mTree[nId].SetSplitDirVert( false) ; - Split( nId, j * SBZ_TREG_COEFF) ; - nId = m_mTree[nId].m_nChild2 ; + if ( j * SBZ_TREG_COEFF > ptMin.y && j * SBZ_TREG_COEFF < ptTop.y){ + m_mTree[nId].SetSplitDirVert( false) ; + Split( nId, j * SBZ_TREG_COEFF) ; + nId = m_mTree[nId].m_nChild2 ; + } } } vLeaves.clear() ; GetHeightLeaves( -1, vLeaves) ; m_vnParents = vLeaves ; } - // se non ho già splittato le patches, controllo se la superficie è chiusa. In tal caso la splitto sul parametro su cui è chiusa - else { - // verifico se la superficie è chiusa ed eventualmente 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 ; - m_mTree[-1].SetSplitDirVert( false) ; + // 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 + 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 ; + m_mTree[-1].SetSplitDirVert( false) ; + Split( -1) ; + // qui devo fare il controllo capped + // 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 bCapped0 = true, bCapped1 = true ; + Point3d ptV0, ptV1 ; + // controllo se tutti i punti sull'isoparametrica sono uguali + for ( int i = 1 ; i < nDegV * nSpanV + 1 ; ++ i) { + ptV0 = m_pSrfBz->GetControlPoint( i * ( nDegU * nSpanU + 1), &bOk) ; + bCapped0 = bCapped0 && AreSamePointApprox( ptP00, ptV0) ; + ptV1 = m_pSrfBz->GetControlPoint( ( i + 1) * ( nDegU * nSpanU + 1) - 1, &bOk) ; + bCapped1 = bCapped1 && AreSamePointApprox( ptP10, ptV1) ; + } + if ( bCapped0 && bCapped1) { + m_mTree[0].SetSplitDirVert( true) ; + Split( 0) ; + m_mTree[1].SetSplitDirVert( true) ; + Split( 1) ; + } + } + if ( AreSamePointApprox( ptP00, ptP10)) { + if( (int) m_mTree.size() == 1) { + m_mTree[-1].m_nLeft = -1 ; + m_mTree[-1].m_nRight = -1 ; + m_mTree[-1].SetSplitDirVert( true) ; Split( -1) ; - // qui devo fare il controllo capped - // devo controllare se i punti ai parametri U=0 e U=1 sono tutti coincidenti - // in caso devo fare uno split nell'altra direzione + // 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 bCapped0 = true, bCapped1 = true ; - Point3d ptV0, ptV1 ; + Point3d ptU0, ptU1 ; // controllo se tutti i punti sull'isoparametrica sono uguali - for ( int i = 1 ; i < nDegV * nSpanV + 1 ; ++ i) { - ptV0 = m_pSrfBz->GetControlPoint( i * ( nDegU * nSpanU + 1), &bOk) ; - bCapped0 = bCapped0 && AreSamePointApprox( ptP00, ptV0) ; - ptV1 = m_pSrfBz->GetControlPoint( ( i + 1) * ( nDegU * nSpanU + 1) - 1, &bOk) ; - bCapped1 = bCapped1 && AreSamePointApprox( ptP10, ptV1) ; + for ( int i = 1 ; i < nDegU * nSpanU + 1 ; ++ i) { + ptU0 = m_pSrfBz->GetControlPoint( i, &bOk) ; + bCapped0 = bCapped0 && AreSamePointApprox( ptP00, ptU0) ; + ptU1 = m_pSrfBz->GetControlPoint( i + ( nDegU * nSpanU + 1) * ( nDegV * nSpanV), &bOk) ; + bCapped1 = bCapped1 && AreSamePointApprox( ptP01, ptU1) ; } if ( bCapped0 && bCapped1) { - m_mTree[0].SetSplitDirVert( true) ; + m_mTree[0].SetSplitDirVert( false) ; Split( 0) ; - m_mTree[1].SetSplitDirVert( true) ; + m_mTree[1].SetSplitDirVert( false) ; Split( 1) ; } } - if ( AreSamePointApprox( ptP00, ptP10)) { - if( (int) m_mTree.size() == 1) { - 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 - // in caso devo fare uno split nell'altra direzione - bool bOk = false ; - bool bCapped0 = true, bCapped1 = true ; - Point3d ptU0, ptU1 ; - // controllo se tutti i punti sull'isoparametrica sono uguali - for ( int i = 1 ; i < nDegU * nSpanU + 1 ; ++ i) { - ptU0 = m_pSrfBz->GetControlPoint( i, &bOk) ; - bCapped0 = bCapped0 && AreSamePointApprox( ptP00, ptU0) ; - ptU1 = m_pSrfBz->GetControlPoint( i + ( nDegU * nSpanU + 1) * ( nDegV * nSpanV), &bOk) ; - bCapped1 = bCapped1 && AreSamePointApprox( ptP01, ptU1) ; - } - if ( bCapped0 && bCapped1) { - m_mTree[0].SetSplitDirVert( false) ; - Split( 0) ; - m_mTree[1].SetSplitDirVert( false) ; - Split( 1) ; - } - } - else if ( (int) m_mTree.size() > 1 && (int) m_mTree.size() < 4) { - 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) ; - } + else if ( (int) m_mTree.size() > 1 && (int) m_mTree.size() < 4) { + 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) ; } } } - // calcolo e salvo la distanza reale tra i vertici della cella root - double dLen0 = Dist( ptP00, ptP10) ; - double dLen1 = Dist( ptP10, ptP11) ; - double dLen2 = Dist( ptP01, ptP11) ; - double dLen3 = Dist( ptP00, ptP01) ; + // 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 pCrvU0( m_pSrfBz->GetCurveOnV( 0)) ; + PtrOwner pCrvU1( m_pSrfBz->GetCurveOnV( 1)) ; + double dLen0 ; pCrvV0->GetApproxLength( dLen0) ; + double dLen1 ; pCrvU1->GetApproxLength( dLen1) ; + double dLen2 ; pCrvV1->GetApproxLength( dLen2) ; + double dLen3 ; pCrvU0->GetApproxLength( dLen3) ; + m_vDim.clear() ; m_vDim.push_back( ( dLen0 != 0 ? dLen0 : 1)) ; m_vDim.push_back( ( dLen1 != 0 ? dLen1 : 1)) ; m_vDim.push_back( ( dLen2 != 0 ? dLen2 : 1)) ; m_vDim.push_back( ( dLen3 != 0 ? dLen3 : 1)) ; } +//---------------------------------------------------------------------------- +bool +AddOrMergeBBox ( const BBox3d& bBox3dA , std::vector& vBBox, const bool& bAdd = true, const int& nInd = 0) { + Point3d ptMin = bBox3dA.GetMin() ; + Point3d ptMax = bBox3dA.GetMax() ; + if ( (int)vBBox.size() == 0) { + vBBox.push_back( bBox3dA) ; + return true ; + } + bool bAdded = false ; + for ( int b = 0 ; b < (int)vBBox.size() ; ++b) { + BBox3d bBox3dB = vBBox[b] ; + BBox3d b3Int ; + // se sono celle diverse e ho un'intersezione faccio il merge + if ( ! ( AreSamePointExact( ptMin, bBox3dB.GetMin()) && AreSamePointExact( ptMax, bBox3dB.GetMax())) && + bBox3dA.FindIntersectionXY( bBox3dB, b3Int)) { + vBBox[b].Add( bBox3dA) ; + if ( ! bAdd ) { + vBBox.erase( vBBox.begin() + nInd) ; + -- b ; + } + // se ho fatto un merge devo controllare se ora la nuova bbox ha delle intersezioni + AddOrMergeBBox( vBBox[b], vBBox, false, b) ; + bAdded = true ; + break ; + } + } + if ( ! bAdded && bAdd) + vBBox.push_back( bBox3dA) ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +Tree::GetIndependentTrees( std::vector>& vTrees) +{ + if ( ! m_bTrimmed ) { + vTrees.push_back( std::tuple( ORIG, ORIG)); + } + else { + // se ho dei loop di trim trovo le loro BBox3d per costruire l'albero solo all'interno di queste BBox + bool bIsRoot = false ; + std::vector vBBox ; + for ( int a = 0 ; a < (int)m_vPlApprox.size(); ++a ) { + PolyLine plLoop = std::get<0>( m_vPlApprox[a]) ; + // calcolo la BBox3d + BBox3d bBox3dA ; + Point3d pt ; + plLoop.GetFirstPoint( pt) ; + bBox3dA.Add( pt) ; + while ( plLoop.GetNextPoint( pt)) + bBox3dA.Add( pt) ; + // controllo se ho intersezioni con altre bbox + // se ho intersezioni unisco le bbox, altrimenti le lascio indipendenti + AddOrMergeBBox( bBox3dA, vBBox) ; + } + // controllo se dopo aver unito le bbox ho ottenuto Root + Point3d ptTR( m_nSpanU * SBZ_TREG_COEFF, m_nSpanV * SBZ_TREG_COEFF) ; + for (int c = 0 ; c < (int)vBBox.size(); ++ c) { + BBox3d bBox3d = vBBox[c] ; + if ( AreSamePointEpsilon( bBox3d.GetMin(), ORIG, 10) && AreSamePointEpsilon( bBox3d.GetMax(), ptTR, 10)){ + bIsRoot = true ; + break ; + } + } + // restituisco le celle parent di partenza a partire dalle bbox che ho ottenuto + if ( ! bIsRoot ) { + for (int i = 0 ; i < (int)vBBox.size() ; ++ i) { + Point3d ptMin = vBBox[i].GetMin() ; + Point3d ptMax = vBBox[i].GetMax() ; + vTrees.push_back( std::tuple( ptMin, ptMax)) ; + } + } + else + vTrees.push_back( std::tuple( ORIG, ORIG)); + } + return true ; +} + //---------------------------------------------------------------------------- void Tree::Split( const int& nId, const double& dSplitValue) @@ -283,7 +395,7 @@ Tree::Split( const int& nId, const double& dSplitValue) // controllo che lo split non venga fatto sul lato della cella if ( ( m_mTree[nId].IsSplitVert() && dSplitValue > m_mTree[nId].GetBottomLeft().x + EPS_SMALL && dSplitValue < m_mTree[nId].GetTopRight().x - EPS_SMALL) || ( ! m_mTree[nId].IsSplitVert() && dSplitValue > m_mTree[nId].GetBottomLeft().y + EPS_SMALL && dSplitValue < m_mTree[nId].GetTopRight().y - EPS_SMALL)) { - // per lo split a parametro libero dovrò impedire che si facciano split troppo vicini al bordo!!!!!!!!!!!!!!!!!!! + // quando si implementerà lo split a parametro libero bisognerà impedire che si facciano split troppo vicini al bordo della cella!!!!!!!!!!!!!!!!!!! m_mTree[nId].m_dSplit = dSplitValue ; Cell cChild1, cChild2 ; cChild1.m_nDepth = m_mTree[nId].m_nDepth + 1 ; @@ -1219,7 +1331,7 @@ Tree::GetPolygons( std::vector& vPolygons) { return false ; POLYLINEVECTOR vPolygonsBasic ; GetPolygonsBasic( vPolygonsBasic) ; - // scorro sui poligoni delle celle non trimmate + // scorro sulle celle e costruisco i poligoni int nCells = (int)vPolygonsBasic.size() ; for ( int i = 0 ; i < nCells ; ++i) { @@ -1418,12 +1530,11 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& clTrim) const nCells.push_back( nId) ; + // se sono in un vertice o su un lato devo controllare di aver trovato la cella giusta Point3d ptBr( m_mTree.at( nId).GetTopRight().x , m_mTree.at( nId).GetBottomLeft().y) ; Point3d ptTl( m_mTree.at( nId).GetBottomLeft().x , m_mTree.at( nId).GetTopRight().y) ; - if ( AreSamePointApprox( ptToAssign, ptTl) || - AreSamePointApprox( ptToAssign, m_mTree.at( nId).GetBottomLeft()) || - AreSamePointApprox( ptToAssign, ptBr) || - AreSamePointApprox( ptToAssign, m_mTree.at( nId).GetTopRight())) + if ( abs( ptToAssign.x - ptTl.x) < EPS_SMALL || abs( ptToAssign.x - ptBr.x) < EPS_SMALL || + abs( ptToAssign.y - ptTl.y) < EPS_SMALL || abs( ptToAssign.y - ptBr.y) < EPS_SMALL) { Point3d ptToAssignPlus ; double dParam ; @@ -1432,11 +1543,11 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& clTrim) const clTrim.GetPointTang( dParam + EPS_SMALL, ICurve::FROM_MINUS, ptToAssignPlus, vDir) ; if ( abs( vDir.x) > 1 - EPS_SMALL || abs( vDir.y) > 1 - EPS_SMALL) { vDir.Rotate( Z_AX, -90) ; - ptToAssignPlus = ptToAssignPlus + vDir * EPS_SMALL ; + ptToAssignPlus = ptToAssignPlus + vDir * 2 * EPS_SMALL ; } nCells = FindCell( ptToAssignPlus, clTrim) ; if ( nCells.empty()) { - ptToAssignPlus = ptToAssignPlus - 2 * vDir * EPS_SMALL ; + ptToAssignPlus = ptToAssignPlus - 4 * vDir * EPS_SMALL ; nCells = FindCell( ptToAssignPlus, clTrim) ; } } @@ -1473,16 +1584,16 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& cl, INTVECTOR vCells bool Tree::TraceLoopLabelCell( void) { - double dLinTol = - EPS_SMALL ; // questo è riferito allo spazio parametrico, quando è già stato riporatato al range 0..1 !!!!!! - // il valore è negativo perché voglio considerare contenuto anche un punto che sta su un lato + // il valore è negativo perché voglio considerare contenuto anche un punto che sta su un lato + double dLinTol = - EPS_SMALL ; POLYLINEVECTOR vplPolygons ; GetPolygonsBasic( vplPolygons) ; // percorro i loop trovando le interezioni con le celle e riempiendo i vettori m_vInters delle varie celle for ( int i = 0 ; i < (int) m_vPlApprox.size() ; ++ i) { PolyLine plLoop = std::get<0>(m_vPlApprox[i]) ; - // calcolo se il loop è CCW o CW + // controllo se il loop è CCW o CW bool bCCW = std::get<1>(m_vPlApprox[i]) ; - // trovo in quale cella è il ptStart + // trovo in quale cella è il ptStart Point3d ptStart ; plLoop.GetFirstPoint( ptStart) ; PNTULIST lPt = plLoop.GetUPointList() ; @@ -1493,9 +1604,14 @@ Tree::TraceLoopLabelCell( void) clFirst.Set( ptFirst->first, ptSecond->first) ; // individuo la cella da cui parte il loop INTVECTOR nCells = FindCell( ptStart, clFirst) ; - int nId = nCells.back() ; + int nId ; + if ( ! nCells.empty()) + nId = nCells.back() ; + else + // il loop è fuori dalla cella root che sto analizzando + continue ; int nFirstCell = nId ; - // trovo quali punti della polyline sono nella cella e l'intersezione + // trovo quali punti della polyline sono nella cella e l'intersezione PNTVECTOR vptInters ; vptInters.push_back( ptStart) ; // qui mi devo salvare quanti elementi ho già nel vettore m_vInters della cella @@ -1512,18 +1628,15 @@ Tree::TraceLoopLabelCell( void) INTVECTOR :: iterator iter = find( m_vnLeaves.begin(), m_vnLeaves.end(), nId) ; int nIdPolygon = std::distance( m_vnLeaves.begin(), iter) ; bool bEraseNextPoint = false ; - //// per debug - //int c = 0 ; - Cell cUnderWork ; while ( plLoop.GetNextPoint( ptCurr)) { - //++ c ; - // sto uscendo dalla cella, quindi cerco l'intersezione Point3d ptTStart, ptTEnd ; plLoop.GetPrevPoint( ptTStart) ; plLoop.GetNextPoint( ptTEnd) ; CurveLine clTrim ; clTrim.Set( ptTStart, ptTEnd) ; - while( ! IsPointInsidePolyLine( ptCurr, vplPolygons[nIdPolygon], dLinTol)) { /// qui devo mettere una tolleranza negativa per poter tener conto anche dei punti che sono SULLA curva + // qui devo mettere una tolleranza negativa per poter tener conto anche dei punti che sono SULLA curva + while( ! IsPointInsidePolyLine( ptCurr, vplPolygons[nIdPolygon], dLinTol)) { + // sto uscendo dalla cella, quindi cerco l'intersezione if ( bEraseNextPoint) { vptInters.pop_back() ; bEraseNextPoint = false ; @@ -1552,8 +1665,6 @@ Tree::TraceLoopLabelCell( void) m_mTree[nId].m_vInters.back().bCCW = bCCW ; // salvo il chunk del loop m_mTree[nId].m_vInters.back().nChunk = m_mChunk[i] ; - // per debug - cUnderWork = m_mTree[nId] ; } // aggiungo la fine del segmento nel vettore delle intersezioni vptInters.push_back( ptCurr) ; @@ -1620,7 +1731,7 @@ Tree::TraceLoopLabelCell( void) GetRightNeigh( nCell, vNeigh) ; // proseguo finché non sono sull'elemento più alto di vFirst e tutti i suoi vicini sono processati/categorizzati bool bAllDone = false ; - while ( nCell != nLastLeft && ! bAllDone) { + while ( ! bAllDone) { // categorizzo la cella m_mTree[nCell].m_nFlag2 = 1 ; CategorizeCell( nCell) ; @@ -1640,7 +1751,8 @@ Tree::TraceLoopLabelCell( void) if ( ! bProceeded) { m_mTree[nCell].SetProcessed() ; } - else { //categorizzo la cella + else { + //categorizzo la cella m_mTree[nCell].m_nFlag2 = 1 ; CategorizeCell( nCell) ; } @@ -2015,7 +2127,7 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool m_mTree[nId].m_vInters.back().nIn = 7 ; } else { - nId = vNeigh[0] ; + nId = vNeigh1[0] ; m_mTree[nId].m_vInters.emplace_back() ; m_mTree[nId].m_vInters.back().nIn = 4 ; } @@ -2064,8 +2176,7 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool m_mTree[nId].m_vInters.back().nIn = 4 ; } else { - GetRightNeigh( nId, vNeigh) ; - nId = vNeigh[0] ; + nId = vNeigh1[0] ; m_mTree[nId].m_vInters.emplace_back() ; m_mTree[nId].m_vInters.back().nIn = 5 ; } @@ -2114,7 +2225,7 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool m_mTree[nId].m_vInters.back().nIn = 5 ; } else { - nId = vNeigh.back() ; + nId = vNeigh1.back() ; m_mTree[nId].m_vInters.emplace_back() ; m_mTree[nId].m_vInters.back().nIn = 6 ; } @@ -2369,7 +2480,7 @@ Tree::CreateCellPolygons( const int& nLeafId, std::vector& vPoly c = 0 ; plTrimmedPoly.Clear() ; nEdgeIn = -1 ; - // devo verificare se tra i loop che sono finiti in vToCheck in realtà qualcuno l'ho usato per fare un poligono///////////////////////////////////// + // devo verificare se tra i loop che sono finiti in vToCheck in realtà qualcuno l'ho usato per fare un poligono for ( int k = 0 ; k < (int)vToCheck.size() ; ++ k) { for ( int i = 0 ; i < (int)vAddedLoops.size() ; ++ i) { if ( vToCheck[k] == vAddedLoops[i]) { @@ -2395,6 +2506,7 @@ Tree::CreateIslandAndHoles( const int& nLeafId, std::vector& vPo PolyLine plTrimmedPoly ; // loop interni in una cella intersecata + int nChunkBiggestCW = -1 ; if ( m_mTree[nId].m_nFlag == 3 || m_mTree[nId].m_nFlag == 2) { PolyLine plInLoop ; Inters inA ; @@ -2407,6 +2519,8 @@ Tree::CreateIslandAndHoles( const int& nLeafId, std::vector& vPo if ( inA.nIn == -1) { // per ogni loop CW verifico che ci sia un loop CCW dello stesso chunk ( che quindi lo contiene) if ( ! inA.bCCW) { + if ( nChunkBiggestCW == -1) + nChunkBiggestCW = inA.nChunk ; bContained = false ; Inters inB = m_mTree[nId].m_vInters[0] ; for( int c = 0 ; c < nInters ; ++ c){ @@ -2443,7 +2557,8 @@ Tree::CreateIslandAndHoles( const int& nLeafId, std::vector& vPo vCellPolygons.push_back( plInLoop) ; vPolygons.push_back( vCellPolygons) ; ++ nPoly ; - vnParentChunk.push_back( inA.nChunk) ; + // imposto il chunk del loop CW più grande ( il primo che ho incontrato) + vnParentChunk.push_back( nChunkBiggestCW) ; vCellPolygons.clear() ; plInLoop.Clear() ; } @@ -2577,20 +2692,37 @@ Tree::CheckIfBefore( const int& nEdge1, const Point3d& ptP1, const int& nEdge2, //---------------------------------------------------------------------------- bool -Tree::CheckIfBefore( const int& nEdge, const Point3d& ptP1, const Point3d& ptP2) const +Tree::CheckIfBefore( const int& nEdge, const Point3d& ptP1, const Point3d& ptP2, const int& nEdge2) const { + // i punti devono essere sullo stesso lato nEdge + // nEdge2 è di backup, in caso nEdge sia un vertice, per capire di quale lato si tratta + int nEdgeRef ; + if ( nEdge != nEdge2 && nEdge2 != -1) { + if ( std::min(nEdge, nEdge2) < 4) + nEdgeRef = std::min(nEdge, nEdge2) ; + else if ( AreSameEdge( nEdge, 0) && AreSameEdge( nEdge2, 0)) + nEdgeRef = 0 ; + else if ( AreSameEdge( nEdge, 1) && AreSameEdge( nEdge2, 1)) + nEdgeRef = 1 ; + else if ( AreSameEdge( nEdge, 2) && AreSameEdge( nEdge2, 2)) + nEdgeRef = 2 ; + else if ( AreSameEdge( nEdge, 3) && AreSameEdge( nEdge2, 3)) + nEdgeRef = 3 ; + } + else + nEdgeRef = nEdge ; // sul lato nEdge controllo se ptP1 viene prima di ptP2. // i lati vengono percorsi in senso antiorario - if ( AreSameEdge( nEdge, 0)) { + if ( AreSameEdge( nEdgeRef, 0)) { return ptP1.x > ptP2.x ; } - else if ( AreSameEdge( nEdge, 1)) { + else if ( AreSameEdge( nEdgeRef, 1)) { return ptP1.y > ptP2.y ; } - else if ( AreSameEdge( nEdge, 2)) { + else if ( AreSameEdge( nEdgeRef, 2)) { return ptP1.x < ptP2.x ; } - else if ( AreSameEdge( nEdge, 3)) { + else if ( AreSameEdge( nEdgeRef, 3)) { return ptP1.y < ptP2.y ; } return false ; @@ -3049,13 +3181,13 @@ Tree::CategorizeCell( const int& nId) bool bIntersIn ; for ( int k = 0 ; k < (int) m_mTree[vNeigh[0]].m_vInters.size() ; ++ k) { if ( AreSameEdge( m_mTree[vNeigh[0]].m_vInters[k].nIn, 3)) { - if ( CheckIfBefore( nEdge, m_mTree[vNeigh[0]].m_vInters[k].vpt[0], ptInters)) { + if ( CheckIfBefore( nEdge, m_mTree[vNeigh[0]].m_vInters[k].vpt[0], ptInters, 3)) { ptInters = m_mTree[vNeigh[0]].m_vInters[k].vpt[0] ; bIntersIn = true ; } } if ( AreSameEdge( m_mTree[vNeigh[0]].m_vInters[k].nOut, 3)) { - if ( CheckIfBefore( nEdge, m_mTree[vNeigh[0]].m_vInters[k].vpt.back(), ptInters)) { + if ( CheckIfBefore( nEdge, m_mTree[vNeigh[0]].m_vInters[k].vpt.back(), ptInters, 3)) { ptInters = m_mTree[vNeigh[0]].m_vInters[k].vpt.back() ; bIntersIn = false ; } @@ -3103,6 +3235,7 @@ Tree::CheckIfBetween( const Inters& inA, const Inters& inB) const } else if ( nEdge == 7) nEdge = 0 ; + // creo la sequenza di Edges da scorrere per trovare i possibili validNextStart while ( ! AreSameEdge( nEdge, inA.nIn) || (int) vEdges.size() == 0) { vEdges.push_back( nEdge) ; if ( nEdge == 3) @@ -3115,16 +3248,16 @@ Tree::CheckIfBetween( const Inters& inA, const Inters& inB) const bool bFound = false ; for ( int i : vEdges) { if ( AreSameEdge( inB.nIn, i)) { - if ( AreSameEdge( inB.nIn, inA.nIn) && AreSameEdge( inA.nIn, inA.nOut)) { + if ( AreSameEdge( inB.nIn, inA.nIn) && AreSameEdge( inA.nIn, inA.nOut) && AreSameEdge( inB.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())) { - if ( CheckIfBefore( nEdge, inA.vpt.back(), inB.vpt[0]) || CheckIfBefore( nEdge, inB.vpt[0], inA.vpt[0])) + if ( CheckIfBefore( nEdge, inA.vpt[0], inA.vpt.back(), inA.nOut)) { + if ( CheckIfBefore( nEdge, inA.vpt.back(), inB.vpt[0], inA.nOut ) || CheckIfBefore( nEdge, inB.vpt[0], inA.vpt[0], inA.nOut)) bFound = true ; } // se l'inizio di A è dopo la fine, allora devo controllare che B sia compreso tra In e Out ( interno) else { - if ( CheckIfBefore( nEdge, inA.vpt.back(), inB.vpt[0]) && CheckIfBefore( nEdge, inB.vpt[0], inA.vpt[0])) + if ( CheckIfBefore( nEdge, inA.vpt.back(), inB.vpt[0], inA.nOut) && CheckIfBefore( nEdge, inB.vpt[0], inA.vpt[0], inA.nOut)) bFound = true ; } } @@ -3138,17 +3271,18 @@ Tree::CheckIfBetween( const Inters& inA, const Inters& inB) const } 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.vpt[0])) + if ( CheckIfBefore( inA.nIn, inB.vpt[0], inA.vpt[0], inB.nIn)) bFound = true ; } else // devo controllare che inB sia prima di OutB - if ( AreSameEdge( 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(), inB.nIn)) { bFound = true ; } else if ( ! AreSameEdge( inB.nOut,inB.nIn)) bFound = true ; } + // se incontro prima l'uscita dell'ingresso, sicuramente InB NON è un validNextStart if ( AreSameEdge( inB.nOut, i) && ! bFound && CheckIfBefore( i, inA.vpt[0], inB.vpt.back()) && CheckIfBefore( i, inA.vpt.back(), inB.vpt.back())) break ; } diff --git a/Tree.h b/Tree.h index 57bf9cd..f2d6b74 100644 --- a/Tree.h +++ b/Tree.h @@ -29,7 +29,14 @@ struct Inters { int nChunk ; // riordino le intersezioni per lato in senso antiorario dal top // se ho più intersezioni che entrano in un lato le riordino considerando che percorro i lati in senso antiorario a partire da ptTR - bool operator < ( Inters& b) { + bool operator < ( Inters& b) { + // trovo in che ordine stanno i due strat, tenendo conto anche della possibilità che siano vertici + INTVECTOR vEdges = { 7, 0, 4, 1, 5, 2, 6, 3} ; + INTVECTOR::iterator iter1 = find( vEdges.begin(), vEdges.end(), nIn) ; + int nPos1 = std::distance( vEdges.begin(), iter1) ; + INTVECTOR::iterator iter2 = find( vEdges.begin(), vEdges.end(), b.nIn) ; + int nPos2 = std::distance( vEdges.begin(), iter2) ; + // se sono loop interni li ordino in modo decrescente rispetto all'area bool bEqIn = ( nIn == b.nIn) ; double dAreaA = 0 , dAreaB = 0 ; if ( bEqIn && nIn == -1) { @@ -44,12 +51,16 @@ struct Inters { pl.Close() ; pl.GetAreaXY( dAreaB) ; } - return nIn < b.nIn || - ( bEqIn && nIn == -1 && abs(dAreaA) > abs(dAreaB)) || - ( bEqIn && nIn == 0 && vpt[0].x > b.vpt[0].x) || - ( bEqIn && nIn == 1 && vpt[0].y > b.vpt[0].y) || - ( bEqIn && nIn == 2 && vpt[0].x < b.vpt[0].x) || - ( bEqIn && nIn == 3 && vpt[0].y < b.vpt[0].y) + // se nIn è un vertice sistemo il valore + int nEdgeIn = nIn ; + if ( nIn > 3) + nEdgeIn = nIn - 4 ; + return nPos1 < nPos2 || + ( bEqIn && nEdgeIn == -1 && abs(dAreaA) > abs(dAreaB)) || + ( bEqIn && nEdgeIn == 0 && vpt[0].x > b.vpt[0].x) || + ( bEqIn && nEdgeIn == 1 && vpt[0].y > b.vpt[0].y) || + ( bEqIn && nEdgeIn == 2 && vpt[0].x < b.vpt[0].x) || + ( bEqIn && nEdgeIn == 3 && vpt[0].y < b.vpt[0].y) ; } bool operator == ( Inters& b) { return AreSamePointExact( vpt[0], b.vpt[0]) ; @@ -115,11 +126,12 @@ class Tree public : ~Tree( void) ; Tree( void) ; - Tree ( const SurfBezier* pSrfBz, const bool bSplitPatches = true) ; - void SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches = true) ; - bool BuildTree( const double& dLinTol = LIN_TOL_STD, const double& dSideMin = 5, const double& dSideMax = INFINITO) ; // dSideMax è il massimo per la dimensione maggiore di un triangolo della trimesh + 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 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 = 5, const double& dSideMax = INFINITO) ; + bool BuildTree_test( const double& dLinTol = LIN_TOL_STD, const double& dSideMin = 1, const double& dSideMax = INFINITO) ; bool GetPolygons( std::vector& vPolygons) ; bool GetPolygonsBasic( POLYLINEVECTOR& vPolygons) ; // restituisce il poligono corrispondente ad ogni cella foglia dell'albero // ad ogni poligono sono stati aggiunti tutti i vertici dei vicini posizionati sui suoi lati @@ -146,8 +158,8 @@ private : bool CreateIslandAndHoles ( const int& nLeafId, std::vector& vPolygons, int& nPoly, INTVECTOR& vnParentChunk) ; bool CheckIfBefore( const PolyLine& pl, const int& nEdge) const ; bool CheckIfBefore( const Inters& inA) const ; - bool CheckIfBefore( const int& nEdge1, const Point3d& ptP1, const int& nEdge2, const Point3d& ptP2) const ; - bool CheckIfBefore( const int& nEdge, const Point3d& ptP1, const Point3d& ptP2) const ; + bool CheckIfBefore( const int& nEdge1, const Point3d& ptP1, const int& nEdge2, const Point3d& ptP2) const ; // punto 1 su edge 1 e punto 2 su edge 2, rispetto al lato 3 + bool CheckIfBefore( const int& nEdge, const Point3d& ptP1, const Point3d& ptP2, const int& nEdge2 = -1) const ; // entrambi i punti sullo stesso lato, nEdge. nEdge2 serve come backup, in caso nEdge sia un vertice. bool AreSameEdge( const int& nEdge1, const int nEdge2) const ; bool AddVertex( const int& nId, const std::vector& vEdgeVertex, PolyLine& plTrimmedPoly, int& c, const Point3d& ptToAdd) const ; //bool SetRightEdgeIn( int nId, std::vector& vEdgeVertex, PolyLine& plTrimmedPoly) ;