From 6a3fc0fd97b7529d8f88183de78e8fbd20dd0711 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Wed, 3 May 2023 12:09:58 +0200 Subject: [PATCH 01/44] EgtGeomKernel : - implementazione delle classi KdTree e Cell - problemi : bilanciamento albero e uso puntatori --- EgtGeomKernel.vcxproj | 2 + EgtGeomKernel.vcxproj.filters | 6 + KdTree.cpp | 286 ++++++++++++++++++++++++++++++++++ KdTree.h | 73 +++++++++ SurfBezier.cpp | 245 +++++++++++++++++++++++------ SurfBezier.h | 2 +- 6 files changed, 562 insertions(+), 52 deletions(-) create mode 100644 KdTree.cpp create mode 100644 KdTree.h diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index f1ddf40..0e496f4 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -339,6 +339,7 @@ copy $(TargetPath) \EgtProg\Dll64 + @@ -603,6 +604,7 @@ copy $(TargetPath) \EgtProg\Dll64 + diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index f6a5e4c..4503501 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -471,6 +471,9 @@ File di origine\GeoOffset + + File di origine\Base + @@ -1103,6 +1106,9 @@ File di intestazione + + File di intestazione + diff --git a/KdTree.cpp b/KdTree.cpp new file mode 100644 index 0000000..fc945ef --- /dev/null +++ b/KdTree.cpp @@ -0,0 +1,286 @@ +//---------------------------------------------------------------------------- +// EgalTech 2023 +//---------------------------------------------------------------------------- +// File : Kd-tree.cpp Data : 21.04.23 Versione : +// Contenuto : Implementazione della classe kd-tree. +// +// +// +// Modifiche : 21.04.23 DB Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "KdTree.h" +#include "SurfBezier.h" +#include "GeoConst.h" + +using namespace std ; + +//---------------------------------------------------------------------------- +Cell::Cell( void) + : m_ptPbl( ORIG), m_ptPtr( ORIG), m_bProcessed ( false) , m_bSplitVert ( true) , m_dSplit( 0) , m_cTop ( nullptr), m_cBottom( nullptr), + m_cLeft( nullptr), m_cRight ( nullptr), m_cParent( nullptr), m_cChild1( nullptr), m_cChild2( nullptr) +{} + +//---------------------------------------------------------------------------- +Cell::~Cell( void) +{ +} + +//---------------------------------------------------------------------------- +inline bool +Cell::IsSame( std::shared_ptr cOtherCell) +{ + if ( AreSamePointXYApprox( m_ptPbl, cOtherCell->GetBottomLeft()) && + AreSamePointXYApprox( m_ptPtr, cOtherCell->GetTopRight())) { + return true ; + } + else { + return false ; + } +} + +//---------------------------------------------------------------------------- +void +Cell::Split( double dSplitValue) +{ + m_dSplit = dSplitValue ; + //Cell cChild1, cChild2, cParent, cTop, cBottom, cLeft, cRight ; + m_cChild1 = make_shared() ; + //m_cChild2 = &cChild2 ; + //m_cParent = &cParent ; + //m_cTop = &cTop ; + //m_cBottom = &cBottom ; + //m_cLeft = &cLeft ; + //m_cRight = &cRight ; + + m_cChild2 = make_shared() ; + //m_cParent = make_shared() ; + //m_cTop = make_shared() ; + //m_cBottom = make_shared() ; + //m_cLeft = make_shared() ; + //m_cRight = make_shared() ; + if ( ! m_bSplitVert ) + { + // la cella figlio 1 è quella sopra + Point3d ptBL( m_ptPbl.x, m_dSplit) ; + m_cChild1->SetBottomLeft( ptBL) ; + m_cChild1->SetTopRight( m_ptPtr) ; + m_cChild1->m_cTop = m_cTop ; + m_cChild1->m_cBottom = m_cChild2 ; + m_cChild1->m_cLeft = m_cLeft ; + m_cChild1->m_cRight = m_cRight ; + //m_cChild1->m_cParent = make_shared(*this) ; + Point3d ptTR( m_ptPtr.x, m_dSplit) ; + m_cChild2->SetBottomLeft( m_ptPbl) ; + m_cChild2->SetTopRight( ptTR) ; + m_cChild2->m_cTop = m_cChild1 ; + m_cChild2->m_cBottom = m_cBottom ; + m_cChild2->m_cLeft = m_cLeft ; + m_cChild2->m_cRight = m_cRight ; + //m_cChild2->m_cParent = make_shared(*this) ; + } + else { + // la cella figlio 1 è quella di sinistra + Point3d ptTR( m_dSplit, m_ptPtr.y) ; + m_cChild1->SetBottomLeft( m_ptPbl) ; + m_cChild1->SetTopRight( ptTR) ; + m_cChild1->m_cTop = m_cTop ; + m_cChild1->m_cBottom = m_cBottom ; + m_cChild1->m_cLeft = m_cLeft ; + m_cChild1->m_cRight = m_cChild2 ; + //m_cChild1->m_cParent = make_shared(*this) ; + Point3d ptBL( m_dSplit, m_ptPbl.y) ; + m_cChild2->SetBottomLeft( ptBL) ; + m_cChild2->SetTopRight( m_ptPtr) ; + m_cChild2->m_cTop = m_cTop ; + m_cChild2->m_cBottom = m_cBottom ; + m_cChild2->m_cLeft = m_cChild1 ; + m_cChild2->m_cRight = m_cRight ; + //m_cChild2->m_cParent = make_shared(*this) ; + } + //m_bProcessed = true ; +} + +//---------------------------------------------------------------------------- +bool +//Cell::IsLeaf ( void) const +Cell::IsLeaf ( void) +{ + if( m_cChild1 == nullptr && m_cChild2 == nullptr) + return true ; + else + return false ; +} + +//---------------------------------------------------------------------------- +KdTree::KdTree( void) + : m_dLinTol(LIN_TOL_FINE), m_pSrfBz(nullptr), m_cRoot( make_shared()) +{} + +//---------------------------------------------------------------------------- +KdTree::KdTree( const SurfBezier* pSrfBz) + : m_dLinTol( LIN_TOL_FINE), m_pSrfBz ( pSrfBz) +{ + // le coordinate delle celle sono nello spazio parametrico + int nDegU, nDegV, nSpanU, nSpanV ; + bool bIsRat, bTrimmed ; + m_pSrfBz->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bIsRat, bTrimmed) ; + Point3d ptTop( nSpanU, nSpanV) ; + m_cRoot = make_shared() ; + m_cRoot->SetBottomLeft( ORIG) ; + m_cRoot->SetTopRight( ptTop) ; +} + +//---------------------------------------------------------------------------- +KdTree::~KdTree( void) +{ +} + +//---------------------------------------------------------------------------- +void KdTree::SetSurf( const SurfBezier* pSrfBz) +{ + m_pSrfBz = pSrfBz ; + // le coordinate delle celle sono nello spazio parametrico + int nDegU, nDegV, nSpanU, nSpanV ; + bool bIsRat, bTrimmed ; + m_pSrfBz->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bIsRat, bTrimmed) ; + Point3d ptTop( nSpanU, nSpanV) ; + m_cRoot = make_shared() ; + m_cRoot->SetBottomLeft( ORIG) ; + m_cRoot->SetTopRight( ptTop) ; +} + +//---------------------------------------------------------------------------- +bool KdTree::BuildTree( int nStepU, int nStepV) +{ + // trovo dove splittare la cella e creo i puntatori ai figli + + // comincio a suddividere la superficie usando un kd-tree + // approssimo con una bilineare e se l'errore di approssimazione è troppo grande cerco una direzione + // in cui dividere la superficie + + double err ; // errore calcolato + double dist ; // distanza tra punti selezionati + double dU, dV , dUmax, dVmax; + Point3d ptBz, ptBl ; + // cerco lo scostamento massimo tra la sup di Bezier e la sua approssimazione bilineare + + // shared_ptr cToSplit = make_shared(&m_cRoot) ; + shared_ptr cToSplit = m_cRoot ; + + + //while ( cToSplit != nullptr && + // ( cToSplit->IsSame( &m_cRoot) || // per entrare nel ciclo + // cToSplit->IsProcessed() == false || // per processare le child1 + // ( ! cToSplit->IsSame( &m_cRoot) && cToSplit->m_cChild2->IsProcessed() == false))) { // per processare le child2 finché torno alla root + int c = 1 ; + while ( cToSplit != nullptr && cToSplit->IsProcessed() == false) { + err = 0 ; + // calcolo la bilineare per gli estremi della cella + SurfBezier pSrfBl ; + pSrfBl.Init(1, 1, 1, 1, false) ; + m_pSrfBz->GetPointD1D2( cToSplit->GetBottomLeft().x, cToSplit->GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; + pSrfBl.SetControlPoint( 0, ptBz) ; // P00 + m_pSrfBz->GetPointD1D2( cToSplit->GetTopRight().x, cToSplit->GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; + pSrfBl.SetControlPoint( 1, ptBz) ; // P01 + m_pSrfBz->GetPointD1D2( cToSplit->GetBottomLeft().x, cToSplit->GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; + pSrfBl.SetControlPoint( 2, ptBz) ; // P10 + m_pSrfBz->GetPointD1D2( cToSplit->GetTopRight().x, cToSplit->GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; + pSrfBl.SetControlPoint( 3, ptBz) ; // P11 + for ( int i = 1 ; i <= nStepU ; ++ i) { + for ( int j = 1 ; j <= nStepV ; ++ j) { + dU = double ( i) / nStepU * ( cToSplit->GetTopRight().y - cToSplit->GetBottomLeft().y) ; + dV = double ( j) / nStepV * ( cToSplit->GetTopRight().x - cToSplit->GetBottomLeft().x) ; + if ( ! m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) || + ! pSrfBl.GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBl)) + return false ; + dist = Dist( ptBz, ptBl) ; + if ( dist > err) { // ### nelle condizioni dell'if probabilmente devo già controllare che la dimensione della cella non sia troppo piccola + err = dist ; + dUmax = dU ; + dVmax = dV ; + } + } + } + // devo spostare la condizione sulla dimensione minima di una cella///////////////////////////////////////////////////////////////////// + // probabilmente qui ### + if ( err > m_dLinTol && ( dUmax - cToSplit->GetBottomLeft().y) >= 0.01 && ( dVmax - cToSplit->GetBottomLeft().x) >= 0.01) { + // devo trovare i punti sui lati corrispondenti a dUmax e dVmax, unendo queste coppie trovo le due direzioni di possibile split + // punti medi del lato successivo in senso orario rispetto al relativo vertice della patch + Point3d ptPSrf, ptP00, ptP10, ptP11, ptP01; + m_pSrfBz->GetPointD1D2( dUmax, dVmax, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + m_pSrfBz->GetPointD1D2( dUmax, 0, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00) ; + m_pSrfBz->GetPointD1D2( 1, dVmax, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10) ; + m_pSrfBz->GetPointD1D2( dUmax, 1, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11) ; + m_pSrfBz->GetPointD1D2( 0, dVmax, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01) ; + Point3d ptP00P11 = ( 1 - dVmax) * ptP00 + dVmax * ptP11 ; + Point3d ptP10P01 = ( 1 - dUmax) * ptP10 + dUmax * ptP01 ; + // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza + // effettuo lo split e configuro le celle figlie + if ( Dist(ptP00P11, ptPSrf) > Dist(ptP10P01, ptPSrf)) { + cToSplit->SetSplitDirVert( false) ; + cToSplit->Split( dUmax) ; + } + else { + cToSplit->SetSplitDirVert( true) ; + cToSplit->Split( dVmax) ; + } + cToSplit->m_cChild1->SetParent( cToSplit) ; + cToSplit->m_cChild2->SetParent( cToSplit) ; + // procedo con lo split del Child1 + cToSplit = cToSplit->m_cChild1 ; + } + else { + // sono arrivato ad una cella Leaf, quindi salvo il poligono + cToSplit->Processed() ; + Point3d ptPbr( cToSplit->GetTopRight().x, cToSplit->GetBottomLeft().y) ; + Point3d ptPtl( cToSplit->GetBottomLeft().x, cToSplit->GetTopRight().y) ; + m_vPolygons.emplace_back() ; + m_vPolygons.back().AddUPoint(0, cToSplit->GetBottomLeft()) ; + m_vPolygons.back().AddUPoint(0.25, ptPbr) ; + m_vPolygons.back().AddUPoint(0.5, cToSplit->GetTopRight()) ; + m_vPolygons.back().AddUPoint(0.75, ptPtl) ; + m_vPolygons.back().AddUPoint(1, cToSplit->GetBottomLeft()) ; + // risalgo i parent finché non trovo il primo Child2 da processare + cToSplit = cToSplit->m_cParent ; + if ( cToSplit->m_cChild1->IsProcessed() && cToSplit->m_cChild2->IsProcessed()) + cToSplit->Processed() ; + // questa condizione mi manda in un loop perché non processo mai il child2 di root + // a'altro canto devo evitare di fare i passaggi successivi se sono già parent processato + + //if ( cToSplit->IsSame( &m_cRoot)) + // continue ; + + while ( cToSplit->m_cChild2->IsProcessed()) { + if ( cToSplit->m_cParent != nullptr ) + cToSplit = cToSplit->m_cParent ; + if ( cToSplit->m_cChild1->IsProcessed() && cToSplit->m_cChild2->IsProcessed()) + cToSplit->Processed() ; + if ( cToSplit->IsSame( m_cRoot) && cToSplit->m_cChild2->IsProcessed()) + break ; + } + //if ( cToSplit->IsSame( &m_cRoot)) + // continue ; + //else + // cToSplit = cToSplit->m_cChild2 ; + + cToSplit = cToSplit->m_cChild2 ; + } + c ++ ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool KdTree::GetPolygons( POLYLINEVECTOR& vPolygons) +{ + // restituisco i poligoni delle celle del kd-tree nello spazio parametrico + if ( m_vPolygons.empty()) + return false ; + vPolygons = m_vPolygons ; + return true ; +} \ No newline at end of file diff --git a/KdTree.h b/KdTree.h new file mode 100644 index 0000000..c782103 --- /dev/null +++ b/KdTree.h @@ -0,0 +1,73 @@ +//---------------------------------------------------------------------------- +// EgalTech 2023 +//---------------------------------------------------------------------------- +// File : Kd-tree.h Data : 21.04.23 Versione : +// Contenuto : Implementazione della classe Cell di un kd-tree. +// +// +// +// Modifiche : 21.04.23 DB Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once + +//--------------------------- Include ---------------------------------------- +#include "SurfBezier.h" + +//---------------------------------------------------------------------------- +class Cell +{ + public : + ~Cell( void) ; + Cell( void) ; + Cell( Point3d ptBL, Point3d ptTR) : m_ptPbl( ptBL), m_ptPtr(ptTR) {} + inline bool IsSame ( std::shared_ptr cOtherCell) ; + void SetBottomLeft( Point3d ptBL) { m_ptPbl = ptBL ; } + void SetTopRight( Point3d ptTR) { m_ptPtr = ptTR ; } + void SetSplitDirVert( bool bVert) { m_bSplitVert = bVert ; } + void SetSplitValue ( double dSplitValue) { m_dSplit = dSplitValue ; } + void SetParent (std::shared_ptr pCParent) { m_cParent = pCParent ; } + void Split( double dSpiltValue) ; + Point3d GetBottomLeft( void) { return m_ptPbl ; } + Point3d GetTopRight( void) { return m_ptPtr ; } + //bool IsLeaf( void) const ; + bool IsLeaf( void) ; + bool IsProcessed ( void) const { return m_bProcessed ; } + void Processed ( void) { m_bProcessed = true ; } + + public : + std::shared_ptr m_cTop ; // cella adiacente al lato top + std::shared_ptr m_cBottom ; // cella adiacente al lato bottom + std::shared_ptr m_cLeft ; // cella adiacente al lato left + std::shared_ptr m_cRight ; // cella adiacente al lato right + std::shared_ptr m_cParent ; // cella genitore + std::shared_ptr m_cChild1 ; // prima cella figlio + std::shared_ptr m_cChild2 ; // seconda cella figlio + + private : + Point3d m_ptPbl ; // punto bottom left + Point3d m_ptPtr ; // punto top right + bool m_bProcessed ; // flag che indica se la cella è stata processata + bool m_bSplitVert ; // flag che indica in quale direzione è stata divisa la cella + double m_dSplit ; // lunghezza normalizzata a cui è stata splittata la cella +} ; + +//---------------------------------------------------------------------------- +class KdTree +{ +public : + ~KdTree( void) ; + KdTree( void) ; + KdTree ( const SurfBezier* pSrfBz) ; + void SetSurf( const SurfBezier* pSrfBz) ; + bool BuildTree( int nStepU, int nStepV) ; + bool GetPolygons( POLYLINEVECTOR& vPolygons) ; + +private : + double m_dLinTol ; // errore dell'approssimazione + std::shared_ptr m_cRoot ; // cella base + const SurfBezier* m_pSrfBz ; // root + POLYLINEVECTOR m_vPolygons ; // vettore dei poligoni del kd-tree +} ; \ No newline at end of file diff --git a/SurfBezier.cpp b/SurfBezier.cpp index ef96e0d..1ec67b5 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -20,6 +20,9 @@ #include "Bernstein.h" #include "CurveBezier.h" #include "CurveComposite.h" +#include "KdTree.h" +#include "Triangulate.h" +#include "SurfTriMesh.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EGkStmFromTriangleSoup.h" #include "/EgtDev/Include/EGkStringUtils3d.h" @@ -33,12 +36,13 @@ using namespace std ; GEOOBJ_REGISTER( SRF_BEZIER, NGE_S_BEZ, SurfBezier) ; //---------------------------------------------------------------------------- -SurfBezier::SurfBezier(void) +SurfBezier::SurfBezier( void) : m_pSTM( nullptr), m_nStatus( TO_VERIFY), m_nDegU(), m_nDegV(), m_nSpanU(), m_nSpanV(), m_bRat( false), m_bTrimmed( false), m_pTrimReg( nullptr) { m_nTempProp[0] = 0 ; m_nTempProp[1] = 0 ; + } //---------------------------------------------------------------------------- @@ -1372,6 +1376,82 @@ SurfBezier::GetCurveOnVApproxLen( double dU) const return dLen ; } +////---------------------------------------------------------------------------- +//const SurfTriMesh* +//SurfBezier::GetAuxSurf( void) const +//{ +// // la superficie deve essere validata +// if ( m_nStatus != OK) { +// ResetAuxSurf() ; +// return nullptr ; +// } +// // se già calcolata, la restituisco +// if ( m_pSTM != nullptr) +// return m_pSTM ; +// // costruttore della superficie +// StmFromTriangleSoup stmSoup ; +// if ( ! stmSoup.Start()) +// return nullptr ; +// // definisco il numero degli step in U e in V +// double dMaxLenU = 0 ; +// for ( int j = 0 ; j <= m_nDegV * m_nSpanV ; ++ j) +// dMaxLenU = max( dMaxLenU, GetCurveOnUApproxLen( double( j) / m_nDegV)) ; +// int nStepU = GetSteps( m_nDegU, m_nSpanU, dMaxLenU, 2) ; +// double dMaxLenV = 0 ; +// for ( int i = 0 ; i <= m_nDegU * m_nSpanU ; ++ i) +// dMaxLenV = max( dMaxLenV, GetCurveOnVApproxLen( double( i) / m_nDegU)) ; +// int nStepV = GetSteps( m_nDegV, m_nSpanV, dMaxLenV, 2) ; +// // prima curva isoparametrica (potrebbe essere un solo punto) +// PolyLine PL1 ; +// GetCurveOnU( 0, nStepU, PL1) ; +// bool bSingle1 = ( PL1.GetPointNbr() == 1) ; +// // ciclo sulle isoparametriche +// for ( int i = 1 ; i <= nStepV ; ++ i) { +// // seconda curva isoparametrica (con tanti punti quanti la prima, oppure uno solo) +// double dV = double( i) * m_nSpanV / nStepV ; +// PolyLine PL2 ; +// GetCurveOnU( dV, nStepU, PL2) ; +// bool bSingle2 = ( PL2.GetPointNbr() == 1) ; +// // inserisco i triangoli della striscia nel costruttore della TriMesh +// Point3d ptP1c, ptP2c ; +// Point3d ptP1n, ptP2n ; +// bool bNext = PL1.GetFirstPoint( ptP1c) && PL2.GetFirstPoint( ptP2c) ; +// if ( bNext) { +// if ( bSingle1 && bSingle2) +// bNext = false ; +// if ( bSingle1) +// ptP1n = ptP1c ; +// else +// bNext = bNext && PL1.GetNextPoint( ptP1n) ; +// if ( bSingle2) +// ptP2n = ptP2c ; +// else +// bNext = bNext && PL2.GetNextPoint( ptP2n) ; +// } +// while ( bNext) { +// // eventuale primo triangolo (con base sui correnti e vertice su P2 successivo) +// if ( ! AreSamePointApprox( ptP1c, ptP2c)) +// stmSoup.AddTriangle( ptP2c, ptP1c, ptP2n) ; +// // eventuale secondo triangolo (con vertice su P1 corrente e base sui successivi) +// if ( ! AreSamePointApprox( ptP1n, ptP2n)) +// stmSoup.AddTriangle( ptP1c, ptP1n, ptP2n) ; +// // passo alla successiva coppia +// ptP1c = ptP1n ; +// ptP2c = ptP2n ; +// bNext = ( bSingle1 || PL1.GetNextPoint( ptP1n)) && ( bSingle2 || PL2.GetNextPoint( ptP2n)) ; +// } +// // salvo isoparametrica PL2 in PL1 +// PL1.GetUPointList().swap( PL2.GetUPointList()) ; +// bSingle1 = bSingle2 ; +// } +// // la completo +// if ( ! stmSoup.End()) +// return nullptr ; +// // la salvo +// m_pSTM = GetBasicSurfTriMesh( stmSoup.GetSurf()) ; +// return m_pSTM ; +//} + //---------------------------------------------------------------------------- const SurfTriMesh* SurfBezier::GetAuxSurf( void) const @@ -1384,10 +1464,6 @@ SurfBezier::GetAuxSurf( void) const // se già calcolata, la restituisco if ( m_pSTM != nullptr) return m_pSTM ; - // costruttore della superficie - StmFromTriangleSoup stmSoup ; - if ( ! stmSoup.Start()) - return nullptr ; // definisco il numero degli step in U e in V double dMaxLenU = 0 ; for ( int j = 0 ; j <= m_nDegV * m_nSpanV ; ++ j) @@ -1397,54 +1473,121 @@ SurfBezier::GetAuxSurf( void) const for ( int i = 0 ; i <= m_nDegU * m_nSpanU ; ++ i) dMaxLenV = max( dMaxLenV, GetCurveOnVApproxLen( double( i) / m_nDegU)) ; int nStepV = GetSteps( m_nDegV, m_nSpanV, dMaxLenV, 2) ; - // prima curva isoparametrica (potrebbe essere un solo punto) - PolyLine PL1 ; - GetCurveOnU( 0, nStepU, PL1) ; - bool bSingle1 = ( PL1.GetPointNbr() == 1) ; - // ciclo sulle isoparametriche - for ( int i = 1 ; i <= nStepV ; ++ i) { - // seconda curva isoparametrica (con tanti punti quanti la prima, oppure uno solo) - double dV = double( i) * m_nSpanV / nStepV ; - PolyLine PL2 ; - GetCurveOnU( dV, nStepU, PL2) ; - bool bSingle2 = ( PL2.GetPointNbr() == 1) ; - // inserisco i triangoli della striscia nel costruttore della TriMesh - Point3d ptP1c, ptP2c ; - Point3d ptP1n, ptP2n ; - bool bNext = PL1.GetFirstPoint( ptP1c) && PL2.GetFirstPoint( ptP2c) ; - if ( bNext) { - if ( bSingle1 && bSingle2) - bNext = false ; - if ( bSingle1) - ptP1n = ptP1c ; - else - bNext = bNext && PL1.GetNextPoint( ptP1n) ; - if ( bSingle2) - ptP2n = ptP2c ; - else - bNext = bNext && PL2.GetNextPoint( ptP2n) ; + if ( m_nDegU == 1 && m_nDegV == 1) { + // costruttore della superficie + StmFromTriangleSoup stmSoup ; + if ( ! stmSoup.Start()) + return nullptr ; + // prima curva isoparametrica (potrebbe essere un solo punto) + PolyLine PL1 ; + GetCurveOnU( 0, nStepU, PL1) ; + bool bSingle1 = ( PL1.GetPointNbr() == 1) ; + // ciclo sulle isoparametriche + for ( int i = 1 ; i <= nStepV ; ++ i) { + // seconda curva isoparametrica (con tanti punti quanti la prima, oppure uno solo) + double dV = double( i) * m_nSpanV / nStepV ; + PolyLine PL2 ; + GetCurveOnU( dV, nStepU, PL2) ; + bool bSingle2 = ( PL2.GetPointNbr() == 1) ; + // inserisco i triangoli della striscia nel costruttore della TriMesh + Point3d ptP1c, ptP2c ; + Point3d ptP1n, ptP2n ; + bool bNext = PL1.GetFirstPoint( ptP1c) && PL2.GetFirstPoint( ptP2c) ; + if ( bNext) { + if ( bSingle1 && bSingle2) + bNext = false ; + if ( bSingle1) + ptP1n = ptP1c ; + else + bNext = bNext && PL1.GetNextPoint( ptP1n) ; + if ( bSingle2) + ptP2n = ptP2c ; + else + bNext = bNext && PL2.GetNextPoint( ptP2n) ; + } + while ( bNext) { + // eventuale primo triangolo (con base sui correnti e vertice su P2 successivo) + if ( ! AreSamePointApprox( ptP1c, ptP2c)) + stmSoup.AddTriangle( ptP2c, ptP1c, ptP2n) ; + // eventuale secondo triangolo (con vertice su P1 corrente e base sui successivi) + if ( ! AreSamePointApprox( ptP1n, ptP2n)) + stmSoup.AddTriangle( ptP1c, ptP1n, ptP2n) ; + // passo alla successiva coppia + ptP1c = ptP1n ; + ptP2c = ptP2n ; + bNext = ( bSingle1 || PL1.GetNextPoint( ptP1n)) && ( bSingle2 || PL2.GetNextPoint( ptP2n)) ; + } + // salvo isoparametrica PL2 in PL1 + PL1.GetUPointList().swap( PL2.GetUPointList()) ; + bSingle1 = bSingle2 ; } - while ( bNext) { - // eventuale primo triangolo (con base sui correnti e vertice su P2 successivo) - if ( ! AreSamePointApprox( ptP1c, ptP2c)) - stmSoup.AddTriangle( ptP2c, ptP1c, ptP2n) ; - // eventuale secondo triangolo (con vertice su P1 corrente e base sui successivi) - if ( ! AreSamePointApprox( ptP1n, ptP2n)) - stmSoup.AddTriangle( ptP1c, ptP1n, ptP2n) ; - // passo alla successiva coppia - ptP1c = ptP1n ; - ptP2c = ptP2n ; - bNext = ( bSingle1 || PL1.GetNextPoint( ptP1n)) && ( bSingle2 || PL2.GetNextPoint( ptP2n)) ; + // la completo + if ( ! stmSoup.End()) + return nullptr ; + // la salvo + m_pSTM = GetBasicSurfTriMesh( stmSoup.GetSurf()) ; + } + else { + // costruttore della superficie + KdTree kdTree( this) ; + kdTree.BuildTree( nStepU, nStepV) ; + POLYLINEVECTOR vPL ; + kdTree.GetPolygons( vPL) ; + PtrOwner pSrfTm( CreateBasicSurfTriMesh()) ; + + //srfTm.CreateByRegion( vPL) ; + // prendo i punti di ogni polyline dell'albero, li triangolo e li porto in 3d + for ( PolyLine i : vPL ) { + SurfTriMesh srfTmCell ; + PNTVECTOR vPnt ; + INTVECTOR vTria ; + Triangulate Tri ; + if ( ! Tri.Make( i, vPnt, vTria)) + return false ; + + // inizializzo la superficie + int nVert = int( vPnt.size()) ; + int nTria = int( vTria.size()) / 3 ; + if ( ! srfTmCell.Init( nVert, nTria)) + return false ; + + // porti i vertici dallo spazio parametrico allo spazio 3d e li inserisco nella superficie + for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) { + Point3d pt3d; + GetPointD1D2( vPnt[i].y, vPnt[i].x, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d) ; + if ( srfTmCell.AddVertex( pt3d) == SVT_NULL) + return false ; + } + + // recupero i triangoli e li inserisco nella superficie + int vV[3] ; + for ( int i = 0 ; i < nTria ; ++i) { + vV[0] = vTria[3*i] ; + vV[1] = vTria[3*i+1] ; + vV[2] = vTria[3*i+2] ; + if ( srfTmCell.AddTriangle( vV) == SVT_NULL) + return false ; + } + + // sistemo la topologia + if ( ! srfTmCell.AdjustTopology()) + return false ; + //if ( ! pSrfTm->Add( srfTmCell)) + // return false ; + + if ( ! pSrfTm->IsValid() ) { + *pSrfTm= srfTmCell ; + } + else { + if ( ! pSrfTm->Add( srfTmCell)) + return false ; + } + } - // salvo isoparametrica PL2 in PL1 - PL1.GetUPointList().swap( PL2.GetUPointList()) ; - bSingle1 = bSingle2 ; - } - // la completo - if ( ! stmSoup.End()) - return nullptr ; - // la salvo - m_pSTM = GetBasicSurfTriMesh( stmSoup.GetSurf()) ; + + // la salvo + m_pSTM = Release(pSrfTm) ; + } return m_pSTM ; } diff --git a/SurfBezier.h b/SurfBezier.h index f64e5a1..b5366e9 100644 --- a/SurfBezier.h +++ b/SurfBezier.h @@ -166,7 +166,7 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW PNTVECTOR m_vPtCtrl ; // vettore dei punti di controllo DBLVECTOR m_vWeCtrl ; // vettore dei pesi di controllo SurfFlatRegion* m_pTrimReg ; // eventuale regione di trim - int m_nTempProp[2] ; // vettore proprietà temporanee + int m_nTempProp[2] ; // vettore proprietà temporanee } ; //----------------------------------------------------------------------------- From 2d83c860f24be8ab4700b3de6712ca18999b47c9 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 8 May 2023 17:02:02 +0200 Subject: [PATCH 02/44] EgtGeomKernel : - utilizzo di un binary tree al posto del kd-tree - implementate le funzioni sul binary tree ( a parte il bilanciamento) - errori noti : calcolo curvatura per decidere la direzione di split. --- EgtGeomKernel.vcxproj | 4 +- EgtGeomKernel.vcxproj.filters | 4 +- KdTree.cpp | 286 ------------- KdTree.h | 73 ---- SurfBezier.cpp | 31 +- Tree.cpp | 756 ++++++++++++++++++++++++++++++++++ Tree.h | 92 +++++ 7 files changed, 869 insertions(+), 377 deletions(-) delete mode 100644 KdTree.cpp delete mode 100644 KdTree.h create mode 100644 Tree.cpp create mode 100644 Tree.h diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index 0e496f4..ef86681 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -339,7 +339,7 @@ copy $(TargetPath) \EgtProg\Dll64 - + @@ -604,7 +604,7 @@ copy $(TargetPath) \EgtProg\Dll64 - + diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index 4503501..ce84aa1 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -471,7 +471,7 @@ File di origine\GeoOffset - + File di origine\Base @@ -1106,7 +1106,7 @@ File di intestazione - + File di intestazione diff --git a/KdTree.cpp b/KdTree.cpp deleted file mode 100644 index fc945ef..0000000 --- a/KdTree.cpp +++ /dev/null @@ -1,286 +0,0 @@ -//---------------------------------------------------------------------------- -// EgalTech 2023 -//---------------------------------------------------------------------------- -// File : Kd-tree.cpp Data : 21.04.23 Versione : -// Contenuto : Implementazione della classe kd-tree. -// -// -// -// Modifiche : 21.04.23 DB Creazione modulo. -// -// -//---------------------------------------------------------------------------- - -//--------------------------- Include ---------------------------------------- -#include "stdafx.h" -#include "KdTree.h" -#include "SurfBezier.h" -#include "GeoConst.h" - -using namespace std ; - -//---------------------------------------------------------------------------- -Cell::Cell( void) - : m_ptPbl( ORIG), m_ptPtr( ORIG), m_bProcessed ( false) , m_bSplitVert ( true) , m_dSplit( 0) , m_cTop ( nullptr), m_cBottom( nullptr), - m_cLeft( nullptr), m_cRight ( nullptr), m_cParent( nullptr), m_cChild1( nullptr), m_cChild2( nullptr) -{} - -//---------------------------------------------------------------------------- -Cell::~Cell( void) -{ -} - -//---------------------------------------------------------------------------- -inline bool -Cell::IsSame( std::shared_ptr cOtherCell) -{ - if ( AreSamePointXYApprox( m_ptPbl, cOtherCell->GetBottomLeft()) && - AreSamePointXYApprox( m_ptPtr, cOtherCell->GetTopRight())) { - return true ; - } - else { - return false ; - } -} - -//---------------------------------------------------------------------------- -void -Cell::Split( double dSplitValue) -{ - m_dSplit = dSplitValue ; - //Cell cChild1, cChild2, cParent, cTop, cBottom, cLeft, cRight ; - m_cChild1 = make_shared() ; - //m_cChild2 = &cChild2 ; - //m_cParent = &cParent ; - //m_cTop = &cTop ; - //m_cBottom = &cBottom ; - //m_cLeft = &cLeft ; - //m_cRight = &cRight ; - - m_cChild2 = make_shared() ; - //m_cParent = make_shared() ; - //m_cTop = make_shared() ; - //m_cBottom = make_shared() ; - //m_cLeft = make_shared() ; - //m_cRight = make_shared() ; - if ( ! m_bSplitVert ) - { - // la cella figlio 1 è quella sopra - Point3d ptBL( m_ptPbl.x, m_dSplit) ; - m_cChild1->SetBottomLeft( ptBL) ; - m_cChild1->SetTopRight( m_ptPtr) ; - m_cChild1->m_cTop = m_cTop ; - m_cChild1->m_cBottom = m_cChild2 ; - m_cChild1->m_cLeft = m_cLeft ; - m_cChild1->m_cRight = m_cRight ; - //m_cChild1->m_cParent = make_shared(*this) ; - Point3d ptTR( m_ptPtr.x, m_dSplit) ; - m_cChild2->SetBottomLeft( m_ptPbl) ; - m_cChild2->SetTopRight( ptTR) ; - m_cChild2->m_cTop = m_cChild1 ; - m_cChild2->m_cBottom = m_cBottom ; - m_cChild2->m_cLeft = m_cLeft ; - m_cChild2->m_cRight = m_cRight ; - //m_cChild2->m_cParent = make_shared(*this) ; - } - else { - // la cella figlio 1 è quella di sinistra - Point3d ptTR( m_dSplit, m_ptPtr.y) ; - m_cChild1->SetBottomLeft( m_ptPbl) ; - m_cChild1->SetTopRight( ptTR) ; - m_cChild1->m_cTop = m_cTop ; - m_cChild1->m_cBottom = m_cBottom ; - m_cChild1->m_cLeft = m_cLeft ; - m_cChild1->m_cRight = m_cChild2 ; - //m_cChild1->m_cParent = make_shared(*this) ; - Point3d ptBL( m_dSplit, m_ptPbl.y) ; - m_cChild2->SetBottomLeft( ptBL) ; - m_cChild2->SetTopRight( m_ptPtr) ; - m_cChild2->m_cTop = m_cTop ; - m_cChild2->m_cBottom = m_cBottom ; - m_cChild2->m_cLeft = m_cChild1 ; - m_cChild2->m_cRight = m_cRight ; - //m_cChild2->m_cParent = make_shared(*this) ; - } - //m_bProcessed = true ; -} - -//---------------------------------------------------------------------------- -bool -//Cell::IsLeaf ( void) const -Cell::IsLeaf ( void) -{ - if( m_cChild1 == nullptr && m_cChild2 == nullptr) - return true ; - else - return false ; -} - -//---------------------------------------------------------------------------- -KdTree::KdTree( void) - : m_dLinTol(LIN_TOL_FINE), m_pSrfBz(nullptr), m_cRoot( make_shared()) -{} - -//---------------------------------------------------------------------------- -KdTree::KdTree( const SurfBezier* pSrfBz) - : m_dLinTol( LIN_TOL_FINE), m_pSrfBz ( pSrfBz) -{ - // le coordinate delle celle sono nello spazio parametrico - int nDegU, nDegV, nSpanU, nSpanV ; - bool bIsRat, bTrimmed ; - m_pSrfBz->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bIsRat, bTrimmed) ; - Point3d ptTop( nSpanU, nSpanV) ; - m_cRoot = make_shared() ; - m_cRoot->SetBottomLeft( ORIG) ; - m_cRoot->SetTopRight( ptTop) ; -} - -//---------------------------------------------------------------------------- -KdTree::~KdTree( void) -{ -} - -//---------------------------------------------------------------------------- -void KdTree::SetSurf( const SurfBezier* pSrfBz) -{ - m_pSrfBz = pSrfBz ; - // le coordinate delle celle sono nello spazio parametrico - int nDegU, nDegV, nSpanU, nSpanV ; - bool bIsRat, bTrimmed ; - m_pSrfBz->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bIsRat, bTrimmed) ; - Point3d ptTop( nSpanU, nSpanV) ; - m_cRoot = make_shared() ; - m_cRoot->SetBottomLeft( ORIG) ; - m_cRoot->SetTopRight( ptTop) ; -} - -//---------------------------------------------------------------------------- -bool KdTree::BuildTree( int nStepU, int nStepV) -{ - // trovo dove splittare la cella e creo i puntatori ai figli - - // comincio a suddividere la superficie usando un kd-tree - // approssimo con una bilineare e se l'errore di approssimazione è troppo grande cerco una direzione - // in cui dividere la superficie - - double err ; // errore calcolato - double dist ; // distanza tra punti selezionati - double dU, dV , dUmax, dVmax; - Point3d ptBz, ptBl ; - // cerco lo scostamento massimo tra la sup di Bezier e la sua approssimazione bilineare - - // shared_ptr cToSplit = make_shared(&m_cRoot) ; - shared_ptr cToSplit = m_cRoot ; - - - //while ( cToSplit != nullptr && - // ( cToSplit->IsSame( &m_cRoot) || // per entrare nel ciclo - // cToSplit->IsProcessed() == false || // per processare le child1 - // ( ! cToSplit->IsSame( &m_cRoot) && cToSplit->m_cChild2->IsProcessed() == false))) { // per processare le child2 finché torno alla root - int c = 1 ; - while ( cToSplit != nullptr && cToSplit->IsProcessed() == false) { - err = 0 ; - // calcolo la bilineare per gli estremi della cella - SurfBezier pSrfBl ; - pSrfBl.Init(1, 1, 1, 1, false) ; - m_pSrfBz->GetPointD1D2( cToSplit->GetBottomLeft().x, cToSplit->GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; - pSrfBl.SetControlPoint( 0, ptBz) ; // P00 - m_pSrfBz->GetPointD1D2( cToSplit->GetTopRight().x, cToSplit->GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; - pSrfBl.SetControlPoint( 1, ptBz) ; // P01 - m_pSrfBz->GetPointD1D2( cToSplit->GetBottomLeft().x, cToSplit->GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; - pSrfBl.SetControlPoint( 2, ptBz) ; // P10 - m_pSrfBz->GetPointD1D2( cToSplit->GetTopRight().x, cToSplit->GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; - pSrfBl.SetControlPoint( 3, ptBz) ; // P11 - for ( int i = 1 ; i <= nStepU ; ++ i) { - for ( int j = 1 ; j <= nStepV ; ++ j) { - dU = double ( i) / nStepU * ( cToSplit->GetTopRight().y - cToSplit->GetBottomLeft().y) ; - dV = double ( j) / nStepV * ( cToSplit->GetTopRight().x - cToSplit->GetBottomLeft().x) ; - if ( ! m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) || - ! pSrfBl.GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBl)) - return false ; - dist = Dist( ptBz, ptBl) ; - if ( dist > err) { // ### nelle condizioni dell'if probabilmente devo già controllare che la dimensione della cella non sia troppo piccola - err = dist ; - dUmax = dU ; - dVmax = dV ; - } - } - } - // devo spostare la condizione sulla dimensione minima di una cella///////////////////////////////////////////////////////////////////// - // probabilmente qui ### - if ( err > m_dLinTol && ( dUmax - cToSplit->GetBottomLeft().y) >= 0.01 && ( dVmax - cToSplit->GetBottomLeft().x) >= 0.01) { - // devo trovare i punti sui lati corrispondenti a dUmax e dVmax, unendo queste coppie trovo le due direzioni di possibile split - // punti medi del lato successivo in senso orario rispetto al relativo vertice della patch - Point3d ptPSrf, ptP00, ptP10, ptP11, ptP01; - m_pSrfBz->GetPointD1D2( dUmax, dVmax, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - m_pSrfBz->GetPointD1D2( dUmax, 0, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00) ; - m_pSrfBz->GetPointD1D2( 1, dVmax, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10) ; - m_pSrfBz->GetPointD1D2( dUmax, 1, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11) ; - m_pSrfBz->GetPointD1D2( 0, dVmax, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01) ; - Point3d ptP00P11 = ( 1 - dVmax) * ptP00 + dVmax * ptP11 ; - Point3d ptP10P01 = ( 1 - dUmax) * ptP10 + dUmax * ptP01 ; - // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza - // effettuo lo split e configuro le celle figlie - if ( Dist(ptP00P11, ptPSrf) > Dist(ptP10P01, ptPSrf)) { - cToSplit->SetSplitDirVert( false) ; - cToSplit->Split( dUmax) ; - } - else { - cToSplit->SetSplitDirVert( true) ; - cToSplit->Split( dVmax) ; - } - cToSplit->m_cChild1->SetParent( cToSplit) ; - cToSplit->m_cChild2->SetParent( cToSplit) ; - // procedo con lo split del Child1 - cToSplit = cToSplit->m_cChild1 ; - } - else { - // sono arrivato ad una cella Leaf, quindi salvo il poligono - cToSplit->Processed() ; - Point3d ptPbr( cToSplit->GetTopRight().x, cToSplit->GetBottomLeft().y) ; - Point3d ptPtl( cToSplit->GetBottomLeft().x, cToSplit->GetTopRight().y) ; - m_vPolygons.emplace_back() ; - m_vPolygons.back().AddUPoint(0, cToSplit->GetBottomLeft()) ; - m_vPolygons.back().AddUPoint(0.25, ptPbr) ; - m_vPolygons.back().AddUPoint(0.5, cToSplit->GetTopRight()) ; - m_vPolygons.back().AddUPoint(0.75, ptPtl) ; - m_vPolygons.back().AddUPoint(1, cToSplit->GetBottomLeft()) ; - // risalgo i parent finché non trovo il primo Child2 da processare - cToSplit = cToSplit->m_cParent ; - if ( cToSplit->m_cChild1->IsProcessed() && cToSplit->m_cChild2->IsProcessed()) - cToSplit->Processed() ; - // questa condizione mi manda in un loop perché non processo mai il child2 di root - // a'altro canto devo evitare di fare i passaggi successivi se sono già parent processato - - //if ( cToSplit->IsSame( &m_cRoot)) - // continue ; - - while ( cToSplit->m_cChild2->IsProcessed()) { - if ( cToSplit->m_cParent != nullptr ) - cToSplit = cToSplit->m_cParent ; - if ( cToSplit->m_cChild1->IsProcessed() && cToSplit->m_cChild2->IsProcessed()) - cToSplit->Processed() ; - if ( cToSplit->IsSame( m_cRoot) && cToSplit->m_cChild2->IsProcessed()) - break ; - } - //if ( cToSplit->IsSame( &m_cRoot)) - // continue ; - //else - // cToSplit = cToSplit->m_cChild2 ; - - cToSplit = cToSplit->m_cChild2 ; - } - c ++ ; - } - return true ; -} - -//---------------------------------------------------------------------------- -bool KdTree::GetPolygons( POLYLINEVECTOR& vPolygons) -{ - // restituisco i poligoni delle celle del kd-tree nello spazio parametrico - if ( m_vPolygons.empty()) - return false ; - vPolygons = m_vPolygons ; - return true ; -} \ No newline at end of file diff --git a/KdTree.h b/KdTree.h deleted file mode 100644 index c782103..0000000 --- a/KdTree.h +++ /dev/null @@ -1,73 +0,0 @@ -//---------------------------------------------------------------------------- -// EgalTech 2023 -//---------------------------------------------------------------------------- -// File : Kd-tree.h Data : 21.04.23 Versione : -// Contenuto : Implementazione della classe Cell di un kd-tree. -// -// -// -// Modifiche : 21.04.23 DB Creazione modulo. -// -// -//---------------------------------------------------------------------------- - -#pragma once - -//--------------------------- Include ---------------------------------------- -#include "SurfBezier.h" - -//---------------------------------------------------------------------------- -class Cell -{ - public : - ~Cell( void) ; - Cell( void) ; - Cell( Point3d ptBL, Point3d ptTR) : m_ptPbl( ptBL), m_ptPtr(ptTR) {} - inline bool IsSame ( std::shared_ptr cOtherCell) ; - void SetBottomLeft( Point3d ptBL) { m_ptPbl = ptBL ; } - void SetTopRight( Point3d ptTR) { m_ptPtr = ptTR ; } - void SetSplitDirVert( bool bVert) { m_bSplitVert = bVert ; } - void SetSplitValue ( double dSplitValue) { m_dSplit = dSplitValue ; } - void SetParent (std::shared_ptr pCParent) { m_cParent = pCParent ; } - void Split( double dSpiltValue) ; - Point3d GetBottomLeft( void) { return m_ptPbl ; } - Point3d GetTopRight( void) { return m_ptPtr ; } - //bool IsLeaf( void) const ; - bool IsLeaf( void) ; - bool IsProcessed ( void) const { return m_bProcessed ; } - void Processed ( void) { m_bProcessed = true ; } - - public : - std::shared_ptr m_cTop ; // cella adiacente al lato top - std::shared_ptr m_cBottom ; // cella adiacente al lato bottom - std::shared_ptr m_cLeft ; // cella adiacente al lato left - std::shared_ptr m_cRight ; // cella adiacente al lato right - std::shared_ptr m_cParent ; // cella genitore - std::shared_ptr m_cChild1 ; // prima cella figlio - std::shared_ptr m_cChild2 ; // seconda cella figlio - - private : - Point3d m_ptPbl ; // punto bottom left - Point3d m_ptPtr ; // punto top right - bool m_bProcessed ; // flag che indica se la cella è stata processata - bool m_bSplitVert ; // flag che indica in quale direzione è stata divisa la cella - double m_dSplit ; // lunghezza normalizzata a cui è stata splittata la cella -} ; - -//---------------------------------------------------------------------------- -class KdTree -{ -public : - ~KdTree( void) ; - KdTree( void) ; - KdTree ( const SurfBezier* pSrfBz) ; - void SetSurf( const SurfBezier* pSrfBz) ; - bool BuildTree( int nStepU, int nStepV) ; - bool GetPolygons( POLYLINEVECTOR& vPolygons) ; - -private : - double m_dLinTol ; // errore dell'approssimazione - std::shared_ptr m_cRoot ; // cella base - const SurfBezier* m_pSrfBz ; // root - POLYLINEVECTOR m_vPolygons ; // vettore dei poligoni del kd-tree -} ; \ No newline at end of file diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 1ec67b5..7106029 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -20,7 +20,7 @@ #include "Bernstein.h" #include "CurveBezier.h" #include "CurveComposite.h" -#include "KdTree.h" +#include "Tree.h" #include "Triangulate.h" #include "SurfTriMesh.h" #include "/EgtDev/Include/EGkSfrCreate.h" @@ -1473,7 +1473,7 @@ SurfBezier::GetAuxSurf( void) const for ( int i = 0 ; i <= m_nDegU * m_nSpanU ; ++ i) dMaxLenV = max( dMaxLenV, GetCurveOnVApproxLen( double( i) / m_nDegU)) ; int nStepV = GetSteps( m_nDegV, m_nSpanV, dMaxLenV, 2) ; - if ( m_nDegU == 1 && m_nDegV == 1) { + if ( m_nDegU == 1 && m_nDegV == 1) { // costruttore della superficie StmFromTriangleSoup stmSoup ; if ( ! stmSoup.Start()) @@ -1529,16 +1529,16 @@ SurfBezier::GetAuxSurf( void) const } else { // costruttore della superficie - KdTree kdTree( this) ; - kdTree.BuildTree( nStepU, nStepV) ; + Tree Tree( this) ; + Tree.BuildTree() ; POLYLINEVECTOR vPL ; - kdTree.GetPolygons( vPL) ; + Tree.GetPolygons( vPL) ; PtrOwner pSrfTm( CreateBasicSurfTriMesh()) ; //srfTm.CreateByRegion( vPL) ; // prendo i punti di ogni polyline dell'albero, li triangolo e li porto in 3d - for ( PolyLine i : vPL ) { - SurfTriMesh srfTmCell ; + for ( PolyLine i : vPL) { + PtrOwner srfTmCell( CreateBasicSurfTriMesh()) ; PNTVECTOR vPnt ; INTVECTOR vTria ; Triangulate Tri ; @@ -1548,14 +1548,15 @@ SurfBezier::GetAuxSurf( void) const // inizializzo la superficie int nVert = int( vPnt.size()) ; int nTria = int( vTria.size()) / 3 ; - if ( ! srfTmCell.Init( nVert, nTria)) + if ( ! srfTmCell->Init( nVert, nTria)) return false ; // porti i vertici dallo spazio parametrico allo spazio 3d e li inserisco nella superficie for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) { Point3d pt3d; - GetPointD1D2( vPnt[i].y, vPnt[i].x, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d) ; - if ( srfTmCell.AddVertex( pt3d) == SVT_NULL) + GetPointD1D2( vPnt[i].x, vPnt[i].y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d) ; + if ( srfTmCell->AddVertex( pt3d) == SVT_NULL) + //if ( srfTmCell->AddVertex( vPnt[i]) == SVT_NULL ) return false ; } @@ -1565,21 +1566,23 @@ SurfBezier::GetAuxSurf( void) const vV[0] = vTria[3*i] ; vV[1] = vTria[3*i+1] ; vV[2] = vTria[3*i+2] ; - if ( srfTmCell.AddTriangle( vV) == SVT_NULL) + if ( srfTmCell->AddTriangle( vV) == SVT_NULL) return false ; } // sistemo la topologia - if ( ! srfTmCell.AdjustTopology()) + if ( ! srfTmCell->AdjustTopology()) return false ; //if ( ! pSrfTm->Add( srfTmCell)) // return false ; if ( ! pSrfTm->IsValid() ) { - *pSrfTm= srfTmCell ; + //pSrfTm.Set( CloneBasicSurfTriMesh(srfTmCell)) ; + pSrfTm.Set( Release(srfTmCell)) ; } else { - if ( ! pSrfTm->Add( srfTmCell)) + //if ( ! pSrfTm->Add( *srfTmCell)) + if ( ! pSrfTm->DoSewing( *srfTmCell)) return false ; } diff --git a/Tree.cpp b/Tree.cpp new file mode 100644 index 0000000..3d6f8e3 --- /dev/null +++ b/Tree.cpp @@ -0,0 +1,756 @@ +//---------------------------------------------------------------------------- +// EgalTech 2023 +//---------------------------------------------------------------------------- +// File : Tree.cpp Data : 21.04.23 Versione : +// Contenuto : Implementazione della classe Tree. +// +// +// +// Modifiche : 21.04.23 DB Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include +#include "Tree.h" +#include "SurfBezier.h" +#include "GeoConst.h" + +using namespace std ; + +//---------------------------------------------------------------------------- +Cell::Cell( void) + : m_nId( -1), m_ptPbl( ORIG), m_bProcessed ( false) , m_bSplitVert ( true) , m_nTop ( -2), m_nBottom( -2), + m_nLeft( -2), m_nRight ( -2), m_nParent( -2), m_nDepth( 0), m_nChild1( -2), m_nChild2( -2) +{ + Point3d ptTr ( 1, 1) ; + m_ptPtr = ptTr ; +} + + +//---------------------------------------------------------------------------- +Cell::Cell( Point3d ptBL, Point3d ptTR) + : m_nId( -1), m_ptPbl( ptBL), m_ptPtr(ptTR), m_bProcessed ( false) , m_bSplitVert ( true) , m_nTop ( -2), + m_nBottom( -2), m_nLeft( -2), m_nRight ( -2), m_nParent( -2), m_nDepth( 0), m_nChild1( -2), m_nChild2( -2) +{} + + +//---------------------------------------------------------------------------- +Cell::~Cell( void) +{ +} + +//---------------------------------------------------------------------------- +inline bool +Cell::IsSame( Cell cOtherCell) +{ + if ( AreSamePointXYApprox( m_ptPbl, cOtherCell.GetBottomLeft()) && + AreSamePointXYApprox( m_ptPtr, cOtherCell.GetTopRight())) { + return true ; + } + else { + return false ; + } +} + +//---------------------------------------------------------------------------- +bool +//Cell::IsLeaf ( void) const +Cell::IsLeaf ( void) +{ + if( m_nChild1 == -2 && m_nChild2 == -2) + return true ; + else + return false ; +} + +//---------------------------------------------------------------------------- +Tree::Tree( void) + : m_dLinTol(LIN_TOL_FINE), m_pSrfBz(nullptr), m_nRoot( -1) +{ + Point3d ptBl( 0, 0), ptTr ( 1, 1) ; + Cell cRoot( ptBl, ptTr) ; + m_mTree.insert( pair< int, Cell>( m_nRoot, cRoot)) ; +} + +//---------------------------------------------------------------------------- +Tree::Tree( const SurfBezier* pSrfBz) + : m_dLinTol( LIN_TOL_FINE), m_pSrfBz ( pSrfBz), m_nRoot( -1) +{ + // le coordinate delle celle sono nello spazio parametrico + int nDegU, nDegV, nSpanU, nSpanV ; + bool bIsRat, bTrimmed ; + m_pSrfBz->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bIsRat, bTrimmed) ; + Point3d ptTop( nSpanU, nSpanV) ; + Cell cRoot( ORIG, ptTop) ; + m_mTree.insert( pair< int, Cell>( m_nRoot, cRoot)) ; +} + +//---------------------------------------------------------------------------- +Tree::~Tree( void) +{ +} + +//---------------------------------------------------------------------------- +void Tree::SetSurf( const SurfBezier* pSrfBz) +{ + m_pSrfBz = pSrfBz ; + // le coordinate delle celle sono nello spazio parametrico + int nDegU, nDegV, nSpanU, nSpanV ; + bool bIsRat, bTrimmed ; + m_pSrfBz->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bIsRat, bTrimmed) ; + Point3d ptTop( nSpanU, nSpanV) ; + Cell cRoot( ORIG, ptTop) ; + m_mTree.insert( pair< int, Cell>( -1, cRoot)) ; +} + +//---------------------------------------------------------------------------- +void +Tree::Split( int nId) +{ + Cell cChild1, cChild2 ; + cChild1.m_nDepth = m_mTree[nId].m_nDepth + 1 ; + cChild2.m_nDepth = m_mTree[nId].m_nDepth + 1 ; + int nNodes = (int) m_mTree.size() ; + cChild1.m_nId = nNodes - 1 ; + m_mTree[nId].m_nChild1 = nNodes - 1 ; + cChild2.m_nId = nNodes ; + m_mTree[nId].m_nChild2 = nNodes ; + m_mTree.insert( pair( nNodes - 1, cChild1)) ; + m_mTree.insert( pair( nNodes, cChild2)) ; + if ( ! m_mTree[nId].IsSplitVert()) + { + // la cella figlio 1 è quella sopra + Point3d ptBL( m_mTree[nId].GetBottomLeft().x, ( m_mTree[nId].GetBottomLeft().y + m_mTree[nId].GetTopRight().y) / 2) ; + m_mTree[m_mTree[nId].m_nChild1].SetBottomLeft( ptBL) ; + m_mTree[m_mTree[nId].m_nChild1].SetTopRight( m_mTree[nId].GetTopRight()) ; + m_mTree[m_mTree[nId].m_nChild1].m_nTop = m_mTree[nId].m_nTop ; + m_mTree[m_mTree[nId].m_nChild1].m_nBottom = m_mTree[nId].m_nChild2 ; + m_mTree[m_mTree[nId].m_nChild1].m_nLeft = m_mTree[nId].m_nLeft ; + m_mTree[m_mTree[nId].m_nChild1].m_nRight = m_mTree[nId].m_nRight ; + Point3d ptTR( m_mTree[nId].GetTopRight().x, ( m_mTree[nId].GetTopRight().y + m_mTree[nId].GetBottomLeft().y) / 2) ; + m_mTree[m_mTree[nId].m_nChild2].SetBottomLeft( m_mTree[nId].GetBottomLeft()) ; + m_mTree[m_mTree[nId].m_nChild2].SetTopRight( ptTR) ; + m_mTree[m_mTree[nId].m_nChild2].m_nTop = m_mTree[nId].m_nChild1 ; + m_mTree[m_mTree[nId].m_nChild2].m_nBottom = m_mTree[nId].m_nBottom ; + m_mTree[m_mTree[nId].m_nChild2].m_nLeft = m_mTree[nId].m_nLeft ; + m_mTree[m_mTree[nId].m_nChild2].m_nRight = m_mTree[nId].m_nRight ; + } + else { + // la cella figlio 1 è quella di sinistra + Point3d ptTR( ( m_mTree[nId].GetBottomLeft().x + m_mTree[nId].GetTopRight().x) / 2, m_mTree[nId].GetTopRight().y) ; + m_mTree[m_mTree[nId].m_nChild1].SetBottomLeft( m_mTree[nId].GetBottomLeft()) ; + m_mTree[m_mTree[nId].m_nChild1].SetTopRight( ptTR) ; + m_mTree[m_mTree[nId].m_nChild1].m_nTop = m_mTree[nId].m_nTop ; + m_mTree[m_mTree[nId].m_nChild1].m_nBottom = m_mTree[nId].m_nBottom ; + m_mTree[m_mTree[nId].m_nChild1].m_nLeft = m_mTree[nId].m_nLeft ; + m_mTree[m_mTree[nId].m_nChild1].m_nRight = m_mTree[nId].m_nChild2 ; + Point3d ptBL(( m_mTree[nId].GetBottomLeft().x + m_mTree[nId].GetTopRight().x) / 2, m_mTree[nId].GetBottomLeft().y) ; + m_mTree[m_mTree[nId].m_nChild2].SetBottomLeft( ptBL) ; + m_mTree[m_mTree[nId].m_nChild2].SetTopRight( m_mTree[nId].GetTopRight()) ; + m_mTree[m_mTree[nId].m_nChild2].m_nTop = m_mTree[nId].m_nTop ; + m_mTree[m_mTree[nId].m_nChild2].m_nBottom = m_mTree[nId].m_nBottom ; + m_mTree[m_mTree[nId].m_nChild2].m_nLeft = m_mTree[nId].m_nChild1 ; + m_mTree[m_mTree[nId].m_nChild2].m_nRight = m_mTree[nId].m_nRight ; + } + m_mTree[m_mTree[nId].m_nChild1].SetParent( nId) ; + m_mTree[m_mTree[nId].m_nChild2].SetParent( nId) ; + //m_bProcessed = true ; +} + +////---------------------------------------------------------------------------- +//bool Tree::BuildTree(void) +//{ +// // di default SplitVert è true ! +// int ToSplit = -1; +// m_mTree[ToSplit].SetSplitDirVert( true) ; +// Split( ToSplit) ; +// // celle 2 e 3 +// ToSplit = m_mTree[-1].m_nChild1 ; +// m_mTree[ToSplit].SetSplitDirVert( false) ; +// Split( ToSplit) ; +// // celle 4 e 5 +// ToSplit = m_mTree[ToSplit].m_nChild1 ; +// m_mTree[ToSplit].SetSplitDirVert( true) ; +// Split( ToSplit) ; +// // celle 6 e 7 +// ToSplit = m_mTree[ToSplit].m_nChild2 ; +// m_mTree[ToSplit].SetSplitDirVert( false) ; +// Split( ToSplit) ; +// // celle 8 e 9 +// ToSplit = m_mTree[ToSplit].m_nChild2 ; +// m_mTree[ToSplit].SetSplitDirVert( true) ; +// Split( ToSplit) ; +// // celle 10 e 11 +// ToSplit = m_mTree[ToSplit].m_nChild1 ; +// m_mTree[ToSplit].SetSplitDirVert( false) ; +// Split( ToSplit) ; +// // celle 12 e 13 +// ToSplit = m_mTree[ToSplit].m_nParent ; +// ToSplit = m_mTree[ToSplit].m_nChild2 ; +// m_mTree[ToSplit].SetSplitDirVert( true) ; +// Split( ToSplit) ; +// INTVECTOR vTops, vBottoms, vLefts, vRights , vLeaves1, vLeaves2, vLeaves; +// int d1, d2 , H1 ; +// GetTopNeigh( 3, vTops) ; +// GetBottomNeigh( 6, vBottoms) ; +// GetLeftNeigh( 1, vLefts) ; +// GetRightNeigh( 4, vRights ) ; +// d1 = GetHeightLeaves( 7, vLeaves1) ; +// d2 = GetHeightLeaves( 5, vLeaves2) ; +// H1 = GetHeightLeaves( -1, vLeaves) ; +// m_vnLeaves = vLeaves ; +// int i = 0 ; +// +// return true ; +//} + + +//---------------------------------------------------------------------------- +bool Tree::BuildTree( void) +{ + // trovo dove splittare la cella e creo i puntatori ai figli + + // comincio a suddividere la superficie usando un kd-tree + // approssimo con una bilineare e se l'errore di approssimazione è troppo grande cerco una direzione + // in cui dividere la superficie + + double dErr ; // errore calcolato + double dDist; // distanza tra punti selezionati sulla isoparametrica + double dSide ; // lunghezza del lato della eventuale cella figlio + double dSplit = 0.5 ; // effettuo sempre split a metà + //double dSidemin = 0.05 ; // lunghezza minima del lato di una cella + double dSidemin = 0.1 ; // lunghezza minima del lato di una cella + int nSteps = 51 ; // numero di Step mentre scorro lungo un'isoparametrica + double dU, dV , dIter, dIterLoc, dULoc, dVLoc ; + bool bVert ; + Point3d ptBz, ptBl ; + // cerco lo scostamento massimo tra la sup di Bezier e la sua approssimazione bilineare + INTVECTOR vBalanceCheck ; + int nCToSplit = -1 ; + + int c = 1 ; + while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { + dErr = 0 ; + // verifico se l'approsimazione bilineare è ancora troppo distante dalla superficie reale + // calcolo la bilineare per gli estremi della cella + SurfBezier pSrfBl ; + pSrfBl.Init(1, 1, 1, 1, false) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; + pSrfBl.SetControlPoint( 0, ptBz) ; // P00 + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; + pSrfBl.SetControlPoint( 1, ptBz) ; // P01 + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; + pSrfBl.SetControlPoint( 2, ptBz) ; // P10 + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; + pSrfBl.SetControlPoint( 3, ptBz) ; // P11 + // scorro lungo le isoparametriche a questi valori di U e V per trovare dov'è il punto di maggior discostamento + dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; + dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; + dULoc = dU - m_mTree[nCToSplit].GetBottomLeft().x / ( m_mTree[nCToSplit].GetTopRight().x - m_mTree[nCToSplit].GetBottomLeft().x) ; + dVLoc = dV - m_mTree[nCToSplit].GetBottomLeft().y / ( m_mTree[nCToSplit].GetTopRight().y - m_mTree[nCToSplit].GetBottomLeft().y) ; + double dErrUmax, dErrVmax ; + for ( int i = 0 ; i < nSteps ; ++ i){ + dIter = double ( i) / double ( nSteps - 1) ; + dIterLoc = ( 1 - dIter) * m_mTree[nCToSplit].GetBottomLeft().y + dIter * m_mTree[nCToSplit].GetTopRight().y ; + if ( ! m_pSrfBz->GetPointD1D2( dU, dIterLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) || + ! pSrfBl.GetPointD1D2( dU, dIter, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBl)) /// dU è riferito alla Bz totale, quant'è sulla Bl?? + return false ; + dDist = Dist( ptBz, ptBl) ; + if ( dDist > dErr) { + dErr = dDist ; + bVert = true ; + dErrVmax = dErr ; + } + dIterLoc = ( 1 - dIter) * m_mTree[nCToSplit].GetBottomLeft().x + dIter * m_mTree[nCToSplit].GetTopRight().x ; + if ( ! m_pSrfBz->GetPointD1D2( dIterLoc, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) || + ! pSrfBl.GetPointD1D2( dIter, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBl)) /// dV è riferito alla Bz totale, quant'è sulla Bl?? + return false ; + dDist = Dist( ptBz, ptBl) ; + if ( dDist > dErr) { + dErr = dDist ; + bVert = false ; + dErrUmax = dErr ; + } + } + // verifico che la cella sia da splittare e che eventualmente sia abbastanza grande da poterlo fare + if ( bVert) + dSide = m_mTree[nCToSplit].GetTopRight().x - m_mTree[nCToSplit].GetBottomLeft().x ; + else + dSide = m_mTree[nCToSplit].GetTopRight().y - m_mTree[nCToSplit].GetBottomLeft().y ; + if ( dErr > m_dLinTol && dSide >= dSidemin) { + m_mTree[nCToSplit].SetSplitDirVert( bVert) ; + // effettuo lo split + Split( nCToSplit) ; + + // qui faccio i check per capire quali celle devo inserire in vBalanceCheck /////////////////////////////////////////////////////// + + // procedo con lo split del Child1 + nCToSplit = m_mTree[nCToSplit].m_nChild1 ; + } + else { + // sono arrivato ad una cella Leaf, quindi salvo la cella + m_vnLeaves.push_back( nCToSplit) ; + m_mTree[nCToSplit].Processed() ; + // risalgo i parent finché non trovo il primo Child2 da processare + nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + m_mTree[nCToSplit].Processed() ; + while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { + if ( m_mTree[nCToSplit].m_nParent != -2 ) + nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + m_mTree[nCToSplit].Processed() ; + if ( nCToSplit == m_nRoot && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed() ) + break ; + } + nCToSplit = m_mTree[nCToSplit].m_nChild2 ; + } + c ++ ; + } + Balance( vBalanceCheck) ; + return true ; +} + +//---------------------------------------------------------------------------- +void Tree::Balance( INTVECTOR vCheck) +{ + for ( int i : vCheck ) { + + } +} + +//---------------------------------------------------------------------------- +void Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) +{ + if ( (int) vTopNeighs.size() == 0) { + if ( m_mTree[nId].m_nTop == -2) + return ; + if ( m_mTree[m_mTree[nId].m_nTop].IsLeaf()) + vTopNeighs.push_back( m_mTree[nId].m_nTop) ; + else { + if ( m_mTree[m_mTree[nId].m_nTop].IsSplitVert()) { + // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima + if ( m_mTree[m_mTree[nId].m_nTop].GetTopRight().x - m_mTree[m_mTree[nId].m_nTop].GetBottomLeft().x <= + m_mTree[nId].GetTopRight().x - m_mTree[nId].GetBottomLeft().x) { + vTopNeighs.push_back( m_mTree[m_mTree[nId].m_nTop].m_nChild1) ; + vTopNeighs.push_back( m_mTree[m_mTree[nId].m_nTop].m_nChild2) ; + } + // altrimenti solo uno dei figli lo sarà + else{ + if ( m_mTree[m_mTree[m_mTree[nId].m_nTop].m_nChild1].GetTopRight().x <= m_mTree[nId].GetBottomLeft().x || + m_mTree[m_mTree[m_mTree[nId].m_nTop].m_nChild1].GetBottomLeft().x >= m_mTree[nId].GetTopRight().x ) + vTopNeighs.push_back( m_mTree[m_mTree[nId].m_nTop].m_nChild2) ; + else + vTopNeighs.push_back( m_mTree[m_mTree[nId].m_nTop].m_nChild1) ; + } + } + else { + vTopNeighs.push_back( m_mTree[m_mTree[nId].m_nTop].m_nChild2) ; + } + } + bool bAllLeaves = true ; + for ( int i : vTopNeighs ) { + if ( ! m_mTree[i].IsLeaf()) + bAllLeaves = false ; + } + if ( ! bAllLeaves ) + // almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child + GetTopNeigh( nId, vTopNeighs) ; + } + else { + for ( int j = 0 ; j != (int) vTopNeighs.size() ; ++ j) { + int i = vTopNeighs[j] ; + if ( m_mTree[i].IsLeaf()) + continue; + else { + // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child + vTopNeighs.erase( remove( vTopNeighs.begin(),vTopNeighs.end(),i)) ; + -- j ; + if ( m_mTree[i].IsSplitVert() ) { + // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima + if ( m_mTree[i].GetTopRight().x - m_mTree[i].GetBottomLeft().x <= + m_mTree[nId].GetTopRight().x - m_mTree[nId].GetBottomLeft().x) { + vTopNeighs.push_back( m_mTree[i].m_nChild1) ; + vTopNeighs.push_back( m_mTree[i].m_nChild2) ; + } + // altrimenti solo uno dei figli lo sarà + else { + if ( m_mTree[m_mTree[i].m_nChild1].GetTopRight().x <= m_mTree[nId].GetBottomLeft().x || + m_mTree[m_mTree[i].m_nChild1].GetBottomLeft().x >= m_mTree[nId].GetTopRight().x ) + vTopNeighs.push_back( m_mTree[i].m_nChild2) ; + else + vTopNeighs.push_back( m_mTree[i].m_nChild1) ; + } + } + else { + vTopNeighs.push_back( m_mTree[i].m_nChild2) ; + } + } + } + } + vector vCells ; + for ( int k : vTopNeighs ) + vCells.push_back( m_mTree[k]) ; + sort( vCells.begin(), vCells.end(), Cell::minorX ) ; + vTopNeighs.clear() ; + for ( Cell c : vCells) + vTopNeighs.push_back( c.m_nId) ; +} + +//---------------------------------------------------------------------------- +void Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) +{ + if ( (int) vBottomNeighs.size() == 0) { + if ( m_mTree[nId].m_nBottom == -2) + return ; + if ( m_mTree[m_mTree[nId].m_nBottom].IsLeaf()) + vBottomNeighs.push_back( m_mTree[nId].m_nBottom) ; + else { + if ( m_mTree[m_mTree[nId].m_nBottom].IsSplitVert()) { + // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima + if ( m_mTree[m_mTree[nId].m_nBottom].GetTopRight().x - m_mTree[m_mTree[nId].m_nBottom].GetBottomLeft().x <= + m_mTree[nId].GetTopRight().x - m_mTree[nId].GetBottomLeft().x) { + vBottomNeighs.push_back( m_mTree[m_mTree[nId].m_nBottom].m_nChild1) ; + vBottomNeighs.push_back( m_mTree[m_mTree[nId].m_nBottom].m_nChild2) ; + } + // altrimenti solo uno dei figli lo sarà + else{ + if ( m_mTree[m_mTree[m_mTree[nId].m_nBottom].m_nChild1].GetTopRight().x <= m_mTree[nId].GetBottomLeft().x || + m_mTree[m_mTree[m_mTree[nId].m_nBottom].m_nChild1].GetBottomLeft().x >= m_mTree[nId].GetTopRight().x ) + vBottomNeighs.push_back( m_mTree[m_mTree[nId].m_nBottom].m_nChild2) ; + else + vBottomNeighs.push_back( m_mTree[m_mTree[nId].m_nBottom].m_nChild1) ; + } + } + else { + vBottomNeighs.push_back( m_mTree[m_mTree[nId].m_nBottom].m_nChild1) ; + } + } + bool bAllLeaves = true ; + for ( int i : vBottomNeighs ) { + if ( ! m_mTree[i].IsLeaf()) + bAllLeaves = false ; + } + if ( ! bAllLeaves ) + // almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child + GetBottomNeigh( nId, vBottomNeighs) ; + } + else { + for ( int j = 0 ; j != (int) vBottomNeighs.size() ; ++ j) { + int i = vBottomNeighs[j] ; + if ( m_mTree[i].IsLeaf()) + continue; + else { + // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child + vBottomNeighs.erase( remove( vBottomNeighs.begin(),vBottomNeighs.end(),i)) ; + -- j ; + if ( m_mTree[i].IsSplitVert()) { + // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima + if ( m_mTree[i].GetTopRight().x - m_mTree[i].GetBottomLeft().x <= + m_mTree[nId].GetTopRight().x - m_mTree[nId].GetBottomLeft().x) { + vBottomNeighs.push_back( m_mTree[i].m_nChild1) ; + vBottomNeighs.push_back( m_mTree[i].m_nChild2) ; + } + // altrimenti solo uno dei figli lo sarà + else { + if ( m_mTree[m_mTree[i].m_nChild1].GetTopRight().x <= m_mTree[nId].GetBottomLeft().x || + m_mTree[m_mTree[i].m_nChild1].GetBottomLeft().x >= m_mTree[nId].GetTopRight().x ) + vBottomNeighs.push_back( m_mTree[i].m_nChild2) ; + else + vBottomNeighs.push_back( m_mTree[i].m_nChild1) ; + } + } + else { + vBottomNeighs.push_back( m_mTree[i].m_nChild1) ; + } + } + } + } + vector vCells ; + for ( int k : vBottomNeighs ) + vCells.push_back( m_mTree[k]) ; + sort( vCells.begin(), vCells.end(), Cell::minorX) ; + vBottomNeighs.clear() ; + for ( Cell c : vCells) + vBottomNeighs.push_back( c.m_nId) ; +} + + +//---------------------------------------------------------------------------- +void Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) +{ + if ( (int) vLeftNeighs.size() == 0 ) { + if ( m_mTree[nId].m_nLeft == -2) + return ; + if ( m_mTree[m_mTree[nId].m_nLeft].IsLeaf()) + vLeftNeighs.push_back( m_mTree[nId].m_nLeft) ; + else { + if ( ! m_mTree[m_mTree[nId].m_nLeft].IsSplitVert()) { + // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima + if ( m_mTree[m_mTree[nId].m_nLeft].GetTopRight().y - m_mTree[m_mTree[nId].m_nLeft].GetBottomLeft().y <= + m_mTree[nId].GetTopRight().y - m_mTree[nId].GetBottomLeft().y) { + vLeftNeighs.push_back( m_mTree[m_mTree[nId].m_nLeft].m_nChild1) ; + vLeftNeighs.push_back( m_mTree[m_mTree[nId].m_nLeft].m_nChild2) ; + } + // altrimenti solo uno dei figli lo sarà + else{ + if ( m_mTree[m_mTree[m_mTree[nId].m_nLeft].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || + m_mTree[m_mTree[m_mTree[nId].m_nLeft].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y ) + vLeftNeighs.push_back( m_mTree[m_mTree[nId].m_nLeft].m_nChild2) ; + else + vLeftNeighs.push_back( m_mTree[m_mTree[nId].m_nLeft].m_nChild1) ; + } + } + else { + vLeftNeighs.push_back( m_mTree[m_mTree[nId].m_nLeft].m_nChild2) ; + } + } + bool bAllLeaves = true ; + for ( int i : vLeftNeighs ) { + if ( ! m_mTree[i].IsLeaf()) + bAllLeaves = false ; + } + if ( ! bAllLeaves ) + // almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child + GetLeftNeigh( nId, vLeftNeighs) ; + } + else { + for ( int j = 0 ; j != (int) vLeftNeighs.size() ; ++ j) { + int i = vLeftNeighs[j] ; + if ( m_mTree[i].IsLeaf()) + continue; + else { + // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child + vLeftNeighs.erase( remove( vLeftNeighs.begin(),vLeftNeighs.end(),i)) ; + -- j ; + if ( ! m_mTree[i].IsSplitVert()) { + // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima + if ( m_mTree[i].GetTopRight().y - m_mTree[i].GetBottomLeft().y <= + m_mTree[nId].GetTopRight().y - m_mTree[nId].GetBottomLeft().y) { + vLeftNeighs.push_back( m_mTree[i].m_nChild1) ; + vLeftNeighs.push_back( m_mTree[i].m_nChild2) ; + } + // altrimenti solo uno dei figli lo sarà + else { + if ( m_mTree[m_mTree[i].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || + m_mTree[m_mTree[i].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y ) + vLeftNeighs.push_back( m_mTree[i].m_nChild2) ; + else + vLeftNeighs.push_back( m_mTree[i].m_nChild1) ; + } + } + else { + vLeftNeighs.push_back( m_mTree[i].m_nChild2) ; + } + } + } + } + vector vCells ; + for ( int k : vLeftNeighs) + vCells.push_back( m_mTree[k]) ; + sort( vCells.begin(), vCells.end(), Cell::minorY) ; + vLeftNeighs.clear() ; + for ( Cell c : vCells) + vLeftNeighs.push_back( c.m_nId) ; +} + +//---------------------------------------------------------------------------- +void Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) +{ + if ( (int) vRightNeighs.size() == 0) { + if ( m_mTree[nId].m_nRight == -2) + return ; + if ( m_mTree[m_mTree[nId].m_nRight].IsLeaf()) + vRightNeighs.push_back( m_mTree[nId].m_nRight) ; + else { + if ( ! m_mTree[m_mTree[nId].m_nRight].IsSplitVert()) { + // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima + if ( m_mTree[m_mTree[nId].m_nRight].GetTopRight().y - m_mTree[m_mTree[nId].m_nRight].GetBottomLeft().y <= + m_mTree[nId].GetTopRight().y - m_mTree[nId].GetBottomLeft().y) { + vRightNeighs.push_back( m_mTree[m_mTree[nId].m_nRight].m_nChild1) ; + vRightNeighs.push_back( m_mTree[m_mTree[nId].m_nRight].m_nChild2) ; + } + // altrimenti solo uno dei figli lo sarà + else{ + if ( m_mTree[m_mTree[m_mTree[nId].m_nRight].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || + m_mTree[m_mTree[m_mTree[nId].m_nRight].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y ) + vRightNeighs.push_back( m_mTree[m_mTree[nId].m_nRight].m_nChild2) ; + else + vRightNeighs.push_back( m_mTree[m_mTree[nId].m_nRight].m_nChild1) ; + } + } + else { + vRightNeighs.push_back( m_mTree[m_mTree[nId].m_nRight].m_nChild1) ; + } + } + bool bAllLeaves = true ; + for ( int i : vRightNeighs) { + if ( ! m_mTree[i].IsLeaf()) + bAllLeaves = false ; + } + if ( ! bAllLeaves ) + // almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child + GetRightNeigh( nId, vRightNeighs) ; + } + else { + for ( int j = 0 ; j != (int) vRightNeighs.size() ; ++ j) { + int i = vRightNeighs[j] ; + if ( m_mTree[i].IsLeaf()) + continue; + else { + // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child + vRightNeighs.erase( remove( vRightNeighs.begin(),vRightNeighs.end(), i)) ; + -- j ; + if ( ! m_mTree[i].IsSplitVert()) { + // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima + if ( m_mTree[i].GetTopRight().y - m_mTree[i].GetBottomLeft().y <= + m_mTree[nId].GetTopRight().y - m_mTree[nId].GetBottomLeft().y) { + vRightNeighs.push_back( m_mTree[i].m_nChild1) ; + vRightNeighs.push_back( m_mTree[i].m_nChild2) ; + } + // altrimenti solo uno dei figli lo sarà + else { + if ( m_mTree[m_mTree[i].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || + m_mTree[m_mTree[i].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y ) + vRightNeighs.push_back( m_mTree[i].m_nChild2) ; + else + vRightNeighs.push_back( m_mTree[i].m_nChild1) ; + } + } + else { + vRightNeighs.push_back( m_mTree[i].m_nChild1) ; + } + } + } + } + vector vCells ; + for ( int k : vRightNeighs) + vCells.push_back( m_mTree[k]) ; + sort( vCells.begin(), vCells.end(), Cell::minorY) ; + vRightNeighs.clear() ; + for ( Cell c : vCells) + vRightNeighs.push_back( c.m_nId) ; +} + +//---------------------------------------------------------------------------- +int Tree::GetHeightLeaves( int nId, INTVECTOR& vnLeaves, int d) +{ + if ( (int) vnLeaves.size() == 0) { + if ( m_mTree[nId].IsLeaf()) + return d ; + else { + vnLeaves.push_back( m_mTree[nId].m_nChild1) ; + vnLeaves.push_back( m_mTree[nId].m_nChild2) ; + if ( ! m_mTree[m_mTree[nId].m_nChild1].IsLeaf() || ! m_mTree[m_mTree[nId].m_nChild2].IsLeaf()) + // almeno un child non è leaf quindi devo richiamare ricorsivamente questa funzione sui child in questione + d = GetHeightLeaves( nId, vnLeaves, m_mTree[m_mTree[nId].m_nChild1].m_nDepth) ; + } + } + else { + for ( int j = 0 ; j != (int) vnLeaves.size() ; ++ j) { + int i = vnLeaves[j] ; + if ( m_mTree[i].IsLeaf() ) { + continue ; + } + else { + // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child + vnLeaves.erase( remove( vnLeaves.begin(),vnLeaves.end(),i)) ; + -- j ; + vnLeaves.push_back( m_mTree[i].m_nChild1) ; + vnLeaves.push_back( m_mTree[i].m_nChild2) ; + d = max ( d, m_mTree[m_mTree[i].m_nChild1].m_nDepth) ; + } + } + return d ; + } + return d - m_mTree[nId].m_nDepth ; +} + +//---------------------------------------------------------------------------- +int Tree::GetDepth( int nId, int nRef = -2) +{ + int c = 0 ; + while ( m_mTree[nId].m_nParent != nRef ) { + nId = m_mTree[nId].m_nParent ; + ++ c ; + } + return c ; +} + +//---------------------------------------------------------------------------- +bool Tree::GetPolygons( POLYLINEVECTOR& vPolygons) +{ + if ( m_vPolygons.empty()) { + PNTVECTOR vVertices ; + INTVECTOR vNeigh ; + bool bBottomRight , bTopLeft ; + // scorro lungo tutte le celle leaves ( dell'albero bilanciato) e oltre agli angoli della cella aggiungo alla polyline anche i vertici sui lati + for ( int nId : m_vnLeaves) { + //Point3d ptPbr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + //Point3d ptPtl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + vVertices.clear() ; + vNeigh.clear() ; + vVertices.push_back( m_mTree[nId].GetBottomLeft()) ; + GetBottomNeigh( nId, vNeigh) ; + // aggiungo i vertici che sono sul lato bottom, solo se ho più di un vicino bottom + if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1){ + for ( int j : vNeigh ) + vVertices.push_back( m_mTree[j].GetTopRight()) ; + bBottomRight = true ; + } + else + bBottomRight = false ; + vNeigh.clear() ; + GetRightNeigh ( nId, vNeigh) ; + // aggiungo i vertici che sono sul lato right, solo se ho più di un vicino right + if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1){ + for ( int j : vNeigh ) + vVertices.push_back( m_mTree[j].GetBottomLeft()) ; + } + // se non l'ho già aggiunto tramite i vicini bottom aggiungo il punto bottom right + else if ( ! bBottomRight ) { + Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + vVertices.push_back( ptBr) ; + } + vNeigh.clear() ; + vVertices.push_back( m_mTree[nId].GetTopRight()) ; + GetTopNeigh ( nId, vNeigh) ; + reverse( vNeigh.begin(), vNeigh.end()) ; + // aggiungo i vertici che sono sul lato top, solo se ho più di un vicino top + if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) { + for ( int j : vNeigh) + vVertices.push_back( m_mTree[j].GetBottomLeft()) ; + bTopLeft = true ; + } + else + bTopLeft = false ; + vNeigh.clear() ; + GetLeftNeigh ( nId, vNeigh) ; + reverse( vNeigh.begin(), vNeigh.end()) ; + // aggiungo i vertici che sono sul lato left, solo se ho più di un vicino left + if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) { + for ( int j : vNeigh) + vVertices.push_back( m_mTree[j].GetTopRight()) ; + } + // se non l'ho già aggiunto tramite i vicini top aggiungo il punto top left + else if ( ! bTopLeft) { + Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + vVertices.push_back( ptTl) ; + } + vNeigh.clear() ; + vVertices.push_back( m_mTree[nId].GetBottomLeft()) ; + double k = 0 ; + m_vPolygons.emplace_back() ; + for ( int i = 0 ; i < (int) vVertices.size() ; ++i ) { + k = double( i) / double( vVertices.size()) ; + m_vPolygons.back().AddUPoint( i, vVertices[i]) ; + } + } + } + // restituisco i poligoni delle celle del tree nello spazio parametrico + vPolygons = m_vPolygons ; + return true ; +} \ No newline at end of file diff --git a/Tree.h b/Tree.h new file mode 100644 index 0000000..aab0ac1 --- /dev/null +++ b/Tree.h @@ -0,0 +1,92 @@ +//---------------------------------------------------------------------------- +// EgalTech 2023 +//---------------------------------------------------------------------------- +// File : Tree.h Data : 21.04.23 Versione : +// Contenuto : Implementazione della classe Cell di un albero binario Tree. +// +// +// +// Modifiche : 21.04.23 DB Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once + +//--------------------------- Include ---------------------------------------- +#include +#include "tree.h" +#include "SurfBezier.h" + +//---------------------------------------------------------------------------- +class Cell +{ + public : + ~Cell( void) ; + Cell( void) ; + Cell( Point3d ptBL, Point3d ptTR) ; + inline bool IsSame( Cell cOtherCell) ; + void SetBottomLeft( Point3d ptBL) { m_ptPbl = ptBL ; } + void SetTopRight( Point3d ptTR) { m_ptPtr = ptTR ; } + void SetSplitDirVert( bool bVert) { m_bSplitVert = bVert ; } + void SetParent(int nParent) { m_nParent = nParent ; } + Point3d GetBottomLeft( void) { return m_ptPbl ; } + Point3d GetTopRight( void) { return m_ptPtr ; } + bool IsSplitVert( void) { return m_bSplitVert ; } + bool IsLeaf( void) ; + bool IsProcessed( void) const { return m_bProcessed ; } + void Processed( void) { m_bProcessed = true ; } + //bool operator- ( const Cell &other) const { return m_ptPbl.x < other.m_ptPbl.x ; } + //bool operator| ( const Cell &other) const { return m_ptPbl.y < other.m_ptPbl.y ; } + static bool minorX ( const Cell& c1, const Cell& c2) { return c1.m_ptPbl.x < c2.m_ptPbl.x ; } + static bool minorY ( const Cell& c1, const Cell& c2) { return c1.m_ptPbl.y < c2.m_ptPbl.y ; } + + public : + int m_nId ; // Id della cella + int m_nTop ; // cella adiacente al lato top + int m_nBottom ; // cella adiacente al lato bottom + int m_nLeft ; // cella adiacente al lato left + int m_nRight ; // cella adiacente al lato right + int m_nParent ; // cella genitore + int m_nDepth ; // profondità della cella rispetto a root + int m_nChild1 ; // prima cella figlio + int m_nChild2 ; // seconda cella figlio + + private : + Point3d m_ptPbl ; // punto bottom left + Point3d m_ptPtr ; // punto top right + bool m_bProcessed ; // flag che indica se la cella è stata processata + bool m_bSplitVert ; // flag che indica in quale direzione è stata divisa la cella + // double m_dSplit ; // lunghezza normalizzata a cui è stata splittata la cella +} ; + +//---------------------------------------------------------------------------- +class Tree +{ +public : + ~Tree( void) ; + Tree( void) ; + Tree ( const SurfBezier* pSrfBz) ; + void SetSurf( const SurfBezier* pSrfBz) ; + bool BuildTree() ; + bool GetPolygons( POLYLINEVECTOR& vPolygons) ; + +private : + void Split( int nId) ; // funzione di split di una cella dell'albero + void Balance ( INTVECTOR vCheck) ; // creo rami in modo che tutte tutte le foglie abbiano come adiacenti foglie ad una profonditù di +- 1 + int GetHeightLeaves ( int nId, INTVECTOR& vnLeaves, int d = 0) ; // altezza del subtree a partire dal nodo nId + int GetDepth ( int nId, int nRef) ; // livello del nodo nId + void GetTopNeigh( int nId, INTVECTOR& vTopNeighs) ; + void GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) ; + void GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) ; + void GetRightNeigh( int nId, INTVECTOR& vRightNeighs) ; + + +private : + double m_dLinTol ; // errore dell'approssimazione + int m_nRoot ; // cella base + const SurfBezier* m_pSrfBz ; // root + POLYLINEVECTOR m_vPolygons ; // vettore dei poligoni del kd-tree + std::map m_mTree ; // mappa che contiene tutti i nodi e le foglie dell'albero. -2 è puntatore Null e -1 è root + INTVECTOR m_vnLeaves ; // vettore delle foglie +} ; \ No newline at end of file From 8c79bbb2b619ff1a6f85f85311cf2c4217bbccc4 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Wed, 10 May 2023 15:35:42 +0200 Subject: [PATCH 03/44] =?UTF-8?q?EgtGeomKernel=20:=20-=20completata=20l'im?= =?UTF-8?q?plementazione=20della=20tassellazione=20adattiva=20per=20una=20?= =?UTF-8?q?superficie=20di=20bezier=20(=20si=20pu=C3=B2=20migliorare=20il?= =?UTF-8?q?=20costo=20di=20memoria=20e=20computazionale)=20-=20manca=20la?= =?UTF-8?q?=20gestione=20del=20trim=20dello=20spazio=20parametrico.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SurfBezier.cpp | 131 ++++++++++++++-------- Tree.cpp | 292 +++++++++++++++++++++++++++++++++---------------- Tree.h | 6 +- 3 files changed, 288 insertions(+), 141 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 7106029..a5f7245 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -1534,62 +1534,101 @@ SurfBezier::GetAuxSurf( void) const POLYLINEVECTOR vPL ; Tree.GetPolygons( vPL) ; PtrOwner pSrfTm( CreateBasicSurfTriMesh()) ; + StmFromTriangleSoup stmSoup ; + if ( ! stmSoup.Start()) + return nullptr ; - //srfTm.CreateByRegion( vPL) ; // prendo i punti di ogni polyline dell'albero, li triangolo e li porto in 3d for ( PolyLine i : vPL) { - PtrOwner srfTmCell( CreateBasicSurfTriMesh()) ; PNTVECTOR vPnt ; INTVECTOR vTria ; Triangulate Tri ; if ( ! Tri.Make( i, vPnt, vTria)) return false ; - - // inizializzo la superficie - int nVert = int( vPnt.size()) ; - int nTria = int( vTria.size()) / 3 ; - if ( ! srfTmCell->Init( nVert, nTria)) - return false ; - - // porti i vertici dallo spazio parametrico allo spazio 3d e li inserisco nella superficie - for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) { - Point3d pt3d; - GetPointD1D2( vPnt[i].x, vPnt[i].y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d) ; - if ( srfTmCell->AddVertex( pt3d) == SVT_NULL) - //if ( srfTmCell->AddVertex( vPnt[i]) == SVT_NULL ) - return false ; - } - - // recupero i triangoli e li inserisco nella superficie - int vV[3] ; - for ( int i = 0 ; i < nTria ; ++i) { - vV[0] = vTria[3*i] ; - vV[1] = vTria[3*i+1] ; - vV[2] = vTria[3*i+2] ; - if ( srfTmCell->AddTriangle( vV) == SVT_NULL) - return false ; - } - - // sistemo la topologia - if ( ! srfTmCell->AdjustTopology()) - return false ; - //if ( ! pSrfTm->Add( srfTmCell)) - // return false ; - - if ( ! pSrfTm->IsValid() ) { - //pSrfTm.Set( CloneBasicSurfTriMesh(srfTmCell)) ; - pSrfTm.Set( Release(srfTmCell)) ; - } - else { - //if ( ! pSrfTm->Add( *srfTmCell)) - if ( ! pSrfTm->DoSewing( *srfTmCell)) - return false ; - } - - } + // porto i punti in 3d + PNTVECTOR vPnt3d ; + for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) { + Point3d pt3d ; + if ( ! GetPointD1D2( vPnt[i].x, vPnt[i].y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d)) + return false ; + vPnt3d.push_back( pt3d) ; + } + int nTria = int( vTria.size()) / 3 ; + for ( int i = 0 ; i < nTria ; ++i) { + if ( ! stmSoup.AddTriangle( vPnt3d[vTria[3*i]], vPnt3d[vTria[3*i+1]], vPnt3d[vTria[3*i+2]])) + return false ; + } + + + // if ( pSrfTm->GetVertexCount() == 0) { + // // inizializzo la superficie + // int nVert = int( vPnt.size()) ; + // int nTria = int( vTria.size()) / 3 ; + // if ( ! pSrfTm->Init( nVert, nTria)) + // return false ; + + // // porti i vertici dallo spazio parametrico allo spazio 3d e li inserisco nella superficie + // for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) { + // Point3d pt3d; + // GetPointD1D2( vPnt[i].x, vPnt[i].y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d) ; + // if ( pSrfTm->AddVertex( pt3d) == SVT_NULL) + // //if ( srfTmCell->AddVertex( vPnt[i]) == SVT_NULL ) + // return false ; + // } + + // // recupero i triangoli e li inserisco nella superficie + // int vV[3] ; + // for ( int i = 0 ; i < nTria ; ++i) { + // vV[0] = vTria[3*i] ; + // vV[1] = vTria[3*i+1] ; + // vV[2] = vTria[3*i+2] ; + // if ( pSrfTm->AddTriangle( vV) == SVT_NULL) + // return false ; + // } + + // // sistemo la topologia + // if ( ! pSrfTm->AdjustTopology()) + // return false ; + + // //pSrfTm.Set( Release(srfTmCell)) ; + // } + // else { + // // inizializzo la superficie + // int nVert = int( vPnt.size()) ; + // int nTria = int( vTria.size()) / 3 ; + + // // porti i vertici dallo spazio parametrico allo spazio 3d e li inserisco nella superficie + // for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) { + // Point3d pt3d; + // GetPointD1D2( vPnt[i].x, vPnt[i].y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d) ; + // if ( pSrfTm->AddVertex( pt3d) == SVT_NULL) + // return false ; + // } + + // // recupero i triangoli e li inserisco nella superficie + // int vV[3] ; + // int nVertCount = int ( pSrfTm->GetVertexCount()) - 4 ; + // for ( int i = 0 ; i < nTria ; ++i) { + // vV[0] = vTria[3*i] + nVertCount ; + // vV[1] = vTria[3*i+1] + nVertCount ; + // vV[2] = vTria[3*i+2] + nVertCount ; + // if ( pSrfTm->AddTriangle( vV) == SVT_NULL) + // return false ; + // } + // } + } + // if ( ! pSrfTm->AdjustTopology()) + // return false ; + //// la salvo + // m_pSTM = Release( pSrfTm) ; + + + // la salvo - m_pSTM = Release(pSrfTm) ; + if ( ! stmSoup.End()) + return nullptr ; + m_pSTM = GetBasicSurfTriMesh( stmSoup.GetSurf()) ; } return m_pSTM ; } diff --git a/Tree.cpp b/Tree.cpp index 3d6f8e3..5304f3f 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -1,4 +1,4 @@ -//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- // EgalTech 2023 //---------------------------------------------------------------------------- // File : Tree.cpp Data : 21.04.23 Versione : @@ -17,6 +17,9 @@ #include "Tree.h" #include "SurfBezier.h" #include "GeoConst.h" +#include "CurveLine.h" +#include "/EgtDev/Include/EGkPolyLine.h" +#include "/EgtDev/Include/EGkDistPointCurve.h" using namespace std ; @@ -68,7 +71,7 @@ Cell::IsLeaf ( void) //---------------------------------------------------------------------------- Tree::Tree( void) - : m_dLinTol(LIN_TOL_FINE), m_pSrfBz(nullptr), m_nRoot( -1) + : m_dLinTol(LIN_TOL_FINE), m_pSrfBz(nullptr), m_nRoot( -1), m_bTrimmed( false) { Point3d ptBl( 0, 0), ptTr ( 1, 1) ; Cell cRoot( ptBl, ptTr) ; @@ -83,6 +86,7 @@ Tree::Tree( const SurfBezier* pSrfBz) int nDegU, nDegV, nSpanU, nSpanV ; bool bIsRat, bTrimmed ; m_pSrfBz->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bIsRat, bTrimmed) ; + m_bTrimmed = bTrimmed ; Point3d ptTop( nSpanU, nSpanV) ; Cell cRoot( ORIG, ptTop) ; m_mTree.insert( pair< int, Cell>( m_nRoot, cRoot)) ; @@ -101,6 +105,7 @@ void Tree::SetSurf( const SurfBezier* pSrfBz) int nDegU, nDegV, nSpanU, nSpanV ; bool bIsRat, bTrimmed ; m_pSrfBz->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bIsRat, bTrimmed) ; + m_bTrimmed = bTrimmed ; Point3d ptTop( nSpanU, nSpanV) ; Cell cRoot( ORIG, ptTop) ; m_mTree.insert( pair< int, Cell>( -1, cRoot)) ; @@ -122,7 +127,7 @@ Tree::Split( int nId) m_mTree.insert( pair( nNodes, cChild2)) ; if ( ! m_mTree[nId].IsSplitVert()) { - // la cella figlio 1 è quella sopra + // la cella figlio 1 è quella sopra Point3d ptBL( m_mTree[nId].GetBottomLeft().x, ( m_mTree[nId].GetBottomLeft().y + m_mTree[nId].GetTopRight().y) / 2) ; m_mTree[m_mTree[nId].m_nChild1].SetBottomLeft( ptBL) ; m_mTree[m_mTree[nId].m_nChild1].SetTopRight( m_mTree[nId].GetTopRight()) ; @@ -139,7 +144,7 @@ Tree::Split( int nId) m_mTree[m_mTree[nId].m_nChild2].m_nRight = m_mTree[nId].m_nRight ; } else { - // la cella figlio 1 è quella di sinistra + // la cella figlio 1 è quella di sinistra Point3d ptTR( ( m_mTree[nId].GetBottomLeft().x + m_mTree[nId].GetTopRight().x) / 2, m_mTree[nId].GetTopRight().y) ; m_mTree[m_mTree[nId].m_nChild1].SetBottomLeft( m_mTree[nId].GetBottomLeft()) ; m_mTree[m_mTree[nId].m_nChild1].SetTopRight( ptTR) ; @@ -163,7 +168,7 @@ Tree::Split( int nId) ////---------------------------------------------------------------------------- //bool Tree::BuildTree(void) //{ -// // di default SplitVert è true ! +// // di default SplitVert è true ! // int ToSplit = -1; // m_mTree[ToSplit].SetSplitDirVert( true) ; // Split( ToSplit) ; @@ -207,24 +212,40 @@ Tree::Split( int nId) // return true ; //} +////---------------------------------------------------------------------------- +//bool Tree::BuildTree( void) +//{ +// int ToSplit = -1 ; +// m_mTree[ToSplit].SetSplitDirVert( true) ; +// Split( ToSplit) ; +// // celle 2 e 3 +// ToSplit = m_mTree[-1].m_nChild1 ; +// m_mTree[ToSplit].SetSplitDirVert( false) ; +// Split( ToSplit) ; +// +// return true ; +//} //---------------------------------------------------------------------------- -bool Tree::BuildTree( void) +bool Tree::BuildTree( double dLinTol, double dSideMax) { // trovo dove splittare la cella e creo i puntatori ai figli // comincio a suddividere la superficie usando un kd-tree - // approssimo con una bilineare e se l'errore di approssimazione è troppo grande cerco una direzione + // approssimo con una bilineare e se l'errore di approssimazione è troppo grande cerco una direzione // in cui dividere la superficie double dErr ; // errore calcolato double dDist; // distanza tra punti selezionati sulla isoparametrica - double dSide ; // lunghezza del lato della eventuale cella figlio - double dSplit = 0.5 ; // effettuo sempre split a metà - //double dSidemin = 0.05 ; // lunghezza minima del lato di una cella - double dSidemin = 0.1 ; // lunghezza minima del lato di una cella + double dSideMinVal, dSideMaxVal ; // lunghezza del lato della eventuale cella figlio + double dSplit = 0.5 ; // effettuo sempre split a metà + double dSideMin = 0.05 ; // lunghezza minima del lato di una cella + //double dSidemin = 0.1 ; // lunghezza minima del lato di una cella + //m_dLinTol = dLinTol ; + m_dLinTol = 0.2 ; int nSteps = 51 ; // numero di Step mentre scorro lungo un'isoparametrica - double dU, dV , dIter, dIterLoc, dULoc, dVLoc ; + double dU, dV , dULoc, dVLoc ; + //double dIter, dIterLoc ; bool bVert ; Point3d ptBz, ptBl ; // cerco lo scostamento massimo tra la sup di Bezier e la sua approssimazione bilineare @@ -234,59 +255,123 @@ bool Tree::BuildTree( void) int c = 1 ; while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { dErr = 0 ; - // verifico se l'approsimazione bilineare è ancora troppo distante dalla superficie reale - // calcolo la bilineare per gli estremi della cella - SurfBezier pSrfBl ; - pSrfBl.Init(1, 1, 1, 1, false) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; - pSrfBl.SetControlPoint( 0, ptBz) ; // P00 - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; - pSrfBl.SetControlPoint( 1, ptBz) ; // P01 - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; - pSrfBl.SetControlPoint( 2, ptBz) ; // P10 - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; - pSrfBl.SetControlPoint( 3, ptBz) ; // P11 - // scorro lungo le isoparametriche a questi valori di U e V per trovare dov'è il punto di maggior discostamento - dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; - dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; - dULoc = dU - m_mTree[nCToSplit].GetBottomLeft().x / ( m_mTree[nCToSplit].GetTopRight().x - m_mTree[nCToSplit].GetBottomLeft().x) ; - dVLoc = dV - m_mTree[nCToSplit].GetBottomLeft().y / ( m_mTree[nCToSplit].GetTopRight().y - m_mTree[nCToSplit].GetBottomLeft().y) ; - double dErrUmax, dErrVmax ; - for ( int i = 0 ; i < nSteps ; ++ i){ - dIter = double ( i) / double ( nSteps - 1) ; - dIterLoc = ( 1 - dIter) * m_mTree[nCToSplit].GetBottomLeft().y + dIter * m_mTree[nCToSplit].GetTopRight().y ; - if ( ! m_pSrfBz->GetPointD1D2( dU, dIterLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) || - ! pSrfBl.GetPointD1D2( dU, dIter, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBl)) /// dU è riferito alla Bz totale, quant'è sulla Bl?? + // calcolo l'errore di approssimazione + + //// calcolo l'errore di approssimazione confrontando con la bilineare corrispondente + //SurfBezier pSrfBl ; + //pSrfBl.Init(1, 1, 1, 1, false) ; + //m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; + //pSrfBl.SetControlPoint( 0, ptBz) ; // P00 + //m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; + //pSrfBl.SetControlPoint( 1, ptBz) ; // P10 + //m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; + //pSrfBl.SetControlPoint( 2, ptBz) ; // P01 + //m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; + //pSrfBl.SetControlPoint( 3, ptBz) ; // P11 + //// scorro lungo le isoparametriche a questi valori di U e V per trovare dov'è il punto di maggior discostamento + //dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; + //dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; + //dULoc = ( dU - m_mTree[nCToSplit].GetBottomLeft().x) / ( m_mTree[nCToSplit].GetTopRight().x - m_mTree[nCToSplit].GetBottomLeft().x) ; + //dVLoc = ( dV - m_mTree[nCToSplit].GetBottomLeft().y) / ( m_mTree[nCToSplit].GetTopRight().y - m_mTree[nCToSplit].GetBottomLeft().y) ; + //double dErrUmax = 0, dErrVmax = 0 ; + //for ( int i = 0 ; i < nSteps ; ++ i){ + // dIter = double ( i) / double ( nSteps - 1) ; + // dIterLoc = ( 1 - dIter) * m_mTree[nCToSplit].GetBottomLeft().y + dIter * m_mTree[nCToSplit].GetTopRight().y ; + // if ( ! m_pSrfBz->GetPointD1D2( dU, dIterLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) || + // ! pSrfBl.GetPointD1D2( dULoc, dIter, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBl)) + // return false ; + // dDist = Dist( ptBz, ptBl) ; + // dErrVmax = max ( dErrVmax, dDist) ; + // if ( dDist > dErr) { + // dErr = dDist ; + // //bVert = true ; + // } + // dIterLoc = ( 1 - dIter) * m_mTree[nCToSplit].GetBottomLeft().x + dIter * m_mTree[nCToSplit].GetTopRight().x ; + // if ( ! m_pSrfBz->GetPointD1D2( dIterLoc, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) || + // ! pSrfBl.GetPointD1D2( dIter, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBl)) + // return false ; + // dDist = Dist( ptBz, ptBl) ; + // dErrUmax = max ( dErrUmax, dDist) ; + // if ( dDist > dErr) { + // dErr = dDist ; + // //bVert = false ; + // } + //} + + Point3d ptP00, ptP10, ptP11, ptP01 ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11) ; + CurveLine cl0010, cl0001, cl1011, cl0111 ; + // U=0 + cl0010.Set( ptP00, ptP10) ; + //// V=0 + //cl0001.Set( ptP00, ptP01) ; + // U=1 + cl0111.Set( ptP01, ptP11) ; + //// V=1 + //cl0111.Set( ptP01, ptP11) ; + Point3d pt0010, pt0111, ptBz0, ptBz1, ptBzV ; + int nFlag ; + CurveLine clV ; + for ( int u = 0 ; u < nSteps ; ++ u){ + dU = double ( u) / double ( nSteps - 1) ; + dULoc = ( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x ; + if ( ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz0) || + ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz1)) return false ; - dDist = Dist( ptBz, ptBl) ; - if ( dDist > dErr) { - dErr = dDist ; - bVert = true ; - dErrVmax = dErr ; - } - dIterLoc = ( 1 - dIter) * m_mTree[nCToSplit].GetBottomLeft().x + dIter * m_mTree[nCToSplit].GetTopRight().x ; - if ( ! m_pSrfBz->GetPointD1D2( dIterLoc, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) || - ! pSrfBl.GetPointD1D2( dIter, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBl)) /// dV è riferito alla Bz totale, quant'è sulla Bl?? - return false ; - dDist = Dist( ptBz, ptBl) ; - if ( dDist > dErr) { - dErr = dDist ; - bVert = false ; - dErrUmax = dErr ; + DistPointCurve dpc0010( ptBz0, cl0010) ; + DistPointCurve dpc0111( ptBz1, cl0111) ; + dpc0010.GetMinDistPoint( 0, pt0010, nFlag) ; + dpc0111.GetMinDistPoint( 0, pt0111, nFlag) ; + clV.Set( pt0010, pt0111) ; + for ( int v = 0 ; v < nSteps ; ++ v){ + dV = double ( v) / double ( nSteps - 1) ; + dVLoc = ( 1 - dV) * m_mTree[nCToSplit].GetBottomLeft().y + dV * m_mTree[nCToSplit].GetTopRight().y ; + if ( ! m_pSrfBz->GetPointD1D2( dULoc, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBzV)) + return false ; + DistPointCurve dpc( ptBzV, clV) ; + dpc.GetDist( dDist) ; + if ( dDist > dErr) + dErr = dDist ; } } + + // calcolo in quale direzione ho più curvatura + // devo trovare i punti sui lati corrispondenti a dUmax e dVmax, unendo queste coppie trovo le due direzioni di possibile split + // punti medi del lato successivo in senso antiorario rispetto al relativo vertice della patch + dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; + dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; + dULoc = dVLoc = 0.5 ; + Point3d ptPSrf ; //ptP00, ptP10, ptP11, ptP01; + m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01) ; + Point3d ptP00P11 = ( 1 - dULoc) * ptP00 + dULoc * ptP11 ; + Point3d ptP10P01 = ( 1 - dVLoc) * ptP10 + dVLoc * ptP01 ; + // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza + // effettuo lo split e configuro le celle figlie + if ( Dist(ptP00P11, ptPSrf) > Dist(ptP10P01, ptPSrf)) + // lungo la direzione U ho una curvatura maggiore + bVert = false ; + else + // lungo la direzione V ho una curvatura maggiore + bVert = true ; + // verifico che la cella sia da splittare e che eventualmente sia abbastanza grande da poterlo fare if ( bVert) - dSide = m_mTree[nCToSplit].GetTopRight().x - m_mTree[nCToSplit].GetBottomLeft().x ; + dSideMinVal = min( Dist( ptP00, ptP10), Dist( ptP01, ptP11)) ; else - dSide = m_mTree[nCToSplit].GetTopRight().y - m_mTree[nCToSplit].GetBottomLeft().y ; - if ( dErr > m_dLinTol && dSide >= dSidemin) { + dSideMinVal = min( Dist( ptP00, ptP01), Dist( ptP10, ptP11)) ; + dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; + if ( ( dErr > m_dLinTol && dSideMinVal >= dSideMin) || dSideMaxVal > dSideMax) { m_mTree[nCToSplit].SetSplitDirVert( bVert) ; // effettuo lo split Split( nCToSplit) ; - // qui faccio i check per capire quali celle devo inserire in vBalanceCheck /////////////////////////////////////////////////////// - // procedo con lo split del Child1 nCToSplit = m_mTree[nCToSplit].m_nChild1 ; } @@ -294,7 +379,7 @@ bool Tree::BuildTree( void) // sono arrivato ad una cella Leaf, quindi salvo la cella m_vnLeaves.push_back( nCToSplit) ; m_mTree[nCToSplit].Processed() ; - // risalgo i parent finché non trovo il primo Child2 da processare + // risalgo i parent finché non trovo il primo Child2 da processare nCToSplit = m_mTree[nCToSplit].m_nParent ; if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) m_mTree[nCToSplit].Processed() ; @@ -318,7 +403,8 @@ bool Tree::BuildTree( void) void Tree::Balance( INTVECTOR vCheck) { for ( int i : vCheck ) { - + // non ancora implementato + // rendolo il tree balanced : ogni foglia deve avere una profondità di +- 1 rispetto ai suoi vicini. } } @@ -332,13 +418,13 @@ void Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) vTopNeighs.push_back( m_mTree[nId].m_nTop) ; else { if ( m_mTree[m_mTree[nId].m_nTop].IsSplitVert()) { - // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima + // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima if ( m_mTree[m_mTree[nId].m_nTop].GetTopRight().x - m_mTree[m_mTree[nId].m_nTop].GetBottomLeft().x <= m_mTree[nId].GetTopRight().x - m_mTree[nId].GetBottomLeft().x) { vTopNeighs.push_back( m_mTree[m_mTree[nId].m_nTop].m_nChild1) ; vTopNeighs.push_back( m_mTree[m_mTree[nId].m_nTop].m_nChild2) ; } - // altrimenti solo uno dei figli lo sarà + // altrimenti solo uno dei figli lo sarà else{ if ( m_mTree[m_mTree[m_mTree[nId].m_nTop].m_nChild1].GetTopRight().x <= m_mTree[nId].GetBottomLeft().x || m_mTree[m_mTree[m_mTree[nId].m_nTop].m_nChild1].GetBottomLeft().x >= m_mTree[nId].GetTopRight().x ) @@ -357,7 +443,7 @@ void Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) bAllLeaves = false ; } if ( ! bAllLeaves ) - // almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child + // almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child GetTopNeigh( nId, vTopNeighs) ; } else { @@ -366,17 +452,17 @@ void Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) if ( m_mTree[i].IsLeaf()) continue; else { - // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child + // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child vTopNeighs.erase( remove( vTopNeighs.begin(),vTopNeighs.end(),i)) ; -- j ; if ( m_mTree[i].IsSplitVert() ) { - // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima + // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima if ( m_mTree[i].GetTopRight().x - m_mTree[i].GetBottomLeft().x <= m_mTree[nId].GetTopRight().x - m_mTree[nId].GetBottomLeft().x) { vTopNeighs.push_back( m_mTree[i].m_nChild1) ; vTopNeighs.push_back( m_mTree[i].m_nChild2) ; } - // altrimenti solo uno dei figli lo sarà + // altrimenti solo uno dei figli lo sarà else { if ( m_mTree[m_mTree[i].m_nChild1].GetTopRight().x <= m_mTree[nId].GetBottomLeft().x || m_mTree[m_mTree[i].m_nChild1].GetBottomLeft().x >= m_mTree[nId].GetTopRight().x ) @@ -410,13 +496,13 @@ void Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) vBottomNeighs.push_back( m_mTree[nId].m_nBottom) ; else { if ( m_mTree[m_mTree[nId].m_nBottom].IsSplitVert()) { - // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima + // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima if ( m_mTree[m_mTree[nId].m_nBottom].GetTopRight().x - m_mTree[m_mTree[nId].m_nBottom].GetBottomLeft().x <= m_mTree[nId].GetTopRight().x - m_mTree[nId].GetBottomLeft().x) { vBottomNeighs.push_back( m_mTree[m_mTree[nId].m_nBottom].m_nChild1) ; vBottomNeighs.push_back( m_mTree[m_mTree[nId].m_nBottom].m_nChild2) ; } - // altrimenti solo uno dei figli lo sarà + // altrimenti solo uno dei figli lo sarà else{ if ( m_mTree[m_mTree[m_mTree[nId].m_nBottom].m_nChild1].GetTopRight().x <= m_mTree[nId].GetBottomLeft().x || m_mTree[m_mTree[m_mTree[nId].m_nBottom].m_nChild1].GetBottomLeft().x >= m_mTree[nId].GetTopRight().x ) @@ -435,7 +521,7 @@ void Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) bAllLeaves = false ; } if ( ! bAllLeaves ) - // almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child + // almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child GetBottomNeigh( nId, vBottomNeighs) ; } else { @@ -444,17 +530,17 @@ void Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) if ( m_mTree[i].IsLeaf()) continue; else { - // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child + // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child vBottomNeighs.erase( remove( vBottomNeighs.begin(),vBottomNeighs.end(),i)) ; -- j ; if ( m_mTree[i].IsSplitVert()) { - // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima + // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima if ( m_mTree[i].GetTopRight().x - m_mTree[i].GetBottomLeft().x <= m_mTree[nId].GetTopRight().x - m_mTree[nId].GetBottomLeft().x) { vBottomNeighs.push_back( m_mTree[i].m_nChild1) ; vBottomNeighs.push_back( m_mTree[i].m_nChild2) ; } - // altrimenti solo uno dei figli lo sarà + // altrimenti solo uno dei figli lo sarà else { if ( m_mTree[m_mTree[i].m_nChild1].GetTopRight().x <= m_mTree[nId].GetBottomLeft().x || m_mTree[m_mTree[i].m_nChild1].GetBottomLeft().x >= m_mTree[nId].GetTopRight().x ) @@ -489,13 +575,13 @@ void Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) vLeftNeighs.push_back( m_mTree[nId].m_nLeft) ; else { if ( ! m_mTree[m_mTree[nId].m_nLeft].IsSplitVert()) { - // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima + // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima if ( m_mTree[m_mTree[nId].m_nLeft].GetTopRight().y - m_mTree[m_mTree[nId].m_nLeft].GetBottomLeft().y <= m_mTree[nId].GetTopRight().y - m_mTree[nId].GetBottomLeft().y) { vLeftNeighs.push_back( m_mTree[m_mTree[nId].m_nLeft].m_nChild1) ; vLeftNeighs.push_back( m_mTree[m_mTree[nId].m_nLeft].m_nChild2) ; } - // altrimenti solo uno dei figli lo sarà + // altrimenti solo uno dei figli lo sarà else{ if ( m_mTree[m_mTree[m_mTree[nId].m_nLeft].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || m_mTree[m_mTree[m_mTree[nId].m_nLeft].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y ) @@ -514,7 +600,7 @@ void Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) bAllLeaves = false ; } if ( ! bAllLeaves ) - // almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child + // almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child GetLeftNeigh( nId, vLeftNeighs) ; } else { @@ -523,17 +609,17 @@ void Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) if ( m_mTree[i].IsLeaf()) continue; else { - // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child + // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child vLeftNeighs.erase( remove( vLeftNeighs.begin(),vLeftNeighs.end(),i)) ; -- j ; if ( ! m_mTree[i].IsSplitVert()) { - // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima + // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima if ( m_mTree[i].GetTopRight().y - m_mTree[i].GetBottomLeft().y <= m_mTree[nId].GetTopRight().y - m_mTree[nId].GetBottomLeft().y) { vLeftNeighs.push_back( m_mTree[i].m_nChild1) ; vLeftNeighs.push_back( m_mTree[i].m_nChild2) ; } - // altrimenti solo uno dei figli lo sarà + // altrimenti solo uno dei figli lo sarà else { if ( m_mTree[m_mTree[i].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || m_mTree[m_mTree[i].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y ) @@ -567,13 +653,13 @@ void Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) vRightNeighs.push_back( m_mTree[nId].m_nRight) ; else { if ( ! m_mTree[m_mTree[nId].m_nRight].IsSplitVert()) { - // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima + // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima if ( m_mTree[m_mTree[nId].m_nRight].GetTopRight().y - m_mTree[m_mTree[nId].m_nRight].GetBottomLeft().y <= m_mTree[nId].GetTopRight().y - m_mTree[nId].GetBottomLeft().y) { vRightNeighs.push_back( m_mTree[m_mTree[nId].m_nRight].m_nChild1) ; vRightNeighs.push_back( m_mTree[m_mTree[nId].m_nRight].m_nChild2) ; } - // altrimenti solo uno dei figli lo sarà + // altrimenti solo uno dei figli lo sarà else{ if ( m_mTree[m_mTree[m_mTree[nId].m_nRight].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || m_mTree[m_mTree[m_mTree[nId].m_nRight].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y ) @@ -592,7 +678,7 @@ void Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) bAllLeaves = false ; } if ( ! bAllLeaves ) - // almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child + // almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child GetRightNeigh( nId, vRightNeighs) ; } else { @@ -601,17 +687,17 @@ void Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) if ( m_mTree[i].IsLeaf()) continue; else { - // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child + // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child vRightNeighs.erase( remove( vRightNeighs.begin(),vRightNeighs.end(), i)) ; -- j ; if ( ! m_mTree[i].IsSplitVert()) { - // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima + // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima if ( m_mTree[i].GetTopRight().y - m_mTree[i].GetBottomLeft().y <= m_mTree[nId].GetTopRight().y - m_mTree[nId].GetBottomLeft().y) { vRightNeighs.push_back( m_mTree[i].m_nChild1) ; vRightNeighs.push_back( m_mTree[i].m_nChild2) ; } - // altrimenti solo uno dei figli lo sarà + // altrimenti solo uno dei figli lo sarà else { if ( m_mTree[m_mTree[i].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || m_mTree[m_mTree[i].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y ) @@ -645,7 +731,7 @@ int Tree::GetHeightLeaves( int nId, INTVECTOR& vnLeaves, int d) vnLeaves.push_back( m_mTree[nId].m_nChild1) ; vnLeaves.push_back( m_mTree[nId].m_nChild2) ; if ( ! m_mTree[m_mTree[nId].m_nChild1].IsLeaf() || ! m_mTree[m_mTree[nId].m_nChild2].IsLeaf()) - // almeno un child non è leaf quindi devo richiamare ricorsivamente questa funzione sui child in questione + // almeno un child non è leaf quindi devo richiamare ricorsivamente questa funzione sui child in questione d = GetHeightLeaves( nId, vnLeaves, m_mTree[m_mTree[nId].m_nChild1].m_nDepth) ; } } @@ -656,7 +742,7 @@ int Tree::GetHeightLeaves( int nId, INTVECTOR& vnLeaves, int d) continue ; } else { - // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child + // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child vnLeaves.erase( remove( vnLeaves.begin(),vnLeaves.end(),i)) ; -- j ; vnLeaves.push_back( m_mTree[i].m_nChild1) ; @@ -689,13 +775,11 @@ bool Tree::GetPolygons( POLYLINEVECTOR& vPolygons) bool bBottomRight , bTopLeft ; // scorro lungo tutte le celle leaves ( dell'albero bilanciato) e oltre agli angoli della cella aggiungo alla polyline anche i vertici sui lati for ( int nId : m_vnLeaves) { - //Point3d ptPbr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; - //Point3d ptPtl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; vVertices.clear() ; vNeigh.clear() ; vVertices.push_back( m_mTree[nId].GetBottomLeft()) ; GetBottomNeigh( nId, vNeigh) ; - // aggiungo i vertici che sono sul lato bottom, solo se ho più di un vicino bottom + // aggiungo i vertici che sono sul lato bottom, solo se ho più di un vicino bottom if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1){ for ( int j : vNeigh ) vVertices.push_back( m_mTree[j].GetTopRight()) ; @@ -705,12 +789,12 @@ bool Tree::GetPolygons( POLYLINEVECTOR& vPolygons) bBottomRight = false ; vNeigh.clear() ; GetRightNeigh ( nId, vNeigh) ; - // aggiungo i vertici che sono sul lato right, solo se ho più di un vicino right + // aggiungo i vertici che sono sul lato right, solo se ho più di un vicino right if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1){ for ( int j : vNeigh ) vVertices.push_back( m_mTree[j].GetBottomLeft()) ; } - // se non l'ho già aggiunto tramite i vicini bottom aggiungo il punto bottom right + // se non l'ho già aggiunto tramite i vicini bottom aggiungo il punto bottom right else if ( ! bBottomRight ) { Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; vVertices.push_back( ptBr) ; @@ -719,7 +803,7 @@ bool Tree::GetPolygons( POLYLINEVECTOR& vPolygons) vVertices.push_back( m_mTree[nId].GetTopRight()) ; GetTopNeigh ( nId, vNeigh) ; reverse( vNeigh.begin(), vNeigh.end()) ; - // aggiungo i vertici che sono sul lato top, solo se ho più di un vicino top + // aggiungo i vertici che sono sul lato top, solo se ho più di un vicino top if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) { for ( int j : vNeigh) vVertices.push_back( m_mTree[j].GetBottomLeft()) ; @@ -730,26 +814,48 @@ bool Tree::GetPolygons( POLYLINEVECTOR& vPolygons) vNeigh.clear() ; GetLeftNeigh ( nId, vNeigh) ; reverse( vNeigh.begin(), vNeigh.end()) ; - // aggiungo i vertici che sono sul lato left, solo se ho più di un vicino left + // aggiungo i vertici che sono sul lato left, solo se ho più di un vicino left if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) { for ( int j : vNeigh) vVertices.push_back( m_mTree[j].GetTopRight()) ; } - // se non l'ho già aggiunto tramite i vicini top aggiungo il punto top left + // se non l'ho già aggiunto tramite i vicini top aggiungo il punto top left else if ( ! bTopLeft) { Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; vVertices.push_back( ptTl) ; } vNeigh.clear() ; vVertices.push_back( m_mTree[nId].GetBottomLeft()) ; - double k = 0 ; + // se hop una cella con vicino dello stesso grado controllo la curvatura nella cella e + // se necessario cambio l'ordine dei vertici per scegliere la diagonale di split migliore + if ( vVertices.size() == 5) { + Point3d ptPSrf, ptP00, ptP10, ptP11, ptP01; + double dU, dV ; + dU = ( m_mTree[nId].GetBottomLeft().x + m_mTree[nId].GetTopRight().x) / 2 ; + dV = ( m_mTree[nId].GetBottomLeft().y + m_mTree[nId].GetTopRight().y) / 2 ; + m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + m_pSrfBz->GetPointD1D2( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00) ; + m_pSrfBz->GetPointD1D2( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10) ; + m_pSrfBz->GetPointD1D2( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11) ; + m_pSrfBz->GetPointD1D2( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01) ; + Point3d ptP00P11 = ( ptP00 + ptP11) / 2 ; + Point3d ptP10P01 = ( ptP10 + ptP01) / 2 ; + // ho la curvatura maggiore sulla diagonale tra P10 e P01, ruoto l'ordine dei vertici, in modo che triangulate prenda la diagonale giusta + if ( Dist(ptP00P11, ptPSrf) > Dist(ptP10P01, ptPSrf)) { + rotate(vVertices.begin(), vVertices.begin() + 1,vVertices.end()) ; + vVertices.back() = vVertices[0] ; + } + } + + //double k = 0 ; m_vPolygons.emplace_back() ; for ( int i = 0 ; i < (int) vVertices.size() ; ++i ) { - k = double( i) / double( vVertices.size()) ; + //k = double( i) / double( vVertices.size()) ; m_vPolygons.back().AddUPoint( i, vVertices[i]) ; } } } + // restituisco i poligoni delle celle del tree nello spazio parametrico vPolygons = m_vPolygons ; return true ; diff --git a/Tree.h b/Tree.h index aab0ac1..4df9a50 100644 --- a/Tree.h +++ b/Tree.h @@ -17,6 +17,7 @@ #include #include "tree.h" #include "SurfBezier.h" +#include "GeoConst.h" //---------------------------------------------------------------------------- class Cell @@ -68,7 +69,7 @@ public : Tree( void) ; Tree ( const SurfBezier* pSrfBz) ; void SetSurf( const SurfBezier* pSrfBz) ; - bool BuildTree() ; + bool BuildTree( double dLinTol = LIN_TOL_STD, double dSideMax = INFINITO) ; // dSidemax è il massimo per la dimensione maggiore di un triangolo della trimesh bool GetPolygons( POLYLINEVECTOR& vPolygons) ; private : @@ -86,7 +87,8 @@ private : double m_dLinTol ; // errore dell'approssimazione int m_nRoot ; // cella base const SurfBezier* m_pSrfBz ; // root + bool m_bTrimmed ; // superficie trimmata POLYLINEVECTOR m_vPolygons ; // vettore dei poligoni del kd-tree std::map m_mTree ; // mappa che contiene tutti i nodi e le foglie dell'albero. -2 è puntatore Null e -1 è root - INTVECTOR m_vnLeaves ; // vettore delle foglie + INTVECTOR m_vnLeaves ; // vettore delle foglie } ; \ No newline at end of file From 268983804e36af1605cd2aff27c45b5249e7061f Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Wed, 17 May 2023 08:46:33 +0200 Subject: [PATCH 04/44] EgtGeomKernel : - gestite le superfici bilineari singole e multipatch - gestite le superfici chiuse o su un parametro o sull'altro - migliorate le prestazioni. Da aggiungere : - split preliminare delle patches - la gestione delle sup. trimmate --- SurfBezier.cpp | 270 ++++++++---------- SurfBezier.h | 1 + Tree.cpp | 730 ++++++++++++++++++++++++++++++------------------- Tree.h | 46 ++-- 4 files changed, 583 insertions(+), 464 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index a5f7245..054b366 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -148,6 +148,13 @@ SurfBezier::SetTrimRegion( const ISurfFlatRegion& sfrTrimReg) return true ; } +//---------------------------------------------------------------------------- +bool +SurfBezier::GetTrimRegion( ISurfFlatRegion& sfrTrimReg) +{ + return true ; +} + //---------------------------------------------------------------------------- bool SurfBezier::GetInfo( int& nDegU, int& nDegV, int& nSpanU, int& nSpanV, bool& bIsRat, bool& bTrimmed) const @@ -1464,172 +1471,111 @@ SurfBezier::GetAuxSurf( void) const // se già calcolata, la restituisco if ( m_pSTM != nullptr) return m_pSTM ; - // definisco il numero degli step in U e in V - double dMaxLenU = 0 ; - for ( int j = 0 ; j <= m_nDegV * m_nSpanV ; ++ j) - dMaxLenU = max( dMaxLenU, GetCurveOnUApproxLen( double( j) / m_nDegV)) ; - int nStepU = GetSteps( m_nDegU, m_nSpanU, dMaxLenU, 2) ; - double dMaxLenV = 0 ; - for ( int i = 0 ; i <= m_nDegU * m_nSpanU ; ++ i) - dMaxLenV = max( dMaxLenV, GetCurveOnVApproxLen( double( i) / m_nDegU)) ; - int nStepV = GetSteps( m_nDegV, m_nSpanV, dMaxLenV, 2) ; - if ( m_nDegU == 1 && m_nDegV == 1) { + //// definisco il numero degli step in U e in V + // double dMaxLenU = 0 ; + // for ( int j = 0 ; j <= m_nDegV * m_nSpanV ; ++ j) + // dMaxLenU = max( dMaxLenU, GetCurveOnUApproxLen( double( j) / m_nDegV)) ; + // int nStepU = GetSteps( m_nDegU, m_nSpanU, dMaxLenU, 2) ; + // double dMaxLenV = 0 ; + // for ( int i = 0 ; i <= m_nDegU * m_nSpanU ; ++ i) + // dMaxLenV = max( dMaxLenV, GetCurveOnVApproxLen( double( i) / m_nDegU)) ; + // int nStepV = GetSteps( m_nDegV, m_nSpanV, dMaxLenV, 2) ; + // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // if ( m_nDegU == 1 && m_nDegV == 1) { + // // costruttore della superficie + // StmFromTriangleSoup stmSoup ; + // if ( ! stmSoup.Start()) + // return nullptr ; + // // prima curva isoparametrica (potrebbe essere un solo punto) + // PolyLine PL1 ; + // GetCurveOnU( 0, nStepU, PL1) ; + // bool bSingle1 = ( PL1.GetPointNbr() == 1) ; + // // ciclo sulle isoparametriche + // for ( int i = 1 ; i <= nStepV ; ++ i) { + // // seconda curva isoparametrica (con tanti punti quanti la prima, oppure uno solo) + // double dV = double( i) * m_nSpanV / nStepV ; + // PolyLine PL2 ; + // GetCurveOnU( dV, nStepU, PL2) ; + // bool bSingle2 = ( PL2.GetPointNbr() == 1) ; + // // inserisco i triangoli della striscia nel costruttore della TriMesh + // Point3d ptP1c, ptP2c ; + // Point3d ptP1n, ptP2n ; + // bool bNext = PL1.GetFirstPoint( ptP1c) && PL2.GetFirstPoint( ptP2c) ; + // if ( bNext) { + // if ( bSingle1 && bSingle2) + // bNext = false ; + // if ( bSingle1) + // ptP1n = ptP1c ; + // else + // bNext = bNext && PL1.GetNextPoint( ptP1n) ; + // if ( bSingle2) + // ptP2n = ptP2c ; + // else + // bNext = bNext && PL2.GetNextPoint( ptP2n) ; + // } + // while ( bNext) { + // // eventuale primo triangolo (con base sui correnti e vertice su P2 successivo) + // if ( ! AreSamePointApprox( ptP1c, ptP2c)) + // stmSoup.AddTriangle( ptP2c, ptP1c, ptP2n) ; + // // eventuale secondo triangolo (con vertice su P1 corrente e base sui successivi) + // if ( ! AreSamePointApprox( ptP1n, ptP2n)) + // stmSoup.AddTriangle( ptP1c, ptP1n, ptP2n) ; + // // passo alla successiva coppia + // ptP1c = ptP1n ; + // ptP2c = ptP2n ; + // bNext = ( bSingle1 || PL1.GetNextPoint( ptP1n)) && ( bSingle2 || PL2.GetNextPoint( ptP2n)) ; + // } + // // salvo isoparametrica PL2 in PL1 + // PL1.GetUPointList().swap( PL2.GetUPointList()) ; + // bSingle1 = bSingle2 ; + // } + // // la completo + // if ( ! stmSoup.End()) + // return nullptr ; + // // la salvo + // m_pSTM = GetBasicSurfTriMesh( stmSoup.GetSurf()) ; + // } + // else { + + // costruttore della superficie - StmFromTriangleSoup stmSoup ; - if ( ! stmSoup.Start()) + Tree Tree( this) ; + Tree.BuildTree() ; + POLYLINEVECTOR vPL ; + Tree.GetPolygons( vPL) ; + PtrOwner pSrfTm( CreateBasicSurfTriMesh()) ; + StmFromTriangleSoup stmSoup ; + if ( ! stmSoup.Start()) + return nullptr ; + + // prendo i punti di ogni polyline dell'albero, li triangolo e li porto in 3d + for ( PolyLine i : vPL) { + PNTVECTOR vPnt ; + INTVECTOR vTria ; + Triangulate Tri ; + if ( ! Tri.Make( i, vPnt, vTria)) return nullptr ; - // prima curva isoparametrica (potrebbe essere un solo punto) - PolyLine PL1 ; - GetCurveOnU( 0, nStepU, PL1) ; - bool bSingle1 = ( PL1.GetPointNbr() == 1) ; - // ciclo sulle isoparametriche - for ( int i = 1 ; i <= nStepV ; ++ i) { - // seconda curva isoparametrica (con tanti punti quanti la prima, oppure uno solo) - double dV = double( i) * m_nSpanV / nStepV ; - PolyLine PL2 ; - GetCurveOnU( dV, nStepU, PL2) ; - bool bSingle2 = ( PL2.GetPointNbr() == 1) ; - // inserisco i triangoli della striscia nel costruttore della TriMesh - Point3d ptP1c, ptP2c ; - Point3d ptP1n, ptP2n ; - bool bNext = PL1.GetFirstPoint( ptP1c) && PL2.GetFirstPoint( ptP2c) ; - if ( bNext) { - if ( bSingle1 && bSingle2) - bNext = false ; - if ( bSingle1) - ptP1n = ptP1c ; - else - bNext = bNext && PL1.GetNextPoint( ptP1n) ; - if ( bSingle2) - ptP2n = ptP2c ; - else - bNext = bNext && PL2.GetNextPoint( ptP2n) ; - } - while ( bNext) { - // eventuale primo triangolo (con base sui correnti e vertice su P2 successivo) - if ( ! AreSamePointApprox( ptP1c, ptP2c)) - stmSoup.AddTriangle( ptP2c, ptP1c, ptP2n) ; - // eventuale secondo triangolo (con vertice su P1 corrente e base sui successivi) - if ( ! AreSamePointApprox( ptP1n, ptP2n)) - stmSoup.AddTriangle( ptP1c, ptP1n, ptP2n) ; - // passo alla successiva coppia - ptP1c = ptP1n ; - ptP2c = ptP2n ; - bNext = ( bSingle1 || PL1.GetNextPoint( ptP1n)) && ( bSingle2 || PL2.GetNextPoint( ptP2n)) ; - } - // salvo isoparametrica PL2 in PL1 - PL1.GetUPointList().swap( PL2.GetUPointList()) ; - bSingle1 = bSingle2 ; + + // porto i punti in 3d + PNTVECTOR vPnt3d ; + for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) { + Point3d pt3d ; + if ( ! GetPointD1D2( vPnt[i].x, vPnt[i].y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d)) + return nullptr ; + vPnt3d.push_back( pt3d) ; } - // la completo - if ( ! stmSoup.End()) - return nullptr ; - // la salvo - m_pSTM = GetBasicSurfTriMesh( stmSoup.GetSurf()) ; - } - else { - // costruttore della superficie - Tree Tree( this) ; - Tree.BuildTree() ; - POLYLINEVECTOR vPL ; - Tree.GetPolygons( vPL) ; - PtrOwner pSrfTm( CreateBasicSurfTriMesh()) ; - StmFromTriangleSoup stmSoup ; - if ( ! stmSoup.Start()) - return nullptr ; + int nTria = int( vTria.size()) / 3 ; + for ( int i = 0 ; i < nTria ; ++i) { + if ( ! stmSoup.AddTriangle( vPnt3d[vTria[3*i]], vPnt3d[vTria[3*i+1]], vPnt3d[vTria[3*i+2]])) + return nullptr ; + } + } - // prendo i punti di ogni polyline dell'albero, li triangolo e li porto in 3d - for ( PolyLine i : vPL) { - PNTVECTOR vPnt ; - INTVECTOR vTria ; - Triangulate Tri ; - if ( ! Tri.Make( i, vPnt, vTria)) - return false ; - - // porto i punti in 3d - PNTVECTOR vPnt3d ; - for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) { - Point3d pt3d ; - if ( ! GetPointD1D2( vPnt[i].x, vPnt[i].y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d)) - return false ; - vPnt3d.push_back( pt3d) ; - } - int nTria = int( vTria.size()) / 3 ; - for ( int i = 0 ; i < nTria ; ++i) { - if ( ! stmSoup.AddTriangle( vPnt3d[vTria[3*i]], vPnt3d[vTria[3*i+1]], vPnt3d[vTria[3*i+2]])) - return false ; - } - - - // if ( pSrfTm->GetVertexCount() == 0) { - // // inizializzo la superficie - // int nVert = int( vPnt.size()) ; - // int nTria = int( vTria.size()) / 3 ; - // if ( ! pSrfTm->Init( nVert, nTria)) - // return false ; - - // // porti i vertici dallo spazio parametrico allo spazio 3d e li inserisco nella superficie - // for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) { - // Point3d pt3d; - // GetPointD1D2( vPnt[i].x, vPnt[i].y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d) ; - // if ( pSrfTm->AddVertex( pt3d) == SVT_NULL) - // //if ( srfTmCell->AddVertex( vPnt[i]) == SVT_NULL ) - // return false ; - // } - - // // recupero i triangoli e li inserisco nella superficie - // int vV[3] ; - // for ( int i = 0 ; i < nTria ; ++i) { - // vV[0] = vTria[3*i] ; - // vV[1] = vTria[3*i+1] ; - // vV[2] = vTria[3*i+2] ; - // if ( pSrfTm->AddTriangle( vV) == SVT_NULL) - // return false ; - // } - - // // sistemo la topologia - // if ( ! pSrfTm->AdjustTopology()) - // return false ; - - // //pSrfTm.Set( Release(srfTmCell)) ; - // } - // else { - // // inizializzo la superficie - // int nVert = int( vPnt.size()) ; - // int nTria = int( vTria.size()) / 3 ; - - // // porti i vertici dallo spazio parametrico allo spazio 3d e li inserisco nella superficie - // for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) { - // Point3d pt3d; - // GetPointD1D2( vPnt[i].x, vPnt[i].y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d) ; - // if ( pSrfTm->AddVertex( pt3d) == SVT_NULL) - // return false ; - // } - - // // recupero i triangoli e li inserisco nella superficie - // int vV[3] ; - // int nVertCount = int ( pSrfTm->GetVertexCount()) - 4 ; - // for ( int i = 0 ; i < nTria ; ++i) { - // vV[0] = vTria[3*i] + nVertCount ; - // vV[1] = vTria[3*i+1] + nVertCount ; - // vV[2] = vTria[3*i+2] + nVertCount ; - // if ( pSrfTm->AddTriangle( vV) == SVT_NULL) - // return false ; - // } - // } - } - // if ( ! pSrfTm->AdjustTopology()) - // return false ; - //// la salvo - // m_pSTM = Release( pSrfTm) ; - - - - // la salvo - if ( ! stmSoup.End()) - return nullptr ; - m_pSTM = GetBasicSurfTriMesh( stmSoup.GetSurf()) ; - } + // la salvo + if ( ! stmSoup.End()) + return nullptr ; + m_pSTM = GetBasicSurfTriMesh( stmSoup.GetSurf()) ; + //} //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// return m_pSTM ; } diff --git a/SurfBezier.h b/SurfBezier.h index b5366e9..12149f8 100644 --- a/SurfBezier.h +++ b/SurfBezier.h @@ -83,6 +83,7 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW { return SetControlPoint( GetInd( nIndU, nIndV), ptCtrl, dW) ; } bool SetControlPoint( int nInd, const Point3d& ptCtrl, double dW) override ; bool SetTrimRegion( const ISurfFlatRegion& sfrTrimReg) override ; + bool GetTrimRegion( ISurfFlatRegion& sfrTrimReg) override ; bool GetInfo( int& nDegU, int& nDegV, int& nSpanU, int& nSpanV, bool& bIsRat, bool& bTrimmed) const override ; const Point3d& GetControlPoint( int nIndU, int nIndV, bool* pbOk) const override { return GetControlPoint( GetInd( nIndU, nIndV), pbOk) ; } diff --git a/Tree.cpp b/Tree.cpp index 5304f3f..9d672ab 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -25,8 +25,8 @@ using namespace std ; //---------------------------------------------------------------------------- Cell::Cell( void) - : m_nId( -1), m_ptPbl( ORIG), m_bProcessed ( false) , m_bSplitVert ( true) , 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_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_ptPbl( ORIG), m_ptPtr(), m_bProcessed ( false) , m_bSplitVert ( true) { Point3d ptTr ( 1, 1) ; m_ptPtr = ptTr ; @@ -35,8 +35,8 @@ Cell::Cell( void) //---------------------------------------------------------------------------- Cell::Cell( Point3d ptBL, Point3d ptTR) - : m_nId( -1), m_ptPbl( ptBL), m_ptPtr(ptTR), m_bProcessed ( false) , m_bSplitVert ( true) , 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_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_ptPbl( ptBL), m_ptPtr(ptTR), m_bProcessed ( false) , m_bSplitVert ( true) {} @@ -47,21 +47,17 @@ Cell::~Cell( void) //---------------------------------------------------------------------------- inline bool -Cell::IsSame( Cell cOtherCell) +Cell::IsSame( Cell cOtherCell) const { - if ( AreSamePointXYApprox( m_ptPbl, cOtherCell.GetBottomLeft()) && - AreSamePointXYApprox( m_ptPtr, cOtherCell.GetTopRight())) { + if ( m_nId == cOtherCell.m_nId) return true ; - } - else { + else return false ; - } } //---------------------------------------------------------------------------- bool -//Cell::IsLeaf ( void) const -Cell::IsLeaf ( void) +Cell::IsLeaf ( void) const { if( m_nChild1 == -2 && m_nChild2 == -2) return true ; @@ -71,25 +67,18 @@ Cell::IsLeaf ( void) //---------------------------------------------------------------------------- Tree::Tree( void) - : m_dLinTol(LIN_TOL_FINE), m_pSrfBz(nullptr), m_nRoot( -1), m_bTrimmed( false) + : m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosed( false) { Point3d ptBl( 0, 0), ptTr ( 1, 1) ; Cell cRoot( ptBl, ptTr) ; - m_mTree.insert( pair< int, Cell>( m_nRoot, cRoot)) ; + m_mTree.insert( pair< int, Cell>( -1, cRoot)) ; } //---------------------------------------------------------------------------- -Tree::Tree( const SurfBezier* pSrfBz) - : m_dLinTol( LIN_TOL_FINE), m_pSrfBz ( pSrfBz), m_nRoot( -1) +Tree::Tree( const SurfBezier* pSrfBz, bool bSplitPatches) + : m_bBilinear( false), m_bMulti( false), m_bClosed( false) { - // le coordinate delle celle sono nello spazio parametrico - int nDegU, nDegV, nSpanU, nSpanV ; - bool bIsRat, bTrimmed ; - m_pSrfBz->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bIsRat, bTrimmed) ; - m_bTrimmed = bTrimmed ; - Point3d ptTop( nSpanU, nSpanV) ; - Cell cRoot( ORIG, ptTop) ; - m_mTree.insert( pair< int, Cell>( m_nRoot, cRoot)) ; + SetSurf( pSrfBz, bSplitPatches) ; } //---------------------------------------------------------------------------- @@ -98,23 +87,83 @@ Tree::~Tree( void) } //---------------------------------------------------------------------------- -void Tree::SetSurf( const SurfBezier* pSrfBz) +void Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) { m_pSrfBz = pSrfBz ; - // le coordinate delle celle sono nello spazio parametrico + // le coordinate delle celle sono nello spazio parametrico int nDegU, nDegV, nSpanU, nSpanV ; bool bIsRat, bTrimmed ; m_pSrfBz->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bIsRat, bTrimmed) ; m_bTrimmed = bTrimmed ; + if ( nDegU == 1 && nDegV == 1) + m_bBilinear = true ; + if ( nSpanU * nSpanV != 1) + m_bMulti = true ; + if ( bSplitPatches) { + int nId = -1 ; + for ( int i = 1 ; i < nSpanU ; ++i ) { + m_mTree[nId].SetSplitDirVert( true) ; + Split( nId, i) ; + } + for ( int j = 1 ; j < nSpanV ; ++j ) { + + } + + // split preliminari per dividere le patch in modo da triangolarle indipendentemente//////////////////////////////////////////////////////// + // devo sistemare le adiacenze // queste si sistemano da sole con lo split + + // così creo dei child1 da cui devo ripassare per processarle, ma nel mio algoritmo non è previto!!!!!!!!!!!!!!!!! + } + // salvo i vertici 3d della cella root Point3d ptTop( nSpanU, nSpanV) ; Cell cRoot( ORIG, ptTop) ; m_mTree.insert( pair< int, Cell>( -1, cRoot)) ; + Point3d ptP00, ptP10, ptP11, ptP01 ; + bool bOk = false ; + 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( pair( -1, vVert)) ; + // 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 ; + // devo gestire se passo da entrambi questi if/////////////////////////////////////////////////////////////////////////////////////////////////////////// + if ( AreSamePointApprox(ptP00, ptP01)) { + m_mTree[-1].m_nTop = -1 ; + m_mTree[-1].m_nBottom = -1 ; + m_mTree[-1].SetSplitDirVert( false) ; + Split(-1) ; + } + if (AreSamePointApprox(ptP00, ptP10)) { + m_mTree[-1].m_nLeft = -1 ; + m_mTree[-1].m_nRight = -1 ; + 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) ; + 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)) ; } //---------------------------------------------------------------------------- void -Tree::Split( int nId) +Tree::Split( int nId, double dSplitValue) { + // per lo split a parametro libero devo impedire che si facciano split troppo vicini al bordo!!!!!!!!!!!!!!!!!!! Cell cChild1, cChild2 ; cChild1.m_nDepth = m_mTree[nId].m_nDepth + 1 ; cChild2.m_nDepth = m_mTree[nId].m_nDepth + 1 ; @@ -125,6 +174,10 @@ Tree::Split( int nId) m_mTree[nId].m_nChild2 = nNodes ; m_mTree.insert( pair( nNodes - 1, cChild1)) ; m_mTree.insert( pair( nNodes, cChild2)) ; + Point3d ptVert1, ptVert2 ; + PNTVECTOR vVert ; + m_mVert.insert( pair( nNodes - 1, vVert)) ; + m_mVert.insert( pair( nNodes, vVert)) ; if ( ! m_mTree[nId].IsSplitVert()) { // la cella figlio 1 è quella sopra @@ -142,6 +195,19 @@ Tree::Split( int nId) m_mTree[m_mTree[nId].m_nChild2].m_nBottom = m_mTree[nId].m_nBottom ; m_mTree[m_mTree[nId].m_nChild2].m_nLeft = m_mTree[nId].m_nLeft ; m_mTree[m_mTree[nId].m_nChild2].m_nRight = m_mTree[nId].m_nRight ; + // metto i corrispondenti 3d dei punti dello split nella mappa m_mVert + // per ogni cella i punti devono essere nell'ordine ptP00, ptP10, ptP11, ptP01 + //double dV = ( 1 - dSplitValue) * m_mTree[nId].GetBottomLeft().y + dSplitValue * m_mTree[nId].GetTopRight().y ; + m_pSrfBz->GetPointD1D2( m_mTree[nId].GetBottomLeft().x, dSplitValue, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert1) ; + m_pSrfBz->GetPointD1D2( m_mTree[nId].GetTopRight().x, dSplitValue, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert2) ; + m_mVert[nNodes - 1].push_back( ptVert1) ; + m_mVert[nNodes - 1].push_back( ptVert2) ; + m_mVert[nNodes - 1].push_back( m_mVert[nId][2]) ; + m_mVert[nNodes - 1].push_back( m_mVert[nId][3]) ; + m_mVert[nNodes].push_back( m_mVert[nId][0]) ; + m_mVert[nNodes].push_back( m_mVert[nId][1]) ; + m_mVert[nNodes].push_back( ptVert2) ; + m_mVert[nNodes].push_back( ptVert1) ; } else { // la cella figlio 1 è quella di sinistra @@ -159,253 +225,359 @@ Tree::Split( int nId) m_mTree[m_mTree[nId].m_nChild2].m_nBottom = m_mTree[nId].m_nBottom ; m_mTree[m_mTree[nId].m_nChild2].m_nLeft = m_mTree[nId].m_nChild1 ; m_mTree[m_mTree[nId].m_nChild2].m_nRight = m_mTree[nId].m_nRight ; + // metto i corrispondenti 3d dei punti dello split nella mappa m_mVert + // per ogni cella i punti devono essere nell'ordine ptP00, ptP10, ptP11, ptP01 + //double dU = ( m_mTree[nId].GetBottomLeft().x + m_mTree[nId].GetTopRight().x) / 2 ; + m_pSrfBz->GetPointD1D2( dSplitValue, m_mTree[nId].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert2) ; + m_pSrfBz->GetPointD1D2( dSplitValue, m_mTree[nId].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert1) ; + m_mVert[nNodes - 1].push_back( m_mVert[nId][0]) ; + m_mVert[nNodes - 1].push_back( ptVert2) ; + m_mVert[nNodes - 1].push_back( ptVert1) ; + m_mVert[nNodes - 1].push_back( m_mVert[nId][3]) ; + m_mVert[nNodes].push_back( ptVert2) ; + m_mVert[nNodes].push_back( m_mVert[nId][1]) ; + m_mVert[nNodes].push_back( m_mVert[nId][2]) ; + m_mVert[nNodes].push_back( ptVert1) ; } m_mTree[m_mTree[nId].m_nChild1].SetParent( nId) ; m_mTree[m_mTree[nId].m_nChild2].SetParent( nId) ; - //m_bProcessed = true ; } -////---------------------------------------------------------------------------- -//bool Tree::BuildTree(void) -//{ -// // di default SplitVert è true ! -// int ToSplit = -1; -// m_mTree[ToSplit].SetSplitDirVert( true) ; -// Split( ToSplit) ; -// // celle 2 e 3 -// ToSplit = m_mTree[-1].m_nChild1 ; -// m_mTree[ToSplit].SetSplitDirVert( false) ; -// Split( ToSplit) ; -// // celle 4 e 5 -// ToSplit = m_mTree[ToSplit].m_nChild1 ; -// m_mTree[ToSplit].SetSplitDirVert( true) ; -// Split( ToSplit) ; -// // celle 6 e 7 -// ToSplit = m_mTree[ToSplit].m_nChild2 ; -// m_mTree[ToSplit].SetSplitDirVert( false) ; -// Split( ToSplit) ; -// // celle 8 e 9 -// ToSplit = m_mTree[ToSplit].m_nChild2 ; -// m_mTree[ToSplit].SetSplitDirVert( true) ; -// Split( ToSplit) ; -// // celle 10 e 11 -// ToSplit = m_mTree[ToSplit].m_nChild1 ; -// m_mTree[ToSplit].SetSplitDirVert( false) ; -// Split( ToSplit) ; -// // celle 12 e 13 -// ToSplit = m_mTree[ToSplit].m_nParent ; -// ToSplit = m_mTree[ToSplit].m_nChild2 ; -// m_mTree[ToSplit].SetSplitDirVert( true) ; -// Split( ToSplit) ; -// INTVECTOR vTops, vBottoms, vLefts, vRights , vLeaves1, vLeaves2, vLeaves; -// int d1, d2 , H1 ; -// GetTopNeigh( 3, vTops) ; -// GetBottomNeigh( 6, vBottoms) ; -// GetLeftNeigh( 1, vLefts) ; -// GetRightNeigh( 4, vRights ) ; -// d1 = GetHeightLeaves( 7, vLeaves1) ; -// d2 = GetHeightLeaves( 5, vLeaves2) ; -// H1 = GetHeightLeaves( -1, vLeaves) ; -// m_vnLeaves = vLeaves ; -// int i = 0 ; -// -// return true ; -//} - -////---------------------------------------------------------------------------- -//bool Tree::BuildTree( void) -//{ -// int ToSplit = -1 ; -// m_mTree[ToSplit].SetSplitDirVert( true) ; -// Split( ToSplit) ; -// // celle 2 e 3 -// ToSplit = m_mTree[-1].m_nChild1 ; -// m_mTree[ToSplit].SetSplitDirVert( false) ; -// Split( ToSplit) ; -// -// return true ; -//} +//---------------------------------------------------------------------------- +void +Tree::Split( int nId) +{ + double dValue ; + if ( m_mTree[nId].IsSplitVert()) + dValue = ( m_mTree[nId].GetBottomLeft().x + m_mTree[nId].GetTopRight().x) / 2 ; + else + dValue = ( m_mTree[nId].GetBottomLeft().y + m_mTree[nId].GetTopRight().y) / 2 ; + Split( nId, dValue) ; +} //---------------------------------------------------------------------------- -bool Tree::BuildTree( double dLinTol, double dSideMax) +bool Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) { - // trovo dove splittare la cella e creo i puntatori ai figli - - // comincio a suddividere la superficie usando un kd-tree - // approssimo con una bilineare e se l'errore di approssimazione è troppo grande cerco una direzione - // in cui dividere la superficie - - double dErr ; // errore calcolato - double dDist; // distanza tra punti selezionati sulla isoparametrica - double dSideMinVal, dSideMaxVal ; // lunghezza del lato della eventuale cella figlio - double dSplit = 0.5 ; // effettuo sempre split a metà - double dSideMin = 0.05 ; // lunghezza minima del lato di una cella - //double dSidemin = 0.1 ; // lunghezza minima del lato di una cella - //m_dLinTol = dLinTol ; - m_dLinTol = 0.2 ; - int nSteps = 51 ; // numero di Step mentre scorro lungo un'isoparametrica - double dU, dV , dULoc, dVLoc ; - //double dIter, dIterLoc ; - bool bVert ; - Point3d ptBz, ptBl ; - // cerco lo scostamento massimo tra la sup di Bezier e la sua approssimazione bilineare + // suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri INTVECTOR vBalanceCheck ; int nCToSplit = -1 ; + // se ho già fatto degli split preliminari parto dal primo child anziché dal root + if ( (int) m_mTree.size() > 1) + nCToSplit = 0 ; + double dLinTol = 0.2 ; + //double dSideMin = 1 ; + if ( ! m_bTrimmed) { + if ( ! m_bBilinear) { + while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { + // calcolo in quale direzione ho più curvatura + // ptP00P10 è un punto tra P00 e P10 + double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; + double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; + double dULoc = 0.5, dVLoc = 0.5 ; + Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00 ; + m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; + Point3d ptV = ( 1 - dULoc) * ptP00P10 + dULoc * ptP11P01 ; + Point3d ptU = ( 1 - dVLoc) * ptP10P11 + dVLoc * ptP01P00 ; + // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza + // misura approssimativa della curvatura in una direzione + double dCurvV = Dist(ptV, ptPSrf) ; + double dCurvU = Dist(ptU, ptPSrf) ; + bool bVert ; + if ( dCurvV > dCurvU) { + // lungo la direzione V ho una curvatura maggiore + bVert = false ; + } + else { + // lungo la direzione U ho una curvatura maggiore + bVert = true ; + } + Point3d ptP00, ptP10, ptP11, ptP01 ; + // distanza reale tra i vertici della cella + ptP00 = m_mVert[nCToSplit][0] ; + ptP10 = m_mVert[nCToSplit][1] ; + ptP11 = m_mVert[nCToSplit][2] ; + ptP01 = m_mVert[nCToSplit][3] ; + double dLen0 = Dist( ptP00, ptP10) ; + double dLen1 = Dist( ptP10, ptP11) ; + double dLen2 = Dist( ptP01, ptP11) ; + double dLen3 = Dist( ptP00, ptP01) ; + // 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 = min( dLen0, dLen2) ; + else + dSideMinVal = max( dLen0, dLen2) ; + } + else { + if ( dLen1 != 0 && dLen3 != 0) + dSideMinVal = min( dLen1, dLen3) ; + else + dSideMinVal = max( dLen1, dLen3) ; + } + // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella + dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; + + // se la cella è abbastanza grande da poter essere divisa ancora, calcolo l'errore di approssimazione + double dErr = 0 ; + if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && ( dCurvV > dLinTol || dCurvU > dLinTol)) { + CurveLine cl0010, cl0001, cl1011, cl0111 ; + // U=0 + cl0010.Set( ptP00, ptP10) ; + // U=1 + cl0111.Set( ptP01, ptP11) ; + Point3d pt0010, pt0111, ptBz0, ptBz1, ptBzV ; + int nFlag ; + CurveLine clV ; + // determino quanti Step fare per ogni direzione parametrica + double dDimU = ( dLen0 >= dLen2 ? dLen0 / m_vDim[0] : dLen2 / m_vDim[2]) ; + double dDimV = ( dLen1 >= dLen3 ? dLen1 / m_vDim[1] : dLen3 / m_vDim[3]) ; + // numero di Step per campionare la superficie nelle due direzioni parametriche + int nStepsU = int( 51 * dDimU + 5 * ( 1 - dDimU)) ; + int nStepsV = int( 51 * dDimV + 5 * ( 1 - dDimV)) ; + for ( int u = 0 ; u < nStepsU ; ++ u) { + dU = double ( u) / double ( nStepsU - 1) ; + dULoc = ( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x ; + if ( ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz0) || + ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetTopRight().y, 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) ; + clV.Set( pt0010, pt0111) ; + for ( int v = 0 ; v < nStepsV ; ++ v) { + dV = double ( v) / double ( nStepsV - 1) ; + dVLoc = ( 1 - dV) * m_mTree[nCToSplit].GetBottomLeft().y + dV * m_mTree[nCToSplit].GetTopRight().y ; + if ( ! m_pSrfBz->GetPointD1D2( dULoc, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBzV)) + return false ; + DistPointCurve dpc( ptBzV, clV) ; + // distanza di approssimazione locale + double dDist ; + dpc.GetDist( dDist) ; + if ( dDist > dErr) + dErr = dDist ; + } + } + } - int c = 1 ; - while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { - dErr = 0 ; - // calcolo l'errore di approssimazione + if ( dErr > dLinTol || dSideMaxVal > dSideMax) { + m_mTree[nCToSplit].SetSplitDirVert( bVert) ; + // effettuo lo split + Split( nCToSplit) ; - //// calcolo l'errore di approssimazione confrontando con la bilineare corrispondente - //SurfBezier pSrfBl ; - //pSrfBl.Init(1, 1, 1, 1, false) ; - //m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; - //pSrfBl.SetControlPoint( 0, ptBz) ; // P00 - //m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; - //pSrfBl.SetControlPoint( 1, ptBz) ; // P10 - //m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; - //pSrfBl.SetControlPoint( 2, ptBz) ; // P01 - //m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) ; - //pSrfBl.SetControlPoint( 3, ptBz) ; // P11 - //// scorro lungo le isoparametriche a questi valori di U e V per trovare dov'è il punto di maggior discostamento - //dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; - //dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; - //dULoc = ( dU - m_mTree[nCToSplit].GetBottomLeft().x) / ( m_mTree[nCToSplit].GetTopRight().x - m_mTree[nCToSplit].GetBottomLeft().x) ; - //dVLoc = ( dV - m_mTree[nCToSplit].GetBottomLeft().y) / ( m_mTree[nCToSplit].GetTopRight().y - m_mTree[nCToSplit].GetBottomLeft().y) ; - //double dErrUmax = 0, dErrVmax = 0 ; - //for ( int i = 0 ; i < nSteps ; ++ i){ - // dIter = double ( i) / double ( nSteps - 1) ; - // dIterLoc = ( 1 - dIter) * m_mTree[nCToSplit].GetBottomLeft().y + dIter * m_mTree[nCToSplit].GetTopRight().y ; - // if ( ! m_pSrfBz->GetPointD1D2( dU, dIterLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) || - // ! pSrfBl.GetPointD1D2( dULoc, dIter, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBl)) - // return false ; - // dDist = Dist( ptBz, ptBl) ; - // dErrVmax = max ( dErrVmax, dDist) ; - // if ( dDist > dErr) { - // dErr = dDist ; - // //bVert = true ; - // } - // dIterLoc = ( 1 - dIter) * m_mTree[nCToSplit].GetBottomLeft().x + dIter * m_mTree[nCToSplit].GetTopRight().x ; - // if ( ! m_pSrfBz->GetPointD1D2( dIterLoc, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz) || - // ! pSrfBl.GetPointD1D2( dIter, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBl)) - // return false ; - // dDist = Dist( ptBz, ptBl) ; - // dErrUmax = max ( dErrUmax, dDist) ; - // if ( dDist > dErr) { - // dErr = dDist ; - // //bVert = false ; - // } - //} - - Point3d ptP00, ptP10, ptP11, ptP01 ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11) ; - CurveLine cl0010, cl0001, cl1011, cl0111 ; - // U=0 - cl0010.Set( ptP00, ptP10) ; - //// V=0 - //cl0001.Set( ptP00, ptP01) ; - // U=1 - cl0111.Set( ptP01, ptP11) ; - //// V=1 - //cl0111.Set( ptP01, ptP11) ; - Point3d pt0010, pt0111, ptBz0, ptBz1, ptBzV ; - int nFlag ; - CurveLine clV ; - for ( int u = 0 ; u < nSteps ; ++ u){ - dU = double ( u) / double ( nSteps - 1) ; - dULoc = ( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x ; - if ( ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz0) || - ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetTopRight().y, 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) ; - clV.Set( pt0010, pt0111) ; - for ( int v = 0 ; v < nSteps ; ++ v){ - dV = double ( v) / double ( nSteps - 1) ; - dVLoc = ( 1 - dV) * m_mTree[nCToSplit].GetBottomLeft().y + dV * m_mTree[nCToSplit].GetTopRight().y ; - if ( ! m_pSrfBz->GetPointD1D2( dULoc, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBzV)) - return false ; - DistPointCurve dpc( ptBzV, clV) ; - dpc.GetDist( dDist) ; - if ( dDist > dErr) - dErr = dDist ; - } - } - - // calcolo in quale direzione ho più curvatura - // devo trovare i punti sui lati corrispondenti a dUmax e dVmax, unendo queste coppie trovo le due direzioni di possibile split - // punti medi del lato successivo in senso antiorario rispetto al relativo vertice della patch - dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; - dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; - dULoc = dVLoc = 0.5 ; - Point3d ptPSrf ; //ptP00, ptP10, ptP11, ptP01; - m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10) ; - m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01) ; - Point3d ptP00P11 = ( 1 - dULoc) * ptP00 + dULoc * ptP11 ; - Point3d ptP10P01 = ( 1 - dVLoc) * ptP10 + dVLoc * ptP01 ; - // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza - // effettuo lo split e configuro le celle figlie - if ( Dist(ptP00P11, ptPSrf) > Dist(ptP10P01, ptPSrf)) - // lungo la direzione U ho una curvatura maggiore - bVert = false ; - else - // lungo la direzione V ho una curvatura maggiore - bVert = true ; - - // verifico che la cella sia da splittare e che eventualmente sia abbastanza grande da poterlo fare - if ( bVert) - dSideMinVal = min( Dist( ptP00, ptP10), Dist( ptP01, ptP11)) ; - else - dSideMinVal = min( Dist( ptP00, ptP01), Dist( ptP10, ptP11)) ; - dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; - if ( ( dErr > m_dLinTol && dSideMinVal >= dSideMin) || dSideMaxVal > dSideMax) { - m_mTree[nCToSplit].SetSplitDirVert( bVert) ; - // effettuo lo split - Split( nCToSplit) ; - - // procedo con lo split del Child1 - nCToSplit = m_mTree[nCToSplit].m_nChild1 ; - } - else { - // sono arrivato ad una cella Leaf, quindi salvo la cella - m_vnLeaves.push_back( nCToSplit) ; - m_mTree[nCToSplit].Processed() ; - // risalgo i parent finché non trovo il primo Child2 da processare - nCToSplit = m_mTree[nCToSplit].m_nParent ; - if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) - m_mTree[nCToSplit].Processed() ; - while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { - if ( m_mTree[nCToSplit].m_nParent != -2 ) - nCToSplit = m_mTree[nCToSplit].m_nParent ; - if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + // procedo con lo split del Child1 + nCToSplit = m_mTree[nCToSplit].m_nChild1 ; + } + else { + // sono arrivato ad una cella Leaf, quindi salvo la cella + m_vnLeaves.push_back( nCToSplit) ; m_mTree[nCToSplit].Processed() ; - if ( nCToSplit == m_nRoot && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed() ) - break ; + // risalgo i parent finché non trovo il primo Child2 da processare + nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + m_mTree[nCToSplit].Processed() ; + while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { + if ( m_mTree[nCToSplit].m_nParent != -2) + nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + m_mTree[nCToSplit].Processed() ; + if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + break ; + } + nCToSplit = m_mTree[nCToSplit].m_nChild2 ; + } + } + Balance( vBalanceCheck) ; // da implementare quando dividerò ad un parametro a scelta e non a metà + } + // bilineare + else { + while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { + // vertici della cella + Point3d ptP00, ptP10, ptP11, ptP01 ; + ptP00 = m_mVert[nCToSplit][0] ; + ptP10 = m_mVert[nCToSplit][1] ; + ptP11 = m_mVert[nCToSplit][2] ; + ptP01 = m_mVert[nCToSplit][3] ; + + // distanza reale tra i vertici della cella + double dLen0 = Dist( ptP00, ptP10) ; + double dLen1 = Dist( ptP10, ptP11) ; + double dLen2 = Dist( ptP01, ptP11) ; + double dLen3 = Dist( ptP00, ptP01) ; + + // calcolo se è migliore la divisione in orizzontale o in verticale + Point3d ptP00P10, ptP00P01 , ptP01P11, ptP10P11 ; + ptP00P10 = ( ptP00 + ptP10) / 2 ; + ptP10P11 = ( ptP10 + ptP11) / 2 ; + ptP01P11 = ( ptP01 + ptP11) / 2 ; + ptP00P01 = ( ptP00 + ptP01) / 2 ; + bool bVert = false ; + + + //// questo calcolo è inutile perché confronto due cose che sono sempre uguali/////////////////////////////////////////////////////// + // calcolo se è meglio spezzare in orizzontale o in verticale + //double dErrVert1 = ( ( ptP00 - ptP01) + ( ptP01P11 - ptP00P10)).Len() ; + //double dErrVert2 = ( ( ptP00P10 - ptP01P11) + ( ptP11 - ptP10)).Len() ; + //double dErrOriz1 = ( ( ptP00P01 - ptP01) + ( ptP11 - ptP10P11)).Len() ; + //double dErrOriz2 = ( ( ptP00 - ptP00P01) + ( ptP10P11 - ptP10)).Len() ; + ////if (0 ) { + //if ( abs( dErrVert1 + dErrVert2 - dErrOriz1 - dErrOriz2) < EPS_SMALL && nCToSplit != -1) { + // bVert = ! m_mTree[m_mTree[nCToSplit].m_nParent].IsSplitVert() ; + //} + //else { + // if ( dErrVert1 + dErrVert2 > dErrOriz1 + dErrOriz2) { + // bVert = false ; + // } + // else { + // bVert = true ; + // } + //} + + // con questo esce la C sulla bilineare + // calcolo in quale direzione è meglio dividere in base allo stretch + Point3d ptPSrfU, ptPSrfV ; + double dU = 0, dV = 0 ; + double dDistU = 0, dDistV = 0 ; + double dULoc, dVLoc ; + PNTVECTOR vPtU, vPtV ; + if ( ! m_bMulti) { + if ( max(dLen0, dLen2) > max(dLen1, dLen3)) { + bVert = true ; + } + else { + bVert = false ; + } + } + else { + for ( double i = 0.25 ; i < 1 ; i = i + 0.25 ) { + /*Point3d ptU = ( 1 - i) * ptP00P01 + i * ptP10P11 ; + Point3d ptV = ( 1 - i) * ptP00P10 + i * ptP01P11 ;*/ + dU = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().x + i * m_mTree[nCToSplit].GetTopRight().x ; + dV = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().y + i * m_mTree[nCToSplit].GetTopRight().y ; + dVLoc = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 ; + dULoc = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 ; + m_pSrfBz->GetPointD1D2( dU, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfU) ; + m_pSrfBz->GetPointD1D2( dULoc, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfV) ; + //dDistU = max( Dist( ptU , ptPSrfU), dDistU) ; + //dDistV = max( Dist( ptV , ptPSrfV), dDistV) ; + vPtU.push_back(ptPSrfU) ; + vPtV.push_back(ptPSrfV) ; + } + // devo guardare se i tre punti in vPtU e vPtV sono allineati + CurveLine clU, clV; + clU.Set(vPtU[0], vPtU[1]) ; + clV.Set(vPtV[0], vPtV[1]) ; + DistPointCurve dpcU( vPtU[2], clU, false) ; + DistPointCurve dpcV( vPtV[2], clV, false) ; + dpcU.GetDist( dDistU) ; + dpcV.GetDist( dDistV) ; + if ( dDistU > dDistV ) { + bVert = true ; + } + else { + bVert = false ; + } + } + + // diagonali + //Point3d ptP00P11, ptP10P01, ptPSrf ; + //ptP00P11 = ( ptP00 + ptP11) / 2 ; + //ptP10P01 = ( ptP10 + ptP01) / 2 ; + //double dU = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 ; + //double dV = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 ; + //m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + //if ( Dist( ptP00P11, ptPSrf) > Dist( ptP10P01, ptPSrf)) + // bVert = false ; + //else + // bVert = true ; + + + + + // verifico che la cella sia abbastanza grande da poter essere splittata + double dSideMinVal = 0, dSideMaxVal = 0 ; + if ( bVert) { + if ( dLen0 != 0 && dLen2 != 0) + dSideMinVal = min( dLen0, dLen2) ; + else + dSideMinVal = max( dLen0, dLen2) ; + } + else { + if ( dLen1 != 0 && dLen3 != 0) + dSideMinVal = min( dLen1, dLen3) ; + else + dSideMinVal = max( dLen1, dLen3) ; + } + // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella + dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; + + + double dErr = 0 ; + if ( m_bMulti ) { + Point3d ptPSrf ; + Plane3d plAppr ; + plAppr.Set( ptP00, ( ptP00 - ptP01) ^ ( ptP00 - ptP10)) ; + for ( double i = 0.25 ; i < 1 ; i = i + 0.25) { + for ( double j = 0.25 ; j < 1 ; j = j + 0.25) { + double dU = ( 1 - i) * m_mTree[nCToSplit].GetTopRight().x + i * m_mTree[nCToSplit].GetBottomLeft().x ; + double dV = ( 1 - j) * m_mTree[nCToSplit].GetTopRight().y + j * m_mTree[nCToSplit].GetBottomLeft().y ; + m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + dErr = max( abs( DistPointPlane( ptPSrf, plAppr)), dErr) ; + } + } + } + else { + dErr = 1. / 4. * ( (ptP00 - ptP01) + (ptP11 - ptP10)).Len() ; + } + // se la cella è abbastanza grande da poter essere divisa ancora e devo approssimare meglio, la divido + if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && dErr > dLinTol) { + m_mTree[nCToSplit].SetSplitDirVert( bVert) ; + // effettuo lo split + Split( nCToSplit) ; + + // procedo con lo split del Child1 + nCToSplit = m_mTree[nCToSplit].m_nChild1 ; + } + else { + // sono arrivato ad una cella Leaf, quindi salvo la cella + m_vnLeaves.push_back( nCToSplit) ; + m_mTree[nCToSplit].Processed() ; + // risalgo i parent finché non trovo il primo Child2 da processare + nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + m_mTree[nCToSplit].Processed() ; + while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { + if ( m_mTree[nCToSplit].m_nParent != -2) + nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + m_mTree[nCToSplit].Processed() ; + if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + break ; + } + nCToSplit = m_mTree[nCToSplit].m_nChild2 ; + } } - nCToSplit = m_mTree[nCToSplit].m_nChild2 ; } - c ++ ; } - Balance( vBalanceCheck) ; + // se la superficie è trimmata + else { + SurfFlatRegion sfrTrimReg ; + } return true ; } //---------------------------------------------------------------------------- void Tree::Balance( INTVECTOR vCheck) { - for ( int i : vCheck ) { - // non ancora implementato - // rendolo il tree balanced : ogni foglia deve avere una profondità di +- 1 rispetto ai suoi vicini. - } + //for ( int i : vCheck ) { + // // non ancora implementato + // // rendo il tree balanced : ogni foglia deve avere una profondità di +- 1 rispetto alle foglie adiacenti. + //} } //---------------------------------------------------------------------------- @@ -478,7 +650,7 @@ void Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) } } vector vCells ; - for ( int k : vTopNeighs ) + for ( int k : vTopNeighs) vCells.push_back( m_mTree[k]) ; sort( vCells.begin(), vCells.end(), Cell::minorX ) ; vTopNeighs.clear() ; @@ -516,7 +688,7 @@ void Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) } } bool bAllLeaves = true ; - for ( int i : vBottomNeighs ) { + for ( int i : vBottomNeighs) { if ( ! m_mTree[i].IsLeaf()) bAllLeaves = false ; } @@ -542,8 +714,8 @@ void Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) } // altrimenti solo uno dei figli lo sarà else { - if ( m_mTree[m_mTree[i].m_nChild1].GetTopRight().x <= m_mTree[nId].GetBottomLeft().x || - m_mTree[m_mTree[i].m_nChild1].GetBottomLeft().x >= m_mTree[nId].GetTopRight().x ) + if ( m_mTree[m_mTree[i].m_nChild1].GetTopRight().x <= m_mTree[nId].GetBottomLeft().x || + m_mTree[m_mTree[i].m_nChild1].GetBottomLeft().x >= m_mTree[nId].GetTopRight().x) vBottomNeighs.push_back( m_mTree[i].m_nChild2) ; else vBottomNeighs.push_back( m_mTree[i].m_nChild1) ; @@ -556,7 +728,7 @@ void Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) } } vector vCells ; - for ( int k : vBottomNeighs ) + for ( int k : vBottomNeighs) vCells.push_back( m_mTree[k]) ; sort( vCells.begin(), vCells.end(), Cell::minorX) ; vBottomNeighs.clear() ; @@ -568,7 +740,7 @@ void Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) //---------------------------------------------------------------------------- void Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) { - if ( (int) vLeftNeighs.size() == 0 ) { + if ( (int) vLeftNeighs.size() == 0) { if ( m_mTree[nId].m_nLeft == -2) return ; if ( m_mTree[m_mTree[nId].m_nLeft].IsLeaf()) @@ -577,14 +749,14 @@ void Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) if ( ! m_mTree[m_mTree[nId].m_nLeft].IsSplitVert()) { // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima if ( m_mTree[m_mTree[nId].m_nLeft].GetTopRight().y - m_mTree[m_mTree[nId].m_nLeft].GetBottomLeft().y <= - m_mTree[nId].GetTopRight().y - m_mTree[nId].GetBottomLeft().y) { + m_mTree[nId].GetTopRight().y - m_mTree[nId].GetBottomLeft().y) { vLeftNeighs.push_back( m_mTree[m_mTree[nId].m_nLeft].m_nChild1) ; vLeftNeighs.push_back( m_mTree[m_mTree[nId].m_nLeft].m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else{ - if ( m_mTree[m_mTree[m_mTree[nId].m_nLeft].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || - m_mTree[m_mTree[m_mTree[nId].m_nLeft].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y ) + if ( m_mTree[m_mTree[m_mTree[nId].m_nLeft].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || + m_mTree[m_mTree[m_mTree[nId].m_nLeft].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y) vLeftNeighs.push_back( m_mTree[m_mTree[nId].m_nLeft].m_nChild2) ; else vLeftNeighs.push_back( m_mTree[m_mTree[nId].m_nLeft].m_nChild1) ; @@ -595,7 +767,7 @@ void Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) } } bool bAllLeaves = true ; - for ( int i : vLeftNeighs ) { + for ( int i : vLeftNeighs) { if ( ! m_mTree[i].IsLeaf()) bAllLeaves = false ; } @@ -615,14 +787,14 @@ void Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) if ( ! m_mTree[i].IsSplitVert()) { // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima if ( m_mTree[i].GetTopRight().y - m_mTree[i].GetBottomLeft().y <= - m_mTree[nId].GetTopRight().y - m_mTree[nId].GetBottomLeft().y) { + m_mTree[nId].GetTopRight().y - m_mTree[nId].GetBottomLeft().y) { vLeftNeighs.push_back( m_mTree[i].m_nChild1) ; vLeftNeighs.push_back( m_mTree[i].m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else { - if ( m_mTree[m_mTree[i].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || - m_mTree[m_mTree[i].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y ) + if ( m_mTree[m_mTree[i].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || + m_mTree[m_mTree[i].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y) vLeftNeighs.push_back( m_mTree[i].m_nChild2) ; else vLeftNeighs.push_back( m_mTree[i].m_nChild1) ; @@ -661,8 +833,8 @@ void Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) } // altrimenti solo uno dei figli lo sarà else{ - if ( m_mTree[m_mTree[m_mTree[nId].m_nRight].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || - m_mTree[m_mTree[m_mTree[nId].m_nRight].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y ) + if ( m_mTree[m_mTree[m_mTree[nId].m_nRight].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || + m_mTree[m_mTree[m_mTree[nId].m_nRight].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y) vRightNeighs.push_back( m_mTree[m_mTree[nId].m_nRight].m_nChild2) ; else vRightNeighs.push_back( m_mTree[m_mTree[nId].m_nRight].m_nChild1) ; @@ -693,14 +865,14 @@ void Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) if ( ! m_mTree[i].IsSplitVert()) { // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima if ( m_mTree[i].GetTopRight().y - m_mTree[i].GetBottomLeft().y <= - m_mTree[nId].GetTopRight().y - m_mTree[nId].GetBottomLeft().y) { + m_mTree[nId].GetTopRight().y - m_mTree[nId].GetBottomLeft().y) { vRightNeighs.push_back( m_mTree[i].m_nChild1) ; vRightNeighs.push_back( m_mTree[i].m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else { - if ( m_mTree[m_mTree[i].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || - m_mTree[m_mTree[i].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y ) + if ( m_mTree[m_mTree[i].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || + m_mTree[m_mTree[i].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y) vRightNeighs.push_back( m_mTree[i].m_nChild2) ; else vRightNeighs.push_back( m_mTree[i].m_nChild1) ; @@ -759,7 +931,7 @@ int Tree::GetHeightLeaves( int nId, INTVECTOR& vnLeaves, int d) int Tree::GetDepth( int nId, int nRef = -2) { int c = 0 ; - while ( m_mTree[nId].m_nParent != nRef ) { + while ( m_mTree[nId].m_nParent != nRef) { nId = m_mTree[nId].m_nParent ; ++ c ; } @@ -826,7 +998,7 @@ bool Tree::GetPolygons( POLYLINEVECTOR& vPolygons) } vNeigh.clear() ; vVertices.push_back( m_mTree[nId].GetBottomLeft()) ; - // se hop una cella con vicino dello stesso grado controllo la curvatura nella cella e + // se ho una cella con vicino dello stesso grado ( quindi il poligono ha solo 5 punti) controllo la curvatura nella cella e // se necessario cambio l'ordine dei vertici per scegliere la diagonale di split migliore if ( vVertices.size() == 5) { Point3d ptPSrf, ptP00, ptP10, ptP11, ptP01; @@ -834,23 +1006,21 @@ bool Tree::GetPolygons( POLYLINEVECTOR& vPolygons) dU = ( m_mTree[nId].GetBottomLeft().x + m_mTree[nId].GetTopRight().x) / 2 ; dV = ( m_mTree[nId].GetBottomLeft().y + m_mTree[nId].GetTopRight().y) / 2 ; m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - m_pSrfBz->GetPointD1D2( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00) ; - m_pSrfBz->GetPointD1D2( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10) ; - m_pSrfBz->GetPointD1D2( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11) ; - m_pSrfBz->GetPointD1D2( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01) ; + ptP00 = m_mVert[nId][0] ; + ptP10 = m_mVert[nId][1] ; + ptP11 = m_mVert[nId][2] ; + ptP01 = m_mVert[nId][3] ; Point3d ptP00P11 = ( ptP00 + ptP11) / 2 ; Point3d ptP10P01 = ( ptP10 + ptP01) / 2 ; // ho la curvatura maggiore sulla diagonale tra P10 e P01, ruoto l'ordine dei vertici, in modo che triangulate prenda la diagonale giusta - if ( Dist(ptP00P11, ptPSrf) > Dist(ptP10P01, ptPSrf)) { + if ( Dist(ptP00P11, ptPSrf) + EPS_SMALL > Dist(ptP10P01, ptPSrf)) { rotate(vVertices.begin(), vVertices.begin() + 1,vVertices.end()) ; vVertices.back() = vVertices[0] ; } } - //double k = 0 ; m_vPolygons.emplace_back() ; - for ( int i = 0 ; i < (int) vVertices.size() ; ++i ) { - //k = double( i) / double( vVertices.size()) ; + for ( int i = 0 ; i < (int) vVertices.size() ; ++i) { m_vPolygons.back().AddUPoint( i, vVertices[i]) ; } } diff --git a/Tree.h b/Tree.h index 4df9a50..00f73bf 100644 --- a/Tree.h +++ b/Tree.h @@ -15,7 +15,6 @@ //--------------------------- Include ---------------------------------------- #include -#include "tree.h" #include "SurfBezier.h" #include "GeoConst.h" @@ -26,19 +25,18 @@ class Cell ~Cell( void) ; Cell( void) ; Cell( Point3d ptBL, Point3d ptTR) ; - inline bool IsSame( Cell cOtherCell) ; + inline bool IsSame( Cell cOtherCell) const ; void SetBottomLeft( Point3d ptBL) { m_ptPbl = ptBL ; } void SetTopRight( Point3d ptTR) { m_ptPtr = ptTR ; } void SetSplitDirVert( bool bVert) { m_bSplitVert = bVert ; } void SetParent(int nParent) { m_nParent = nParent ; } - Point3d GetBottomLeft( void) { return m_ptPbl ; } - Point3d GetTopRight( void) { return m_ptPtr ; } - bool IsSplitVert( void) { return m_bSplitVert ; } - bool IsLeaf( void) ; + Point3d GetBottomLeft( void) const { return m_ptPbl ; } + Point3d GetTopRight( void) const { return m_ptPtr ; } + double GetSplitValue( void) const { return m_dSplit ; } + bool IsSplitVert( void) const { return m_bSplitVert ; } + bool IsLeaf( void) const ; bool IsProcessed( void) const { return m_bProcessed ; } void Processed( void) { m_bProcessed = true ; } - //bool operator- ( const Cell &other) const { return m_ptPbl.x < other.m_ptPbl.x ; } - //bool operator| ( const Cell &other) const { return m_ptPbl.y < other.m_ptPbl.y ; } static bool minorX ( const Cell& c1, const Cell& c2) { return c1.m_ptPbl.x < c2.m_ptPbl.x ; } static bool minorY ( const Cell& c1, const Cell& c2) { return c1.m_ptPbl.y < c2.m_ptPbl.y ; } @@ -58,7 +56,7 @@ class Cell Point3d m_ptPtr ; // punto top right bool m_bProcessed ; // flag che indica se la cella è stata processata bool m_bSplitVert ; // flag che indica in quale direzione è stata divisa la cella - // double m_dSplit ; // lunghezza normalizzata a cui è stata splittata la cella + double m_dSplit ; // parametro a cui è stata splittata la cella } ; //---------------------------------------------------------------------------- @@ -67,28 +65,32 @@ class Tree public : ~Tree( void) ; Tree( void) ; - Tree ( const SurfBezier* pSrfBz) ; - void SetSurf( const SurfBezier* pSrfBz) ; - bool BuildTree( double dLinTol = LIN_TOL_STD, double dSideMax = INFINITO) ; // dSidemax è il massimo per la dimensione maggiore di un triangolo della trimesh + Tree ( const SurfBezier* pSrfBz, bool bSplitPatches = false) ; + void SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches = false) ; + bool BuildTree( double dLinTol = LIN_TOL_STD, double dSideMin = 5, 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 GetPolygons( POLYLINEVECTOR& vPolygons) ; private : - void Split( int nId) ; // funzione di split di una cella dell'albero + void Split( int nId, double dSplitValue) ; // funzione di split di una cella al parametro indicato nella direzione data da bVert + void Split( int nId) ; // funzione di split di una cella dell'albero a metà nella direzione data da bVert void Balance ( INTVECTOR vCheck) ; // creo rami in modo che tutte tutte le foglie abbiano come adiacenti foglie ad una profonditù di +- 1 int GetHeightLeaves ( int nId, INTVECTOR& vnLeaves, int d = 0) ; // altezza del subtree a partire dal nodo nId int GetDepth ( int nId, int nRef) ; // livello del nodo nId - void GetTopNeigh( int nId, INTVECTOR& vTopNeighs) ; - void GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) ; - void GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) ; - void GetRightNeigh( int nId, INTVECTOR& vRightNeighs) ; - + void GetTopNeigh( int nId, INTVECTOR& vTopNeighs) ; // restituisce le celle foglie che sono adiacenti al lato top + void GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) ; // restituisce le celle foglie che sono adiacenti al lato bottom + void GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) ; // restituisce le celle foglie che sono adiacenti al lato left + void GetRightNeigh( int nId, INTVECTOR& vRightNeighs) ; // restituisce le celle foglie che sono adiacenti al lato right private : - double m_dLinTol ; // errore dell'approssimazione - int m_nRoot ; // cella base - const SurfBezier* m_pSrfBz ; // root + const SurfBezier* m_pSrfBz ; // superficie di bezier + DBLVECTOR m_vDim ; // distanze tra i vertici della superficie di bezier in ordine antiorario a partire da ptP00 bool m_bTrimmed ; // superficie trimmata - POLYLINEVECTOR m_vPolygons ; // vettore dei poligoni del kd-tree + bool m_bBilinear ; // superficie bilineare + bool m_bMulti ; // superficie multi-patch + bool m_bClosed ; // superficie chiusa + POLYLINEVECTOR m_vPolygons ; // vettore dei poligoni del tree std::map m_mTree ; // mappa che contiene tutti i nodi e le foglie dell'albero. -2 è puntatore Null e -1 è root + std::map m_mVert ; // mappa che contiene tutti i vertici 3d delle celle del tree. L'Id è lo stesso che la cella ha in m_mTree INTVECTOR m_vnLeaves ; // vettore delle foglie } ; \ No newline at end of file From c3b8677910c50f6d38624587d43dbd5360be5eda Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Thu, 18 May 2023 09:48:02 +0200 Subject: [PATCH 05/44] EgtGeomKernel : - aggiunto lo split preliminare delle patches e impostato come default - gestito il caso di superfici chiuse come il toro - corretto un errore sul miglioramento delle prestazioni Da aggiungere : - gestione delle sup. trimmate. --- SurfBezier.cpp | 80 +---- Tree.cpp | 867 ++++++++++++++++++++++++++----------------------- Tree.h | 6 +- 3 files changed, 468 insertions(+), 485 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 054b366..c1c5b3d 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -1382,7 +1382,7 @@ SurfBezier::GetCurveOnVApproxLen( double dU) const return 0 ; return dLen ; } - +// ////---------------------------------------------------------------------------- //const SurfTriMesh* //SurfBezier::GetAuxSurf( void) const @@ -1471,75 +1471,9 @@ SurfBezier::GetAuxSurf( void) const // se già calcolata, la restituisco if ( m_pSTM != nullptr) return m_pSTM ; - //// definisco il numero degli step in U e in V - // double dMaxLenU = 0 ; - // for ( int j = 0 ; j <= m_nDegV * m_nSpanV ; ++ j) - // dMaxLenU = max( dMaxLenU, GetCurveOnUApproxLen( double( j) / m_nDegV)) ; - // int nStepU = GetSteps( m_nDegU, m_nSpanU, dMaxLenU, 2) ; - // double dMaxLenV = 0 ; - // for ( int i = 0 ; i <= m_nDegU * m_nSpanU ; ++ i) - // dMaxLenV = max( dMaxLenV, GetCurveOnVApproxLen( double( i) / m_nDegU)) ; - // int nStepV = GetSteps( m_nDegV, m_nSpanV, dMaxLenV, 2) ; - // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // if ( m_nDegU == 1 && m_nDegV == 1) { - // // costruttore della superficie - // StmFromTriangleSoup stmSoup ; - // if ( ! stmSoup.Start()) - // return nullptr ; - // // prima curva isoparametrica (potrebbe essere un solo punto) - // PolyLine PL1 ; - // GetCurveOnU( 0, nStepU, PL1) ; - // bool bSingle1 = ( PL1.GetPointNbr() == 1) ; - // // ciclo sulle isoparametriche - // for ( int i = 1 ; i <= nStepV ; ++ i) { - // // seconda curva isoparametrica (con tanti punti quanti la prima, oppure uno solo) - // double dV = double( i) * m_nSpanV / nStepV ; - // PolyLine PL2 ; - // GetCurveOnU( dV, nStepU, PL2) ; - // bool bSingle2 = ( PL2.GetPointNbr() == 1) ; - // // inserisco i triangoli della striscia nel costruttore della TriMesh - // Point3d ptP1c, ptP2c ; - // Point3d ptP1n, ptP2n ; - // bool bNext = PL1.GetFirstPoint( ptP1c) && PL2.GetFirstPoint( ptP2c) ; - // if ( bNext) { - // if ( bSingle1 && bSingle2) - // bNext = false ; - // if ( bSingle1) - // ptP1n = ptP1c ; - // else - // bNext = bNext && PL1.GetNextPoint( ptP1n) ; - // if ( bSingle2) - // ptP2n = ptP2c ; - // else - // bNext = bNext && PL2.GetNextPoint( ptP2n) ; - // } - // while ( bNext) { - // // eventuale primo triangolo (con base sui correnti e vertice su P2 successivo) - // if ( ! AreSamePointApprox( ptP1c, ptP2c)) - // stmSoup.AddTriangle( ptP2c, ptP1c, ptP2n) ; - // // eventuale secondo triangolo (con vertice su P1 corrente e base sui successivi) - // if ( ! AreSamePointApprox( ptP1n, ptP2n)) - // stmSoup.AddTriangle( ptP1c, ptP1n, ptP2n) ; - // // passo alla successiva coppia - // ptP1c = ptP1n ; - // ptP2c = ptP2n ; - // bNext = ( bSingle1 || PL1.GetNextPoint( ptP1n)) && ( bSingle2 || PL2.GetNextPoint( ptP2n)) ; - // } - // // salvo isoparametrica PL2 in PL1 - // PL1.GetUPointList().swap( PL2.GetUPointList()) ; - // bSingle1 = bSingle2 ; - // } - // // la completo - // if ( ! stmSoup.End()) - // return nullptr ; - // // la salvo - // m_pSTM = GetBasicSurfTriMesh( stmSoup.GetSurf()) ; - // } - // else { - - + // costruttore della superficie - Tree Tree( this) ; + Tree Tree( this, true) ; Tree.BuildTree() ; POLYLINEVECTOR vPL ; Tree.GetPolygons( vPL) ; @@ -1548,7 +1482,7 @@ SurfBezier::GetAuxSurf( void) const if ( ! stmSoup.Start()) return nullptr ; - // prendo i punti di ogni polyline dell'albero, li triangolo e li porto in 3d + // prendo i punti di ogni polyline dell'albero, li triangolo e li porto in 3d for ( PolyLine i : vPL) { PNTVECTOR vPnt ; INTVECTOR vTria ; @@ -1556,7 +1490,7 @@ SurfBezier::GetAuxSurf( void) const if ( ! Tri.Make( i, vPnt, vTria)) return nullptr ; - // porto i punti in 3d + // porto i punti in 3d PNTVECTOR vPnt3d ; for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) { Point3d pt3d ; @@ -1571,11 +1505,11 @@ SurfBezier::GetAuxSurf( void) const } } - // la salvo + // la salvo if ( ! stmSoup.End()) return nullptr ; m_pSTM = GetBasicSurfTriMesh( stmSoup.GetSurf()) ; - //} //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + return m_pSTM ; } diff --git a/Tree.cpp b/Tree.cpp index 9d672ab..bce006f 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -99,21 +99,7 @@ void Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) m_bBilinear = true ; if ( nSpanU * nSpanV != 1) m_bMulti = true ; - if ( bSplitPatches) { - int nId = -1 ; - for ( int i = 1 ; i < nSpanU ; ++i ) { - m_mTree[nId].SetSplitDirVert( true) ; - Split( nId, i) ; - } - for ( int j = 1 ; j < nSpanV ; ++j ) { - - } - - // split preliminari per dividere le patch in modo da triangolarle indipendentemente//////////////////////////////////////////////////////// - // devo sistemare le adiacenze // queste si sistemano da sole con lo split - - // così creo dei child1 da cui devo ripassare per processarle, ma nel mio algoritmo non è previto!!!!!!!!!!!!!!!!! - } + // salvo i vertici 3d della cella root Point3d ptTop( nSpanU, nSpanV) ; Cell cRoot( ORIG, ptTop) ; @@ -130,24 +116,96 @@ void Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) ptP01 = m_pSrfBz->GetControlPoint( ( nDegU * nSpanU + 1 ) * ( nDegV * nSpanV), &bOk) ; vVert.push_back( ptP01) ; m_mVert.insert( pair( -1, vVert)) ; - // 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 ; - // devo gestire se passo da entrambi questi if/////////////////////////////////////////////////////////////////////////////////////////////////////////// - if ( AreSamePointApprox(ptP00, ptP01)) { - m_mTree[-1].m_nTop = -1 ; - m_mTree[-1].m_nBottom = -1 ; - m_mTree[-1].SetSplitDirVert( false) ; - Split(-1) ; + // se richiesto divido preliminarmente le patches + if ( bSplitPatches && ( nSpanU > 1 || nSpanV > 1)) { + int nId = -1 ; + for ( int i = 1 ; i < nSpanU ; ++i) { + m_mTree[nId].SetSplitDirVert( true) ; + Split( nId, i) ; + ++ nId ; + ++ nId ; } - if (AreSamePointApprox(ptP00, ptP10)) { - m_mTree[-1].m_nLeft = -1 ; - m_mTree[-1].m_nRight = -1 ; - m_mTree[-1].SetSplitDirVert( true) ; - Split( -1) ; + 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) ; + nId = m_mTree[nId].m_nChild2 ; + } + } + // split preliminari per dividere le patch in modo da triangolarle indipendentemente//////////////////////////////////////////////////////// + } + // 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) ; + 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) ; + // 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) ; + } + } } } + // calcolo e salvo la distanza reale tra i vertici della cella root double dLen0 = Dist( ptP00, ptP10) ; double dLen1 = Dist( ptP10, ptP11) ; @@ -163,84 +221,87 @@ void Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) void Tree::Split( int nId, double dSplitValue) { - // per lo split a parametro libero devo impedire che si facciano split troppo vicini al bordo!!!!!!!!!!!!!!!!!!! - Cell cChild1, cChild2 ; - cChild1.m_nDepth = m_mTree[nId].m_nDepth + 1 ; - cChild2.m_nDepth = m_mTree[nId].m_nDepth + 1 ; - int nNodes = (int) m_mTree.size() ; - cChild1.m_nId = nNodes - 1 ; - m_mTree[nId].m_nChild1 = nNodes - 1 ; - cChild2.m_nId = nNodes ; - m_mTree[nId].m_nChild2 = nNodes ; - m_mTree.insert( pair( nNodes - 1, cChild1)) ; - m_mTree.insert( pair( nNodes, cChild2)) ; - Point3d ptVert1, ptVert2 ; - PNTVECTOR vVert ; - m_mVert.insert( pair( nNodes - 1, vVert)) ; - m_mVert.insert( pair( nNodes, vVert)) ; - if ( ! m_mTree[nId].IsSplitVert()) - { - // la cella figlio 1 è quella sopra - Point3d ptBL( m_mTree[nId].GetBottomLeft().x, ( m_mTree[nId].GetBottomLeft().y + m_mTree[nId].GetTopRight().y) / 2) ; - m_mTree[m_mTree[nId].m_nChild1].SetBottomLeft( ptBL) ; - m_mTree[m_mTree[nId].m_nChild1].SetTopRight( m_mTree[nId].GetTopRight()) ; - m_mTree[m_mTree[nId].m_nChild1].m_nTop = m_mTree[nId].m_nTop ; - m_mTree[m_mTree[nId].m_nChild1].m_nBottom = m_mTree[nId].m_nChild2 ; - m_mTree[m_mTree[nId].m_nChild1].m_nLeft = m_mTree[nId].m_nLeft ; - m_mTree[m_mTree[nId].m_nChild1].m_nRight = m_mTree[nId].m_nRight ; - Point3d ptTR( m_mTree[nId].GetTopRight().x, ( m_mTree[nId].GetTopRight().y + m_mTree[nId].GetBottomLeft().y) / 2) ; - m_mTree[m_mTree[nId].m_nChild2].SetBottomLeft( m_mTree[nId].GetBottomLeft()) ; - m_mTree[m_mTree[nId].m_nChild2].SetTopRight( ptTR) ; - m_mTree[m_mTree[nId].m_nChild2].m_nTop = m_mTree[nId].m_nChild1 ; - m_mTree[m_mTree[nId].m_nChild2].m_nBottom = m_mTree[nId].m_nBottom ; - m_mTree[m_mTree[nId].m_nChild2].m_nLeft = m_mTree[nId].m_nLeft ; - m_mTree[m_mTree[nId].m_nChild2].m_nRight = m_mTree[nId].m_nRight ; - // metto i corrispondenti 3d dei punti dello split nella mappa m_mVert - // per ogni cella i punti devono essere nell'ordine ptP00, ptP10, ptP11, ptP01 - //double dV = ( 1 - dSplitValue) * m_mTree[nId].GetBottomLeft().y + dSplitValue * m_mTree[nId].GetTopRight().y ; - m_pSrfBz->GetPointD1D2( m_mTree[nId].GetBottomLeft().x, dSplitValue, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert1) ; - m_pSrfBz->GetPointD1D2( m_mTree[nId].GetTopRight().x, dSplitValue, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert2) ; - m_mVert[nNodes - 1].push_back( ptVert1) ; - m_mVert[nNodes - 1].push_back( ptVert2) ; - m_mVert[nNodes - 1].push_back( m_mVert[nId][2]) ; - m_mVert[nNodes - 1].push_back( m_mVert[nId][3]) ; - m_mVert[nNodes].push_back( m_mVert[nId][0]) ; - m_mVert[nNodes].push_back( m_mVert[nId][1]) ; - m_mVert[nNodes].push_back( ptVert2) ; - m_mVert[nNodes].push_back( ptVert1) ; + // 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 devo impedire che si facciano split troppo vicini al bordo!!!!!!!!!!!!!!!!!!! + m_mTree[nId].m_dSplit = dSplitValue ; + Cell cChild1, cChild2 ; + cChild1.m_nDepth = m_mTree[nId].m_nDepth + 1 ; + cChild2.m_nDepth = m_mTree[nId].m_nDepth + 1 ; + int nNodes = (int) m_mTree.size() ; + cChild1.m_nId = nNodes - 1 ; + m_mTree[nId].m_nChild1 = nNodes - 1 ; + cChild2.m_nId = nNodes ; + m_mTree[nId].m_nChild2 = nNodes ; + m_mTree.insert( pair( nNodes - 1, cChild1)) ; + m_mTree.insert( pair( nNodes, cChild2)) ; + Point3d ptVert1, ptVert2 ; + PNTVECTOR vVert ; + m_mVert.insert( pair( nNodes - 1, vVert)) ; + m_mVert.insert( pair( nNodes, vVert)) ; + if ( ! m_mTree[nId].IsSplitVert()) + { + // la cella figlio 1 è quella sopra + Point3d ptBL( m_mTree[nId].GetBottomLeft().x, dSplitValue) ; + m_mTree[m_mTree[nId].m_nChild1].SetBottomLeft( ptBL) ; + m_mTree[m_mTree[nId].m_nChild1].SetTopRight( m_mTree[nId].GetTopRight()) ; + m_mTree[m_mTree[nId].m_nChild1].m_nTop = m_mTree[nId].m_nTop ; + m_mTree[m_mTree[nId].m_nChild1].m_nBottom = m_mTree[nId].m_nChild2 ; + m_mTree[m_mTree[nId].m_nChild1].m_nLeft = m_mTree[nId].m_nLeft ; + m_mTree[m_mTree[nId].m_nChild1].m_nRight = m_mTree[nId].m_nRight ; + Point3d ptTR( m_mTree[nId].GetTopRight().x, dSplitValue) ; + m_mTree[m_mTree[nId].m_nChild2].SetBottomLeft( m_mTree[nId].GetBottomLeft()) ; + m_mTree[m_mTree[nId].m_nChild2].SetTopRight( ptTR) ; + m_mTree[m_mTree[nId].m_nChild2].m_nTop = m_mTree[nId].m_nChild1 ; + m_mTree[m_mTree[nId].m_nChild2].m_nBottom = m_mTree[nId].m_nBottom ; + m_mTree[m_mTree[nId].m_nChild2].m_nLeft = m_mTree[nId].m_nLeft ; + m_mTree[m_mTree[nId].m_nChild2].m_nRight = m_mTree[nId].m_nRight ; + // metto i corrispondenti 3d dei punti dello split nella mappa m_mVert + // per ogni cella i punti devono essere nell'ordine ptP00, ptP10, ptP11, ptP01 + m_pSrfBz->GetPointD1D2( m_mTree[nId].GetBottomLeft().x, dSplitValue, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert1) ; + m_pSrfBz->GetPointD1D2( m_mTree[nId].GetTopRight().x, dSplitValue, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert2) ; + m_mVert[nNodes - 1].push_back( ptVert1) ; + m_mVert[nNodes - 1].push_back( ptVert2) ; + m_mVert[nNodes - 1].push_back( m_mVert[nId][2]) ; + m_mVert[nNodes - 1].push_back( m_mVert[nId][3]) ; + m_mVert[nNodes].push_back( m_mVert[nId][0]) ; + m_mVert[nNodes].push_back( m_mVert[nId][1]) ; + m_mVert[nNodes].push_back( ptVert2) ; + m_mVert[nNodes].push_back( ptVert1) ; + } + else { + // la cella figlio 1 è quella di sinistra + Point3d ptTR( dSplitValue, m_mTree[nId].GetTopRight().y) ; + m_mTree[m_mTree[nId].m_nChild1].SetBottomLeft( m_mTree[nId].GetBottomLeft()) ; + m_mTree[m_mTree[nId].m_nChild1].SetTopRight( ptTR) ; + m_mTree[m_mTree[nId].m_nChild1].m_nTop = m_mTree[nId].m_nTop ; + m_mTree[m_mTree[nId].m_nChild1].m_nBottom = m_mTree[nId].m_nBottom ; + m_mTree[m_mTree[nId].m_nChild1].m_nLeft = m_mTree[nId].m_nLeft ; + m_mTree[m_mTree[nId].m_nChild1].m_nRight = m_mTree[nId].m_nChild2 ; + Point3d ptBL( dSplitValue, m_mTree[nId].GetBottomLeft().y) ; + m_mTree[m_mTree[nId].m_nChild2].SetBottomLeft( ptBL) ; + m_mTree[m_mTree[nId].m_nChild2].SetTopRight( m_mTree[nId].GetTopRight()) ; + m_mTree[m_mTree[nId].m_nChild2].m_nTop = m_mTree[nId].m_nTop ; + m_mTree[m_mTree[nId].m_nChild2].m_nBottom = m_mTree[nId].m_nBottom ; + m_mTree[m_mTree[nId].m_nChild2].m_nLeft = m_mTree[nId].m_nChild1 ; + m_mTree[m_mTree[nId].m_nChild2].m_nRight = m_mTree[nId].m_nRight ; + // metto i corrispondenti 3d dei punti dello split nella mappa m_mVert + // per ogni cella i punti devono essere nell'ordine ptP00, ptP10, ptP11, ptP01 + m_pSrfBz->GetPointD1D2( dSplitValue, m_mTree[nId].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert2) ; + m_pSrfBz->GetPointD1D2( dSplitValue, m_mTree[nId].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert1) ; + m_mVert[nNodes - 1].push_back( m_mVert[nId][0]) ; + m_mVert[nNodes - 1].push_back( ptVert2) ; + m_mVert[nNodes - 1].push_back( ptVert1) ; + m_mVert[nNodes - 1].push_back( m_mVert[nId][3]) ; + m_mVert[nNodes].push_back( ptVert2) ; + m_mVert[nNodes].push_back( m_mVert[nId][1]) ; + m_mVert[nNodes].push_back( m_mVert[nId][2]) ; + m_mVert[nNodes].push_back( ptVert1) ; + } + m_mTree[m_mTree[nId].m_nChild1].SetParent( nId) ; + m_mTree[m_mTree[nId].m_nChild2].SetParent( nId) ; } - else { - // la cella figlio 1 è quella di sinistra - Point3d ptTR( ( m_mTree[nId].GetBottomLeft().x + m_mTree[nId].GetTopRight().x) / 2, m_mTree[nId].GetTopRight().y) ; - m_mTree[m_mTree[nId].m_nChild1].SetBottomLeft( m_mTree[nId].GetBottomLeft()) ; - m_mTree[m_mTree[nId].m_nChild1].SetTopRight( ptTR) ; - m_mTree[m_mTree[nId].m_nChild1].m_nTop = m_mTree[nId].m_nTop ; - m_mTree[m_mTree[nId].m_nChild1].m_nBottom = m_mTree[nId].m_nBottom ; - m_mTree[m_mTree[nId].m_nChild1].m_nLeft = m_mTree[nId].m_nLeft ; - m_mTree[m_mTree[nId].m_nChild1].m_nRight = m_mTree[nId].m_nChild2 ; - Point3d ptBL(( m_mTree[nId].GetBottomLeft().x + m_mTree[nId].GetTopRight().x) / 2, m_mTree[nId].GetBottomLeft().y) ; - m_mTree[m_mTree[nId].m_nChild2].SetBottomLeft( ptBL) ; - m_mTree[m_mTree[nId].m_nChild2].SetTopRight( m_mTree[nId].GetTopRight()) ; - m_mTree[m_mTree[nId].m_nChild2].m_nTop = m_mTree[nId].m_nTop ; - m_mTree[m_mTree[nId].m_nChild2].m_nBottom = m_mTree[nId].m_nBottom ; - m_mTree[m_mTree[nId].m_nChild2].m_nLeft = m_mTree[nId].m_nChild1 ; - m_mTree[m_mTree[nId].m_nChild2].m_nRight = m_mTree[nId].m_nRight ; - // metto i corrispondenti 3d dei punti dello split nella mappa m_mVert - // per ogni cella i punti devono essere nell'ordine ptP00, ptP10, ptP11, ptP01 - //double dU = ( m_mTree[nId].GetBottomLeft().x + m_mTree[nId].GetTopRight().x) / 2 ; - m_pSrfBz->GetPointD1D2( dSplitValue, m_mTree[nId].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert2) ; - m_pSrfBz->GetPointD1D2( dSplitValue, m_mTree[nId].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert1) ; - m_mVert[nNodes - 1].push_back( m_mVert[nId][0]) ; - m_mVert[nNodes - 1].push_back( ptVert2) ; - m_mVert[nNodes - 1].push_back( ptVert1) ; - m_mVert[nNodes - 1].push_back( m_mVert[nId][3]) ; - m_mVert[nNodes].push_back( ptVert2) ; - m_mVert[nNodes].push_back( m_mVert[nId][1]) ; - m_mVert[nNodes].push_back( m_mVert[nId][2]) ; - m_mVert[nNodes].push_back( ptVert1) ; - } - m_mTree[m_mTree[nId].m_nChild1].SetParent( nId) ; - m_mTree[m_mTree[nId].m_nChild2].SetParent( nId) ; } //---------------------------------------------------------------------------- @@ -259,307 +320,288 @@ Tree::Split( int nId) bool Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) { // suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri - INTVECTOR vBalanceCheck ; int nCToSplit = -1 ; - // se ho già fatto degli split preliminari parto dal primo child anziché dal root - if ( (int) m_mTree.size() > 1) - nCToSplit = 0 ; double dLinTol = 0.2 ; //double dSideMin = 1 ; if ( ! m_bTrimmed) { if ( ! m_bBilinear) { while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { - // calcolo in quale direzione ho più curvatura - // ptP00P10 è un punto tra P00 e P10 - double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; - double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; - double dULoc = 0.5, dVLoc = 0.5 ; - Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00 ; - m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; - m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; - Point3d ptV = ( 1 - dULoc) * ptP00P10 + dULoc * ptP11P01 ; - Point3d ptU = ( 1 - dVLoc) * ptP10P11 + dVLoc * ptP01P00 ; - // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza - // misura approssimativa della curvatura in una direzione - double dCurvV = Dist(ptV, ptPSrf) ; - double dCurvU = Dist(ptU, ptPSrf) ; - bool bVert ; - if ( dCurvV > dCurvU) { - // lungo la direzione V ho una curvatura maggiore - bVert = false ; - } - else { - // lungo la direzione U ho una curvatura maggiore - bVert = true ; - } - Point3d ptP00, ptP10, ptP11, ptP01 ; - // distanza reale tra i vertici della cella - ptP00 = m_mVert[nCToSplit][0] ; - ptP10 = m_mVert[nCToSplit][1] ; - ptP11 = m_mVert[nCToSplit][2] ; - ptP01 = m_mVert[nCToSplit][3] ; - double dLen0 = Dist( ptP00, ptP10) ; - double dLen1 = Dist( ptP10, ptP11) ; - double dLen2 = Dist( ptP01, ptP11) ; - double dLen3 = Dist( ptP00, ptP01) ; - // 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 = min( dLen0, dLen2) ; - else - dSideMinVal = max( dLen0, dLen2) ; - } - else { - if ( dLen1 != 0 && dLen3 != 0) - dSideMinVal = min( dLen1, dLen3) ; - else - dSideMinVal = max( dLen1, dLen3) ; - } - // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella - dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; + // controllo che la cella non sia già stata preliminarmente splittata + if ( m_mTree[nCToSplit].IsLeaf()) { + // calcolo in quale direzione ho più curvatura + // ptP00P10 è un punto tra P00 e P10 + double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; + double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; + double dULoc = 0.5, dVLoc = 0.5 ; + Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00 ; + m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; + Point3d ptV = ( 1 - dULoc) * ptP00P10 + dULoc * ptP11P01 ; + Point3d ptU = ( 1 - dVLoc) * ptP10P11 + dVLoc * ptP01P00 ; + // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza + // misura approssimativa della curvatura in una direzione + double dCurvV = Dist( ptV, ptPSrf) ; + double dCurvU = Dist( ptU, ptPSrf) ; + bool bVert ; + if ( dCurvV > dCurvU) { + // lungo la direzione V ho una curvatura maggiore + bVert = false ; + } + else { + // lungo la direzione U ho una curvatura maggiore + bVert = true ; + } + m_mTree[nCToSplit].SetSplitDirVert( bVert) ; + Point3d ptP00, ptP10, ptP11, ptP01 ; + // distanza reale tra i vertici della cella + ptP00 = m_mVert[nCToSplit][0] ; + ptP10 = m_mVert[nCToSplit][1] ; + ptP11 = m_mVert[nCToSplit][2] ; + ptP01 = m_mVert[nCToSplit][3] ; + double dLen0 = Dist( ptP00, ptP10) ; + double dLen1 = Dist( ptP10, ptP11) ; + double dLen2 = Dist( ptP01, ptP11) ; + double dLen3 = Dist( ptP00, ptP01) ; + // 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 = min( dLen0, dLen2) ; + else + dSideMinVal = max( dLen0, dLen2) ; + } + else { + if ( dLen1 != 0 && dLen3 != 0) + dSideMinVal = min( dLen1, dLen3) ; + else + dSideMinVal = max( dLen1, dLen3) ; + } + // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella + dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; - // se la cella è abbastanza grande da poter essere divisa ancora, calcolo l'errore di approssimazione - double dErr = 0 ; - if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && ( dCurvV > dLinTol || dCurvU > dLinTol)) { - CurveLine cl0010, cl0001, cl1011, cl0111 ; - // U=0 - cl0010.Set( ptP00, ptP10) ; - // U=1 - cl0111.Set( ptP01, ptP11) ; - Point3d pt0010, pt0111, ptBz0, ptBz1, ptBzV ; - int nFlag ; - CurveLine clV ; - // determino quanti Step fare per ogni direzione parametrica - double dDimU = ( dLen0 >= dLen2 ? dLen0 / m_vDim[0] : dLen2 / m_vDim[2]) ; - double dDimV = ( dLen1 >= dLen3 ? dLen1 / m_vDim[1] : dLen3 / m_vDim[3]) ; - // numero di Step per campionare la superficie nelle due direzioni parametriche - int nStepsU = int( 51 * dDimU + 5 * ( 1 - dDimU)) ; - int nStepsV = int( 51 * dDimV + 5 * ( 1 - dDimV)) ; - for ( int u = 0 ; u < nStepsU ; ++ u) { - dU = double ( u) / double ( nStepsU - 1) ; - dULoc = ( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x ; - if ( ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz0) || - ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetTopRight().y, 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) ; - clV.Set( pt0010, pt0111) ; - for ( int v = 0 ; v < nStepsV ; ++ v) { - dV = double ( v) / double ( nStepsV - 1) ; - dVLoc = ( 1 - dV) * m_mTree[nCToSplit].GetBottomLeft().y + dV * m_mTree[nCToSplit].GetTopRight().y ; - if ( ! m_pSrfBz->GetPointD1D2( dULoc, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBzV)) + // se la cella è abbastanza grande da poter essere divisa ancora, calcolo l'errore di approssimazione + double dErr = 0 ; + bool bSplit = false ; + if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && ( dCurvV > dLinTol || dCurvU > dLinTol)) { + CurveLine cl0010, cl0001, cl1011, cl0111 ; + // U=0 + cl0010.Set( ptP00, ptP10) ; + // U=1 + cl0111.Set( ptP01, ptP11) ; + Point3d pt0010, pt0111, ptBz0, ptBz1, ptBzV ; + int nFlag ; + CurveLine clV ; + // determino quanti Step fare per ogni direzione parametrica + double dDimU = ( dLen0 >= dLen2 ? dLen0 / m_vDim[0] : dLen2 / m_vDim[2]) ; + dDimU = ( dDimU > 1 ? 1 : dDimU) ; + double dDimV = ( dLen1 >= dLen3 ? dLen1 / m_vDim[1] : dLen3 / m_vDim[3]) ; + dDimV = ( dDimV > 1 ? 1 : dDimV) ; + // numero di Step per campionare la superficie nelle due direzioni parametriche + int nStepsU = int( 51 * dDimU + 5 * ( 1 - dDimU)) ; + int nStepsV = int( 51 * dDimV + 5 * ( 1 - dDimV)) ; + for ( int u = 0 ; u < nStepsU && ! bSplit ; ++ u) { + dU = double ( u) / double ( nStepsU - 1) ; + dULoc = ( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x ; + if ( ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz0) || + ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz1)) return false ; - DistPointCurve dpc( ptBzV, clV) ; - // distanza di approssimazione locale - double dDist ; - dpc.GetDist( dDist) ; - if ( dDist > dErr) - dErr = dDist ; + DistPointCurve dpc0010( ptBz0, cl0010) ; + DistPointCurve dpc0111( ptBz1, cl0111) ; + dpc0010.GetMinDistPoint( 0, pt0010, nFlag) ; + dpc0111.GetMinDistPoint( 0, pt0111, nFlag) ; + clV.Set( pt0010, pt0111) ; + for ( int v = 0 ; v < nStepsV ; ++ v) { + dV = double ( v) / double ( nStepsV - 1) ; + dVLoc = ( 1 - dV) * m_mTree[nCToSplit].GetBottomLeft().y + dV * m_mTree[nCToSplit].GetTopRight().y ; + if ( ! m_pSrfBz->GetPointD1D2( dULoc, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBzV)) + return false ; + DistPointCurve dpc( ptBzV, clV) ; + // distanza di approssimazione locale + double dDist ; + dpc.GetDist( dDist) ; + //if ( dDist > dErr) + // dErr = dDist ; + if ( dDist > dLinTol) { + bSplit = true ; + break ; + } + } } } - } - if ( dErr > dLinTol || dSideMaxVal > dSideMax) { - m_mTree[nCToSplit].SetSplitDirVert( bVert) ; - // effettuo lo split - Split( nCToSplit) ; + //if ( dErr > dLinTol || dSideMaxVal > dSideMax) { + if ( bSplit || dSideMaxVal > dSideMax) { + m_mTree[nCToSplit].SetSplitDirVert( bVert) ; + // effettuo lo split + Split( nCToSplit) ; - // procedo con lo split del Child1 - nCToSplit = m_mTree[nCToSplit].m_nChild1 ; - } - else { - // sono arrivato ad una cella Leaf, quindi salvo la cella - m_vnLeaves.push_back( nCToSplit) ; - m_mTree[nCToSplit].Processed() ; - // risalgo i parent finché non trovo il primo Child2 da processare - nCToSplit = m_mTree[nCToSplit].m_nParent ; - if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + // procedo con lo split del Child1 + nCToSplit = m_mTree[nCToSplit].m_nChild1 ; + } + else { + // sono arrivato ad una cella Leaf, quindi salvo la cella + m_vnLeaves.push_back( nCToSplit) ; m_mTree[nCToSplit].Processed() ; - while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { - if ( m_mTree[nCToSplit].m_nParent != -2) - nCToSplit = m_mTree[nCToSplit].m_nParent ; + // risalgo i parent finché non trovo il primo Child2 da processare + nCToSplit = m_mTree[nCToSplit].m_nParent ; if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) m_mTree[nCToSplit].Processed() ; - if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) - break ; + while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { + if ( m_mTree[nCToSplit].m_nParent != -2) + nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + m_mTree[nCToSplit].Processed() ; + if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + break ; + } + nCToSplit = m_mTree[nCToSplit].m_nChild2 ; } - nCToSplit = m_mTree[nCToSplit].m_nChild2 ; + } + else { + nCToSplit = m_mTree[nCToSplit].m_nChild1 ; } } - Balance( vBalanceCheck) ; // da implementare quando dividerò ad un parametro a scelta e non a metà + Balance() ; // da implementare quando dividerò ad un parametro a scelta e non a metà } // bilineare else { while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { - // vertici della cella - Point3d ptP00, ptP10, ptP11, ptP01 ; - ptP00 = m_mVert[nCToSplit][0] ; - ptP10 = m_mVert[nCToSplit][1] ; - ptP11 = m_mVert[nCToSplit][2] ; - ptP01 = m_mVert[nCToSplit][3] ; - - // distanza reale tra i vertici della cella - double dLen0 = Dist( ptP00, ptP10) ; - double dLen1 = Dist( ptP10, ptP11) ; - double dLen2 = Dist( ptP01, ptP11) ; - double dLen3 = Dist( ptP00, ptP01) ; - - // calcolo se è migliore la divisione in orizzontale o in verticale - Point3d ptP00P10, ptP00P01 , ptP01P11, ptP10P11 ; - ptP00P10 = ( ptP00 + ptP10) / 2 ; - ptP10P11 = ( ptP10 + ptP11) / 2 ; - ptP01P11 = ( ptP01 + ptP11) / 2 ; - ptP00P01 = ( ptP00 + ptP01) / 2 ; - bool bVert = false ; - - - //// questo calcolo è inutile perché confronto due cose che sono sempre uguali/////////////////////////////////////////////////////// - // calcolo se è meglio spezzare in orizzontale o in verticale - //double dErrVert1 = ( ( ptP00 - ptP01) + ( ptP01P11 - ptP00P10)).Len() ; - //double dErrVert2 = ( ( ptP00P10 - ptP01P11) + ( ptP11 - ptP10)).Len() ; - //double dErrOriz1 = ( ( ptP00P01 - ptP01) + ( ptP11 - ptP10P11)).Len() ; - //double dErrOriz2 = ( ( ptP00 - ptP00P01) + ( ptP10P11 - ptP10)).Len() ; - ////if (0 ) { - //if ( abs( dErrVert1 + dErrVert2 - dErrOriz1 - dErrOriz2) < EPS_SMALL && nCToSplit != -1) { - // bVert = ! m_mTree[m_mTree[nCToSplit].m_nParent].IsSplitVert() ; - //} - //else { - // if ( dErrVert1 + dErrVert2 > dErrOriz1 + dErrOriz2) { - // bVert = false ; - // } - // else { - // bVert = true ; - // } - //} - - // con questo esce la C sulla bilineare - // calcolo in quale direzione è meglio dividere in base allo stretch - Point3d ptPSrfU, ptPSrfV ; - double dU = 0, dV = 0 ; - double dDistU = 0, dDistV = 0 ; - double dULoc, dVLoc ; - PNTVECTOR vPtU, vPtV ; - if ( ! m_bMulti) { - if ( max(dLen0, dLen2) > max(dLen1, dLen3)) { - bVert = true ; - } - else { - bVert = false ; - } - } - else { - for ( double i = 0.25 ; i < 1 ; i = i + 0.25 ) { - /*Point3d ptU = ( 1 - i) * ptP00P01 + i * ptP10P11 ; - Point3d ptV = ( 1 - i) * ptP00P10 + i * ptP01P11 ;*/ - dU = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().x + i * m_mTree[nCToSplit].GetTopRight().x ; - dV = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().y + i * m_mTree[nCToSplit].GetTopRight().y ; - dVLoc = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 ; - dULoc = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 ; - m_pSrfBz->GetPointD1D2( dU, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfU) ; - m_pSrfBz->GetPointD1D2( dULoc, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfV) ; - //dDistU = max( Dist( ptU , ptPSrfU), dDistU) ; - //dDistV = max( Dist( ptV , ptPSrfV), dDistV) ; - vPtU.push_back(ptPSrfU) ; - vPtV.push_back(ptPSrfV) ; - } - // devo guardare se i tre punti in vPtU e vPtV sono allineati - CurveLine clU, clV; - clU.Set(vPtU[0], vPtU[1]) ; - clV.Set(vPtV[0], vPtV[1]) ; - DistPointCurve dpcU( vPtU[2], clU, false) ; - DistPointCurve dpcV( vPtV[2], clV, false) ; - dpcU.GetDist( dDistU) ; - dpcV.GetDist( dDistV) ; - if ( dDistU > dDistV ) { - bVert = true ; - } - else { - bVert = false ; - } - } - - // diagonali - //Point3d ptP00P11, ptP10P01, ptPSrf ; - //ptP00P11 = ( ptP00 + ptP11) / 2 ; - //ptP10P01 = ( ptP10 + ptP01) / 2 ; - //double dU = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 ; - //double dV = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 ; - //m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - //if ( Dist( ptP00P11, ptPSrf) > Dist( ptP10P01, ptPSrf)) - // bVert = false ; - //else - // bVert = true ; - - - - - // verifico che la cella sia abbastanza grande da poter essere splittata - double dSideMinVal = 0, dSideMaxVal = 0 ; - if ( bVert) { - if ( dLen0 != 0 && dLen2 != 0) - dSideMinVal = min( dLen0, dLen2) ; - else - dSideMinVal = max( dLen0, dLen2) ; - } - else { - if ( dLen1 != 0 && dLen3 != 0) - dSideMinVal = min( dLen1, dLen3) ; - else - dSideMinVal = max( dLen1, dLen3) ; - } - // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella - dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; - - - double dErr = 0 ; - if ( m_bMulti ) { - Point3d ptPSrf ; - Plane3d plAppr ; - plAppr.Set( ptP00, ( ptP00 - ptP01) ^ ( ptP00 - ptP10)) ; - for ( double i = 0.25 ; i < 1 ; i = i + 0.25) { - for ( double j = 0.25 ; j < 1 ; j = j + 0.25) { - double dU = ( 1 - i) * m_mTree[nCToSplit].GetTopRight().x + i * m_mTree[nCToSplit].GetBottomLeft().x ; - double dV = ( 1 - j) * m_mTree[nCToSplit].GetTopRight().y + j * m_mTree[nCToSplit].GetBottomLeft().y ; - m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - dErr = max( abs( DistPointPlane( ptPSrf, plAppr)), dErr) ; + if ( m_mTree[nCToSplit].IsLeaf()) { + // vertici della cella + Point3d ptP00, ptP10, ptP11, ptP01 ; + ptP00 = m_mVert[nCToSplit][0] ; + ptP10 = m_mVert[nCToSplit][1] ; + ptP11 = m_mVert[nCToSplit][2] ; + ptP01 = m_mVert[nCToSplit][3] ; + // distanza reale tra i vertici della cella + double dLen0 = Dist( ptP00, ptP10) ; + double dLen1 = Dist( ptP10, ptP11) ; + double dLen2 = Dist( ptP01, ptP11) ; + double dLen3 = Dist( ptP00, ptP01) ; + // calcolo se è migliore la divisione in orizzontale o in verticale + Point3d ptP00P10, ptP00P01 , ptP01P11, ptP10P11 ; + ptP00P10 = ( ptP00 + ptP10) / 2 ; + ptP10P11 = ( ptP10 + ptP11) / 2 ; + ptP01P11 = ( ptP01 + ptP11) / 2 ; + ptP00P01 = ( ptP00 + ptP01) / 2 ; + + bool bVert = false ; + // calcolo in quale direzione è meglio dividere in base allo stretch + Point3d ptPSrfU, ptPSrfV ; + double dU = 0, dV = 0 ; + double dDistU = 0, dDistV = 0 ; + double dULoc, dVLoc ; + PNTVECTOR vPtU, vPtV ; + if ( ! m_bMulti) { + if ( max(dLen0, dLen2) > max(dLen1, dLen3)) { + bVert = true ; + } + else { + bVert = false ; } } - } - else { - dErr = 1. / 4. * ( (ptP00 - ptP01) + (ptP11 - ptP10)).Len() ; - } - // se la cella è abbastanza grande da poter essere divisa ancora e devo approssimare meglio, la divido - if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && dErr > dLinTol) { - m_mTree[nCToSplit].SetSplitDirVert( bVert) ; - // effettuo lo split - Split( nCToSplit) ; + else { + for ( double i = 0.25 ; i < 1 ; i = i + 0.25 ) { + dU = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().x + i * m_mTree[nCToSplit].GetTopRight().x ; + dV = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().y + i * m_mTree[nCToSplit].GetTopRight().y ; + dVLoc = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 ; + dULoc = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 ; + m_pSrfBz->GetPointD1D2( dU, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfU) ; + m_pSrfBz->GetPointD1D2( dULoc, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfV) ; + vPtU.push_back( ptPSrfU) ; + vPtV.push_back( ptPSrfV) ; + } + // devo guardare se i tre punti in vPtU e vPtV sono allineati + CurveLine clU, clV; + clU.Set(vPtU[0], vPtU[1]) ; + clV.Set(vPtV[0], vPtV[1]) ; + DistPointCurve dpcU( vPtU[2], clU, false) ; + DistPointCurve dpcV( vPtV[2], clV, false) ; + dpcU.GetDist( dDistU) ; + dpcV.GetDist( dDistV) ; + if ( dDistU > dDistV) { + bVert = true ; + } + else { + bVert = false ; + } + } + + // verifico che la cella sia abbastanza grande da poter essere splittata + double dSideMinVal = 0, dSideMaxVal = 0 ; + if ( bVert) { + if ( dLen0 != 0 && dLen2 != 0) + dSideMinVal = min( dLen0, dLen2) ; + else + dSideMinVal = max( dLen0, dLen2) ; + } + else { + if ( dLen1 != 0 && dLen3 != 0) + dSideMinVal = min( dLen1, dLen3) ; + else + dSideMinVal = max( dLen1, dLen3) ; + } + // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella + dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; - // procedo con lo split del Child1 - nCToSplit = m_mTree[nCToSplit].m_nChild1 ; - } - else { - // sono arrivato ad una cella Leaf, quindi salvo la cella - m_vnLeaves.push_back( nCToSplit) ; - m_mTree[nCToSplit].Processed() ; - // risalgo i parent finché non trovo il primo Child2 da processare - nCToSplit = m_mTree[nCToSplit].m_nParent ; - if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + + double dErr = 0 ; + if ( m_bMulti) { + Point3d ptPSrf ; + Plane3d plAppr ; + if ( ! AreSamePointApprox( ptP00, ptP10) && ! AreSamePointApprox( ptP00, ptP01)) + plAppr.Set( ptP00, ( ptP00 - ptP01) ^ ( ptP00 - ptP10)) ; + else if ( AreSamePointApprox( ptP00, ptP10)) { + plAppr.Set( ptP01, ( ptP00 - ptP01) ^ ( ptP01 - ptP11)) ; + } + else if ( AreSamePointApprox( ptP00, ptP01)) { + plAppr.Set( ptP10, ( ptP10 - ptP11) ^ ( ptP00 - ptP10)) ; + } + for ( double i = 0.25 ; i < 1 ; i = i + 0.25) { + for ( double j = 0.25 ; j < 1 ; j = j + 0.25) { + double dU = ( 1 - i) * m_mTree[nCToSplit].GetTopRight().x + i * m_mTree[nCToSplit].GetBottomLeft().x ; + double dV = ( 1 - j) * m_mTree[nCToSplit].GetTopRight().y + j * m_mTree[nCToSplit].GetBottomLeft().y ; + m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + dErr = max( abs( DistPointPlane( ptPSrf, plAppr)), dErr) ; + } + } + } + else { + dErr = 1. / 4. * ( (ptP00 - ptP01) + (ptP11 - ptP10)).Len() ; + } + // se la cella è abbastanza grande da poter essere divisa ancora e devo approssimare meglio, la divido + if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && dErr > dLinTol) { + m_mTree[nCToSplit].SetSplitDirVert( bVert) ; + // effettuo lo split + Split( nCToSplit) ; + + // procedo con lo split del Child1 + nCToSplit = m_mTree[nCToSplit].m_nChild1 ; + } + else { + // sono arrivato ad una cella Leaf, quindi salvo la cella + m_vnLeaves.push_back( nCToSplit) ; m_mTree[nCToSplit].Processed() ; - while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { - if ( m_mTree[nCToSplit].m_nParent != -2) - nCToSplit = m_mTree[nCToSplit].m_nParent ; + // risalgo i parent finché non trovo il primo Child2 da processare + nCToSplit = m_mTree[nCToSplit].m_nParent ; if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) m_mTree[nCToSplit].Processed() ; - if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) - break ; + while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { + if ( m_mTree[nCToSplit].m_nParent != -2) + nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + m_mTree[nCToSplit].Processed() ; + if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + break ; + } + nCToSplit = m_mTree[nCToSplit].m_nChild2 ; } - nCToSplit = m_mTree[nCToSplit].m_nChild2 ; + } + else { + nCToSplit = m_mTree[nCToSplit].m_nChild1 ; } } } @@ -572,7 +614,7 @@ bool Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) } //---------------------------------------------------------------------------- -void Tree::Balance( INTVECTOR vCheck) +void Tree::Balance() { //for ( int i : vCheck ) { // // non ancora implementato @@ -652,12 +694,13 @@ void Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) vector vCells ; for ( int k : vTopNeighs) vCells.push_back( m_mTree[k]) ; - sort( vCells.begin(), vCells.end(), Cell::minorX ) ; + std::sort( vCells.begin(), vCells.end(), Cell::minorX) ; vTopNeighs.clear() ; for ( Cell c : vCells) vTopNeighs.push_back( c.m_nId) ; } + //---------------------------------------------------------------------------- void Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) { @@ -730,7 +773,7 @@ void Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) vector vCells ; for ( int k : vBottomNeighs) vCells.push_back( m_mTree[k]) ; - sort( vCells.begin(), vCells.end(), Cell::minorX) ; + std::sort( vCells.begin(), vCells.end(), Cell::minorX) ; vBottomNeighs.clear() ; for ( Cell c : vCells) vBottomNeighs.push_back( c.m_nId) ; @@ -809,7 +852,7 @@ void Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) vector vCells ; for ( int k : vLeftNeighs) vCells.push_back( m_mTree[k]) ; - sort( vCells.begin(), vCells.end(), Cell::minorY) ; + std::sort( vCells.begin(), vCells.end(), Cell::minorY) ; vLeftNeighs.clear() ; for ( Cell c : vCells) vLeftNeighs.push_back( c.m_nId) ; @@ -887,7 +930,7 @@ void Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) vector vCells ; for ( int k : vRightNeighs) vCells.push_back( m_mTree[k]) ; - sort( vCells.begin(), vCells.end(), Cell::minorY) ; + std::sort( vCells.begin(), vCells.end(), Cell::minorY) ; vRightNeighs.clear() ; for ( Cell c : vCells) vRightNeighs.push_back( c.m_nId) ; @@ -896,35 +939,41 @@ void Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) //---------------------------------------------------------------------------- int Tree::GetHeightLeaves( int nId, INTVECTOR& vnLeaves, int d) { - if ( (int) vnLeaves.size() == 0) { - if ( m_mTree[nId].IsLeaf()) - return d ; - else { - vnLeaves.push_back( m_mTree[nId].m_nChild1) ; - vnLeaves.push_back( m_mTree[nId].m_nChild2) ; - if ( ! m_mTree[m_mTree[nId].m_nChild1].IsLeaf() || ! m_mTree[m_mTree[nId].m_nChild2].IsLeaf()) - // almeno un child non è leaf quindi devo richiamare ricorsivamente questa funzione sui child in questione - d = GetHeightLeaves( nId, vnLeaves, m_mTree[m_mTree[nId].m_nChild1].m_nDepth) ; - } + if ( nId == -1 && m_mTree[-1].IsLeaf()) { + vnLeaves.push_back( -1) ; + return 0 ; } else { - for ( int j = 0 ; j != (int) vnLeaves.size() ; ++ j) { - int i = vnLeaves[j] ; - if ( m_mTree[i].IsLeaf() ) { - continue ; - } + if ( (int) vnLeaves.size() == 0) { + if ( m_mTree[nId].IsLeaf()) + return d ; else { - // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child - vnLeaves.erase( remove( vnLeaves.begin(),vnLeaves.end(),i)) ; - -- j ; - vnLeaves.push_back( m_mTree[i].m_nChild1) ; - vnLeaves.push_back( m_mTree[i].m_nChild2) ; - d = max ( d, m_mTree[m_mTree[i].m_nChild1].m_nDepth) ; + vnLeaves.push_back( m_mTree[nId].m_nChild1) ; + vnLeaves.push_back( m_mTree[nId].m_nChild2) ; + if ( ! m_mTree[m_mTree[nId].m_nChild1].IsLeaf() || ! m_mTree[m_mTree[nId].m_nChild2].IsLeaf()) + // almeno un child non è leaf quindi devo richiamare ricorsivamente questa funzione sui child in questione + d = GetHeightLeaves( nId, vnLeaves, m_mTree[m_mTree[nId].m_nChild1].m_nDepth) ; } } - return d ; + else { + for ( int j = 0 ; j != (int) vnLeaves.size() ; ++ j) { + int i = vnLeaves[j] ; + if ( m_mTree[i].IsLeaf() ) { + continue ; + } + else { + // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child + vnLeaves.erase( remove( vnLeaves.begin(),vnLeaves.end(),i)) ; + -- j ; + vnLeaves.push_back( m_mTree[i].m_nChild1) ; + vnLeaves.push_back( m_mTree[i].m_nChild2) ; + d = max ( d, m_mTree[m_mTree[i].m_nChild1].m_nDepth) ; + } + } + return d ; + } + return d - m_mTree[nId].m_nDepth ; } - return d - m_mTree[nId].m_nDepth ; } //---------------------------------------------------------------------------- @@ -974,7 +1023,7 @@ bool Tree::GetPolygons( POLYLINEVECTOR& vPolygons) vNeigh.clear() ; vVertices.push_back( m_mTree[nId].GetTopRight()) ; GetTopNeigh ( nId, vNeigh) ; - reverse( vNeigh.begin(), vNeigh.end()) ; + std::reverse( vNeigh.begin(), vNeigh.end()) ; // aggiungo i vertici che sono sul lato top, solo se ho più di un vicino top if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) { for ( int j : vNeigh) @@ -985,7 +1034,7 @@ bool Tree::GetPolygons( POLYLINEVECTOR& vPolygons) bTopLeft = false ; vNeigh.clear() ; GetLeftNeigh ( nId, vNeigh) ; - reverse( vNeigh.begin(), vNeigh.end()) ; + std::reverse( vNeigh.begin(), vNeigh.end()) ; // aggiungo i vertici che sono sul lato left, solo se ho più di un vicino left if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) { for ( int j : vNeigh) diff --git a/Tree.h b/Tree.h index 00f73bf..7ccbc33 100644 --- a/Tree.h +++ b/Tree.h @@ -48,6 +48,7 @@ class Cell int m_nRight ; // cella adiacente al lato right int m_nParent ; // cella genitore int m_nDepth ; // profondità della cella rispetto a root + double m_dSplit ; // parametro a cui è stata splittata la cella int m_nChild1 ; // prima cella figlio int m_nChild2 ; // seconda cella figlio @@ -56,7 +57,6 @@ class Cell Point3d m_ptPtr ; // punto top right bool m_bProcessed ; // flag che indica se la cella è stata processata bool m_bSplitVert ; // flag che indica in quale direzione è stata divisa la cella - double m_dSplit ; // parametro a cui è stata splittata la cella } ; //---------------------------------------------------------------------------- @@ -66,7 +66,7 @@ public : ~Tree( void) ; Tree( void) ; Tree ( const SurfBezier* pSrfBz, bool bSplitPatches = false) ; - void SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches = false) ; + void SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches = true) ; bool BuildTree( double dLinTol = LIN_TOL_STD, double dSideMin = 5, 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 GetPolygons( POLYLINEVECTOR& vPolygons) ; @@ -74,7 +74,7 @@ public : private : void Split( int nId, double dSplitValue) ; // funzione di split di una cella al parametro indicato nella direzione data da bVert void Split( int nId) ; // funzione di split di una cella dell'albero a metà nella direzione data da bVert - void Balance ( INTVECTOR vCheck) ; // creo rami in modo che tutte tutte le foglie abbiano come adiacenti foglie ad una profonditù di +- 1 + void Balance () ; // creo rami in modo che tutte tutte le foglie abbiano come adiacenti foglie ad una profonditù di +- 1 int GetHeightLeaves ( int nId, INTVECTOR& vnLeaves, int d = 0) ; // altezza del subtree a partire dal nodo nId int GetDepth ( int nId, int nRef) ; // livello del nodo nId void GetTopNeigh( int nId, INTVECTOR& vTopNeighs) ; // restituisce le celle foglie che sono adiacenti al lato top From f0429aefa491b35f51cd926ea81c224291b8762f Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Thu, 18 May 2023 15:07:27 +0200 Subject: [PATCH 06/44] EgtGeomKernel : - migliorata la robustezza per il calcolo della curvatura - pulizia del codice Da aggiungere : - gestione trim. --- Tree.cpp | 400 ++++++++++++++++++++++++++++++------------------------- Tree.h | 35 ++--- 2 files changed, 237 insertions(+), 198 deletions(-) diff --git a/Tree.cpp b/Tree.cpp index bce006f..3ef45ea 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -34,9 +34,9 @@ Cell::Cell( void) //---------------------------------------------------------------------------- -Cell::Cell( Point3d ptBL, Point3d ptTR) +Cell::Cell( Point3d& ptBL, 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_ptPbl( ptBL), m_ptPtr(ptTR), m_bProcessed ( false) , m_bSplitVert ( true) + m_nChild1( -2), m_nChild2( -2), m_ptPbl( ptBL), m_ptPtr( ptTR), m_bProcessed ( false) , m_bSplitVert ( true) {} @@ -47,7 +47,7 @@ Cell::~Cell( void) //---------------------------------------------------------------------------- inline bool -Cell::IsSame( Cell cOtherCell) const +Cell::IsSame( const Cell& cOtherCell) const { if ( m_nId == cOtherCell.m_nId) return true ; @@ -95,14 +95,17 @@ void Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) bool bIsRat, bTrimmed ; m_pSrfBz->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bIsRat, bTrimmed) ; m_bTrimmed = bTrimmed ; + m_nDegU = nDegU ; + m_nDegV = nDegV ; if ( nDegU == 1 && nDegV == 1) m_bBilinear = true ; if ( nSpanU * nSpanV != 1) m_bMulti = true ; // salvo i vertici 3d della cella root + Point3d ptBottom ( 0, 0) ; Point3d ptTop( nSpanU, nSpanV) ; - Cell cRoot( ORIG, ptTop) ; + Cell cRoot( ptBottom, ptTop) ; m_mTree.insert( pair< int, Cell>( -1, cRoot)) ; Point3d ptP00, ptP10, ptP11, ptP01 ; bool bOk = false ; @@ -224,7 +227,7 @@ Tree::Split( int nId, 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 devo impedire che si facciano split troppo vicini al bordo!!!!!!!!!!!!!!!!!!! + // per lo split a parametro libero dovrò impedire che si facciano split troppo vicini al bordo!!!!!!!!!!!!!!!!!!! m_mTree[nId].m_dSplit = dSplitValue ; Cell cChild1, cChild2 ; cChild1.m_nDepth = m_mTree[nId].m_nDepth + 1 ; @@ -330,21 +333,65 @@ bool Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) if ( m_mTree[nCToSplit].IsLeaf()) { // calcolo in quale direzione ho più curvatura // ptP00P10 è un punto tra P00 e P10 - double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; - double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; - double dULoc = 0.5, dVLoc = 0.5 ; - Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00 ; - m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; - m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; - Point3d ptV = ( 1 - dULoc) * ptP00P10 + dULoc * ptP11P01 ; - Point3d ptU = ( 1 - dVLoc) * ptP10P11 + dVLoc * ptP01P00 ; - // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza - // misura approssimativa della curvatura in una direzione - double dCurvV = Dist( ptV, ptPSrf) ; - double dCurvU = Dist( ptU, ptPSrf) ; + double dCurvU = 0, dCurvV = 0 ; + double dLenParU = m_mTree[nCToSplit].GetTopRight().x - m_mTree[nCToSplit].GetBottomLeft().x ; + double dLenParV = m_mTree[nCToSplit].GetTopRight().y - m_mTree[nCToSplit].GetBottomLeft().y ; + if ( dLenParU <= 1. / m_nDegV || dLenParV <= 1. / m_nDegU) { + double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; + double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; + double dULoc = 0.5, dVLoc = 0.5 ; + Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00 ; + m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; + Point3d ptV = ( 1 - dULoc) * ptP00P10 + dULoc * ptP11P01 ; + Point3d ptU = ( 1 - dVLoc) * ptP10P11 + dVLoc * ptP01P00 ; + dCurvV = Dist( ptV, ptPSrf) ; + dCurvU = Dist( ptU, ptPSrf) ; + } + // faccio un'analisi più fine della curvatura se almeno il grado di una curva di uno dei due parametri è alto e + // se sto ancora guardando una cella abbastanza grande + else{ + Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00, ptPSrfMid; + double dStep = 1. / m_nDegU ; + for ( double k = dStep ; k < 1 ; k = k + dStep) { + double dU = k * m_mTree[nCToSplit].GetTopRight().x + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().x ; + double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; + m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + if ( k == 0.5) + ptPSrfMid = ptPSrf ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; + CurveLine clV ; + clV.Set( ptP00P10, ptP11P01) ; + DistPointCurve dpc( ptPSrf, clV) ; + double dDist ; + dpc.GetDist( dDist) ; + dCurvV = max( dCurvV, dDist) ; + } + dStep = 1. / m_nDegV ; + for ( double k = dStep ; k < 1 ; k = k + dStep) { + double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; + double dV = k * m_mTree[nCToSplit].GetTopRight().y + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().y ; + if ( k == 0.5) + ptPSrf = ptPSrfMid ; + else + m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; + CurveLine clU ; + clU.Set( ptP01P00, ptP10P11) ; + DistPointCurve dpc( ptPSrf, clU) ; + double dDist ; + dpc.GetDist( dDist) ; + dCurvU = max( dCurvU, dDist) ; + } + } + + // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza + // misura approssimativa della curvatura in una direzione bool bVert ; if ( dCurvV > dCurvU) { // lungo la direzione V ho una curvatura maggiore @@ -383,7 +430,6 @@ bool Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; // se la cella è abbastanza grande da poter essere divisa ancora, calcolo l'errore di approssimazione - double dErr = 0 ; bool bSplit = false ; if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && ( dCurvV > dLinTol || dCurvU > dLinTol)) { CurveLine cl0010, cl0001, cl1011, cl0111 ; @@ -403,8 +449,8 @@ bool Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) int nStepsU = int( 51 * dDimU + 5 * ( 1 - dDimU)) ; int nStepsV = int( 51 * dDimV + 5 * ( 1 - dDimV)) ; for ( int u = 0 ; u < nStepsU && ! bSplit ; ++ u) { - dU = double ( u) / double ( nStepsU - 1) ; - dULoc = ( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x ; + double dU = double ( u) / double ( nStepsU - 1) ; + double dULoc = ( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x ; if ( ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz0) || ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz1)) return false ; @@ -414,16 +460,14 @@ bool Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) dpc0111.GetMinDistPoint( 0, pt0111, nFlag) ; clV.Set( pt0010, pt0111) ; for ( int v = 0 ; v < nStepsV ; ++ v) { - dV = double ( v) / double ( nStepsV - 1) ; - dVLoc = ( 1 - dV) * m_mTree[nCToSplit].GetBottomLeft().y + dV * m_mTree[nCToSplit].GetTopRight().y ; + double dV = double ( v) / double ( nStepsV - 1) ; + double dVLoc = ( 1 - dV) * m_mTree[nCToSplit].GetBottomLeft().y + dV * m_mTree[nCToSplit].GetTopRight().y ; if ( ! m_pSrfBz->GetPointD1D2( dULoc, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBzV)) return false ; DistPointCurve dpc( ptBzV, clV) ; // distanza di approssimazione locale double dDist ; dpc.GetDist( dDist) ; - //if ( dDist > dErr) - // dErr = dDist ; if ( dDist > dLinTol) { bSplit = true ; break ; @@ -432,7 +476,6 @@ bool Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) } } - //if ( dErr > dLinTol || dSideMaxVal > dSideMax) { if ( bSplit || dSideMaxVal > dSideMax) { m_mTree[nCToSplit].SetSplitDirVert( bVert) ; // effettuo lo split @@ -481,19 +524,12 @@ bool Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) double dLen1 = Dist( ptP10, ptP11) ; double dLen2 = Dist( ptP01, ptP11) ; double dLen3 = Dist( ptP00, ptP01) ; - // calcolo se è migliore la divisione in orizzontale o in verticale - Point3d ptP00P10, ptP00P01 , ptP01P11, ptP10P11 ; - ptP00P10 = ( ptP00 + ptP10) / 2 ; - ptP10P11 = ( ptP10 + ptP11) / 2 ; - ptP01P11 = ( ptP01 + ptP11) / 2 ; - ptP00P01 = ( ptP00 + ptP01) / 2 ; bool bVert = false ; // calcolo in quale direzione è meglio dividere in base allo stretch Point3d ptPSrfU, ptPSrfV ; double dU = 0, dV = 0 ; double dDistU = 0, dDistV = 0 ; - double dULoc, dVLoc ; PNTVECTOR vPtU, vPtV ; if ( ! m_bMulti) { if ( max(dLen0, dLen2) > max(dLen1, dLen3)) { @@ -507,8 +543,8 @@ bool Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) for ( double i = 0.25 ; i < 1 ; i = i + 0.25 ) { dU = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().x + i * m_mTree[nCToSplit].GetTopRight().x ; dV = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().y + i * m_mTree[nCToSplit].GetTopRight().y ; - dVLoc = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 ; - dULoc = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 ; + double dVLoc = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 ; + double dULoc = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 ; m_pSrfBz->GetPointD1D2( dU, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfU) ; m_pSrfBz->GetPointD1D2( dULoc, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfV) ; vPtU.push_back( ptPSrfU) ; @@ -623,37 +659,37 @@ void Tree::Balance() } //---------------------------------------------------------------------------- -void Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) +void Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) const { if ( (int) vTopNeighs.size() == 0) { - if ( m_mTree[nId].m_nTop == -2) + if ( m_mTree.at(nId).m_nTop == -2) return ; - if ( m_mTree[m_mTree[nId].m_nTop].IsLeaf()) - vTopNeighs.push_back( m_mTree[nId].m_nTop) ; + if ( m_mTree.at(m_mTree.at(nId).m_nTop).IsLeaf()) + vTopNeighs.push_back( m_mTree.at(nId).m_nTop) ; else { - if ( m_mTree[m_mTree[nId].m_nTop].IsSplitVert()) { + if ( m_mTree.at(m_mTree.at(nId).m_nTop).IsSplitVert()) { // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima - if ( m_mTree[m_mTree[nId].m_nTop].GetTopRight().x - m_mTree[m_mTree[nId].m_nTop].GetBottomLeft().x <= - m_mTree[nId].GetTopRight().x - m_mTree[nId].GetBottomLeft().x) { - vTopNeighs.push_back( m_mTree[m_mTree[nId].m_nTop].m_nChild1) ; - vTopNeighs.push_back( m_mTree[m_mTree[nId].m_nTop].m_nChild2) ; + if ( m_mTree.at(m_mTree.at(nId).m_nTop).GetTopRight().x - m_mTree.at(m_mTree.at(nId).m_nTop).GetBottomLeft().x <= + m_mTree.at(nId).GetTopRight().x - m_mTree.at(nId).GetBottomLeft().x) { + vTopNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild1) ; + vTopNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else{ - if ( m_mTree[m_mTree[m_mTree[nId].m_nTop].m_nChild1].GetTopRight().x <= m_mTree[nId].GetBottomLeft().x || - m_mTree[m_mTree[m_mTree[nId].m_nTop].m_nChild1].GetBottomLeft().x >= m_mTree[nId].GetTopRight().x ) - vTopNeighs.push_back( m_mTree[m_mTree[nId].m_nTop].m_nChild2) ; + if ( m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild1).GetTopRight().x <= m_mTree.at(nId).GetBottomLeft().x || + m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild1).GetBottomLeft().x >= m_mTree.at(nId).GetTopRight().x ) + vTopNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild2) ; else - vTopNeighs.push_back( m_mTree[m_mTree[nId].m_nTop].m_nChild1) ; + vTopNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild1) ; } } else { - vTopNeighs.push_back( m_mTree[m_mTree[nId].m_nTop].m_nChild2) ; + vTopNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild2) ; } } bool bAllLeaves = true ; for ( int i : vTopNeighs ) { - if ( ! m_mTree[i].IsLeaf()) + if ( ! m_mTree.at(i).IsLeaf()) bAllLeaves = false ; } if ( ! bAllLeaves ) @@ -662,38 +698,38 @@ void Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) } else { for ( int j = 0 ; j != (int) vTopNeighs.size() ; ++ j) { - int i = vTopNeighs[j] ; - if ( m_mTree[i].IsLeaf()) + int i = vTopNeighs.at(j) ; + if ( m_mTree.at(i).IsLeaf()) continue; else { // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child vTopNeighs.erase( remove( vTopNeighs.begin(),vTopNeighs.end(),i)) ; -- j ; - if ( m_mTree[i].IsSplitVert() ) { + if ( m_mTree.at(i).IsSplitVert() ) { // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima - if ( m_mTree[i].GetTopRight().x - m_mTree[i].GetBottomLeft().x <= - m_mTree[nId].GetTopRight().x - m_mTree[nId].GetBottomLeft().x) { - vTopNeighs.push_back( m_mTree[i].m_nChild1) ; - vTopNeighs.push_back( m_mTree[i].m_nChild2) ; + if ( m_mTree.at(i).GetTopRight().x - m_mTree.at(i).GetBottomLeft().x <= + m_mTree.at(nId).GetTopRight().x - m_mTree.at(nId).GetBottomLeft().x) { + vTopNeighs.push_back( m_mTree.at(i).m_nChild1) ; + vTopNeighs.push_back( m_mTree.at(i).m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else { - if ( m_mTree[m_mTree[i].m_nChild1].GetTopRight().x <= m_mTree[nId].GetBottomLeft().x || - m_mTree[m_mTree[i].m_nChild1].GetBottomLeft().x >= m_mTree[nId].GetTopRight().x ) - vTopNeighs.push_back( m_mTree[i].m_nChild2) ; + if ( m_mTree.at(m_mTree.at(i).m_nChild1).GetTopRight().x <= m_mTree.at(nId).GetBottomLeft().x || + m_mTree.at(m_mTree.at(i).m_nChild1).GetBottomLeft().x >= m_mTree.at(nId).GetTopRight().x ) + vTopNeighs.push_back( m_mTree.at(i).m_nChild2) ; else - vTopNeighs.push_back( m_mTree[i].m_nChild1) ; + vTopNeighs.push_back( m_mTree.at(i).m_nChild1) ; } } else { - vTopNeighs.push_back( m_mTree[i].m_nChild2) ; + vTopNeighs.push_back( m_mTree.at(i).m_nChild2) ; } } } } vector vCells ; for ( int k : vTopNeighs) - vCells.push_back( m_mTree[k]) ; + vCells.push_back( m_mTree.at(k)) ; std::sort( vCells.begin(), vCells.end(), Cell::minorX) ; vTopNeighs.clear() ; for ( Cell c : vCells) @@ -702,37 +738,37 @@ void Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) //---------------------------------------------------------------------------- -void Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) +void Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) const { if ( (int) vBottomNeighs.size() == 0) { - if ( m_mTree[nId].m_nBottom == -2) + if ( m_mTree.at(nId).m_nBottom == -2) return ; - if ( m_mTree[m_mTree[nId].m_nBottom].IsLeaf()) - vBottomNeighs.push_back( m_mTree[nId].m_nBottom) ; + if ( m_mTree.at(m_mTree.at(nId).m_nBottom).IsLeaf()) + vBottomNeighs.push_back( m_mTree.at(nId).m_nBottom) ; else { - if ( m_mTree[m_mTree[nId].m_nBottom].IsSplitVert()) { + if ( m_mTree.at(m_mTree.at(nId).m_nBottom).IsSplitVert()) { // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima - if ( m_mTree[m_mTree[nId].m_nBottom].GetTopRight().x - m_mTree[m_mTree[nId].m_nBottom].GetBottomLeft().x <= - m_mTree[nId].GetTopRight().x - m_mTree[nId].GetBottomLeft().x) { - vBottomNeighs.push_back( m_mTree[m_mTree[nId].m_nBottom].m_nChild1) ; - vBottomNeighs.push_back( m_mTree[m_mTree[nId].m_nBottom].m_nChild2) ; + if ( m_mTree.at(m_mTree.at(nId).m_nBottom).GetTopRight().x - m_mTree.at(m_mTree.at(nId).m_nBottom).GetBottomLeft().x <= + m_mTree.at(nId).GetTopRight().x - m_mTree.at(nId).GetBottomLeft().x) { + vBottomNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild1) ; + vBottomNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else{ - if ( m_mTree[m_mTree[m_mTree[nId].m_nBottom].m_nChild1].GetTopRight().x <= m_mTree[nId].GetBottomLeft().x || - m_mTree[m_mTree[m_mTree[nId].m_nBottom].m_nChild1].GetBottomLeft().x >= m_mTree[nId].GetTopRight().x ) - vBottomNeighs.push_back( m_mTree[m_mTree[nId].m_nBottom].m_nChild2) ; + if ( m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild1).GetTopRight().x <= m_mTree.at(nId).GetBottomLeft().x || + m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild1).GetBottomLeft().x >= m_mTree.at(nId).GetTopRight().x ) + vBottomNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild2) ; else - vBottomNeighs.push_back( m_mTree[m_mTree[nId].m_nBottom].m_nChild1) ; + vBottomNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild1) ; } } else { - vBottomNeighs.push_back( m_mTree[m_mTree[nId].m_nBottom].m_nChild1) ; + vBottomNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild1) ; } } bool bAllLeaves = true ; for ( int i : vBottomNeighs) { - if ( ! m_mTree[i].IsLeaf()) + if ( ! m_mTree.at(i).IsLeaf()) bAllLeaves = false ; } if ( ! bAllLeaves ) @@ -741,38 +777,38 @@ void Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) } else { for ( int j = 0 ; j != (int) vBottomNeighs.size() ; ++ j) { - int i = vBottomNeighs[j] ; - if ( m_mTree[i].IsLeaf()) + int i = vBottomNeighs.at(j) ; + if ( m_mTree.at(i).IsLeaf()) continue; else { // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child vBottomNeighs.erase( remove( vBottomNeighs.begin(),vBottomNeighs.end(),i)) ; -- j ; - if ( m_mTree[i].IsSplitVert()) { + if ( m_mTree.at(i).IsSplitVert()) { // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima - if ( m_mTree[i].GetTopRight().x - m_mTree[i].GetBottomLeft().x <= - m_mTree[nId].GetTopRight().x - m_mTree[nId].GetBottomLeft().x) { - vBottomNeighs.push_back( m_mTree[i].m_nChild1) ; - vBottomNeighs.push_back( m_mTree[i].m_nChild2) ; + if ( m_mTree.at(i).GetTopRight().x - m_mTree.at(i).GetBottomLeft().x <= + m_mTree.at(nId).GetTopRight().x - m_mTree.at(nId).GetBottomLeft().x) { + vBottomNeighs.push_back( m_mTree.at(i).m_nChild1) ; + vBottomNeighs.push_back( m_mTree.at(i).m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else { - if ( m_mTree[m_mTree[i].m_nChild1].GetTopRight().x <= m_mTree[nId].GetBottomLeft().x || - m_mTree[m_mTree[i].m_nChild1].GetBottomLeft().x >= m_mTree[nId].GetTopRight().x) - vBottomNeighs.push_back( m_mTree[i].m_nChild2) ; + if ( m_mTree.at(m_mTree.at(i).m_nChild1).GetTopRight().x <= m_mTree.at(nId).GetBottomLeft().x || + m_mTree.at(m_mTree.at(i).m_nChild1).GetBottomLeft().x >= m_mTree.at(nId).GetTopRight().x) + vBottomNeighs.push_back( m_mTree.at(i).m_nChild2) ; else - vBottomNeighs.push_back( m_mTree[i].m_nChild1) ; + vBottomNeighs.push_back( m_mTree.at(i).m_nChild1) ; } } else { - vBottomNeighs.push_back( m_mTree[i].m_nChild1) ; + vBottomNeighs.push_back( m_mTree.at(i).m_nChild1) ; } } } } vector vCells ; for ( int k : vBottomNeighs) - vCells.push_back( m_mTree[k]) ; + vCells.push_back( m_mTree.at(k)) ; std::sort( vCells.begin(), vCells.end(), Cell::minorX) ; vBottomNeighs.clear() ; for ( Cell c : vCells) @@ -781,37 +817,37 @@ void Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) //---------------------------------------------------------------------------- -void Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) +void Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) const { if ( (int) vLeftNeighs.size() == 0) { - if ( m_mTree[nId].m_nLeft == -2) + if ( m_mTree.at(nId).m_nLeft == -2) return ; - if ( m_mTree[m_mTree[nId].m_nLeft].IsLeaf()) - vLeftNeighs.push_back( m_mTree[nId].m_nLeft) ; + if ( m_mTree.at(m_mTree.at(nId).m_nLeft).IsLeaf()) + vLeftNeighs.push_back( m_mTree.at(nId).m_nLeft) ; else { - if ( ! m_mTree[m_mTree[nId].m_nLeft].IsSplitVert()) { + if ( ! m_mTree.at(m_mTree.at(nId).m_nLeft).IsSplitVert()) { // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima - if ( m_mTree[m_mTree[nId].m_nLeft].GetTopRight().y - m_mTree[m_mTree[nId].m_nLeft].GetBottomLeft().y <= - m_mTree[nId].GetTopRight().y - m_mTree[nId].GetBottomLeft().y) { - vLeftNeighs.push_back( m_mTree[m_mTree[nId].m_nLeft].m_nChild1) ; - vLeftNeighs.push_back( m_mTree[m_mTree[nId].m_nLeft].m_nChild2) ; + if ( m_mTree.at(m_mTree.at(nId).m_nLeft).GetTopRight().y - m_mTree.at(m_mTree.at(nId).m_nLeft).GetBottomLeft().y <= + m_mTree.at(nId).GetTopRight().y - m_mTree.at(nId).GetBottomLeft().y) { + vLeftNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild1) ; + vLeftNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else{ - if ( m_mTree[m_mTree[m_mTree[nId].m_nLeft].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || - m_mTree[m_mTree[m_mTree[nId].m_nLeft].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y) - vLeftNeighs.push_back( m_mTree[m_mTree[nId].m_nLeft].m_nChild2) ; + if ( m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild1).GetTopRight().y <= m_mTree.at(nId).GetBottomLeft().y || + m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild1).GetBottomLeft().y >= m_mTree.at(nId).GetTopRight().y) + vLeftNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild2) ; else - vLeftNeighs.push_back( m_mTree[m_mTree[nId].m_nLeft].m_nChild1) ; + vLeftNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild1) ; } } else { - vLeftNeighs.push_back( m_mTree[m_mTree[nId].m_nLeft].m_nChild2) ; + vLeftNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild2) ; } } bool bAllLeaves = true ; for ( int i : vLeftNeighs) { - if ( ! m_mTree[i].IsLeaf()) + if ( ! m_mTree.at(i).IsLeaf()) bAllLeaves = false ; } if ( ! bAllLeaves ) @@ -820,38 +856,38 @@ void Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) } else { for ( int j = 0 ; j != (int) vLeftNeighs.size() ; ++ j) { - int i = vLeftNeighs[j] ; - if ( m_mTree[i].IsLeaf()) + int i = vLeftNeighs.at(j) ; + if ( m_mTree.at(i).IsLeaf()) continue; else { // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child vLeftNeighs.erase( remove( vLeftNeighs.begin(),vLeftNeighs.end(),i)) ; -- j ; - if ( ! m_mTree[i].IsSplitVert()) { + if ( ! m_mTree.at(i).IsSplitVert()) { // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima - if ( m_mTree[i].GetTopRight().y - m_mTree[i].GetBottomLeft().y <= - m_mTree[nId].GetTopRight().y - m_mTree[nId].GetBottomLeft().y) { - vLeftNeighs.push_back( m_mTree[i].m_nChild1) ; - vLeftNeighs.push_back( m_mTree[i].m_nChild2) ; + if ( m_mTree.at(i).GetTopRight().y - m_mTree.at(i).GetBottomLeft().y <= + m_mTree.at(nId).GetTopRight().y - m_mTree.at(nId).GetBottomLeft().y) { + vLeftNeighs.push_back( m_mTree.at(i).m_nChild1) ; + vLeftNeighs.push_back( m_mTree.at(i).m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else { - if ( m_mTree[m_mTree[i].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || - m_mTree[m_mTree[i].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y) - vLeftNeighs.push_back( m_mTree[i].m_nChild2) ; + if ( m_mTree.at(m_mTree.at(i).m_nChild1).GetTopRight().y <= m_mTree.at(nId).GetBottomLeft().y || + m_mTree.at(m_mTree.at(i).m_nChild1).GetBottomLeft().y >= m_mTree.at(nId).GetTopRight().y) + vLeftNeighs.push_back( m_mTree.at(i).m_nChild2) ; else - vLeftNeighs.push_back( m_mTree[i].m_nChild1) ; + vLeftNeighs.push_back( m_mTree.at(i).m_nChild1) ; } } else { - vLeftNeighs.push_back( m_mTree[i].m_nChild2) ; + vLeftNeighs.push_back( m_mTree.at(i).m_nChild2) ; } } } } vector vCells ; for ( int k : vLeftNeighs) - vCells.push_back( m_mTree[k]) ; + vCells.push_back( m_mTree.at(k)) ; std::sort( vCells.begin(), vCells.end(), Cell::minorY) ; vLeftNeighs.clear() ; for ( Cell c : vCells) @@ -859,37 +895,37 @@ void Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) } //---------------------------------------------------------------------------- -void Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) +void Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) const { if ( (int) vRightNeighs.size() == 0) { - if ( m_mTree[nId].m_nRight == -2) + if ( m_mTree.at(nId).m_nRight == -2) return ; - if ( m_mTree[m_mTree[nId].m_nRight].IsLeaf()) - vRightNeighs.push_back( m_mTree[nId].m_nRight) ; + if ( m_mTree.at(m_mTree.at(nId).m_nRight).IsLeaf()) + vRightNeighs.push_back( m_mTree.at(nId).m_nRight) ; else { - if ( ! m_mTree[m_mTree[nId].m_nRight].IsSplitVert()) { + if ( ! m_mTree.at(m_mTree.at(nId).m_nRight).IsSplitVert()) { // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima - if ( m_mTree[m_mTree[nId].m_nRight].GetTopRight().y - m_mTree[m_mTree[nId].m_nRight].GetBottomLeft().y <= - m_mTree[nId].GetTopRight().y - m_mTree[nId].GetBottomLeft().y) { - vRightNeighs.push_back( m_mTree[m_mTree[nId].m_nRight].m_nChild1) ; - vRightNeighs.push_back( m_mTree[m_mTree[nId].m_nRight].m_nChild2) ; + if ( m_mTree.at(m_mTree.at(nId).m_nRight).GetTopRight().y - m_mTree.at(m_mTree.at(nId).m_nRight).GetBottomLeft().y <= + m_mTree.at(nId).GetTopRight().y - m_mTree.at(nId).GetBottomLeft().y) { + vRightNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild1) ; + vRightNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else{ - if ( m_mTree[m_mTree[m_mTree[nId].m_nRight].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || - m_mTree[m_mTree[m_mTree[nId].m_nRight].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y) - vRightNeighs.push_back( m_mTree[m_mTree[nId].m_nRight].m_nChild2) ; + if ( m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild1).GetTopRight().y <= m_mTree.at(nId).GetBottomLeft().y || + m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild1).GetBottomLeft().y >= m_mTree.at(nId).GetTopRight().y) + vRightNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild2) ; else - vRightNeighs.push_back( m_mTree[m_mTree[nId].m_nRight].m_nChild1) ; + vRightNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild1) ; } } else { - vRightNeighs.push_back( m_mTree[m_mTree[nId].m_nRight].m_nChild1) ; + vRightNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild1) ; } } bool bAllLeaves = true ; for ( int i : vRightNeighs) { - if ( ! m_mTree[i].IsLeaf()) + if ( ! m_mTree.at(i).IsLeaf()) bAllLeaves = false ; } if ( ! bAllLeaves ) @@ -898,38 +934,38 @@ void Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) } else { for ( int j = 0 ; j != (int) vRightNeighs.size() ; ++ j) { - int i = vRightNeighs[j] ; - if ( m_mTree[i].IsLeaf()) + int i = vRightNeighs.at(j) ; + if ( m_mTree.at(i).IsLeaf()) continue; else { // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child vRightNeighs.erase( remove( vRightNeighs.begin(),vRightNeighs.end(), i)) ; -- j ; - if ( ! m_mTree[i].IsSplitVert()) { + if ( ! m_mTree.at(i).IsSplitVert()) { // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima - if ( m_mTree[i].GetTopRight().y - m_mTree[i].GetBottomLeft().y <= - m_mTree[nId].GetTopRight().y - m_mTree[nId].GetBottomLeft().y) { - vRightNeighs.push_back( m_mTree[i].m_nChild1) ; - vRightNeighs.push_back( m_mTree[i].m_nChild2) ; + if ( m_mTree.at(i).GetTopRight().y - m_mTree.at(i).GetBottomLeft().y <= + m_mTree.at(nId).GetTopRight().y - m_mTree.at(nId).GetBottomLeft().y) { + vRightNeighs.push_back( m_mTree.at(i).m_nChild1) ; + vRightNeighs.push_back( m_mTree.at(i).m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else { - if ( m_mTree[m_mTree[i].m_nChild1].GetTopRight().y <= m_mTree[nId].GetBottomLeft().y || - m_mTree[m_mTree[i].m_nChild1].GetBottomLeft().y >= m_mTree[nId].GetTopRight().y) - vRightNeighs.push_back( m_mTree[i].m_nChild2) ; + if ( m_mTree.at(m_mTree.at(i).m_nChild1).GetTopRight().y <= m_mTree.at(nId).GetBottomLeft().y || + m_mTree.at(m_mTree.at(i).m_nChild1).GetBottomLeft().y >= m_mTree.at(nId).GetTopRight().y) + vRightNeighs.push_back( m_mTree.at(i).m_nChild2) ; else - vRightNeighs.push_back( m_mTree[i].m_nChild1) ; + vRightNeighs.push_back( m_mTree.at(i).m_nChild1) ; } } else { - vRightNeighs.push_back( m_mTree[i].m_nChild1) ; + vRightNeighs.push_back( m_mTree.at(i).m_nChild1) ; } } } } vector vCells ; for ( int k : vRightNeighs) - vCells.push_back( m_mTree[k]) ; + vCells.push_back( m_mTree.at(k)) ; std::sort( vCells.begin(), vCells.end(), Cell::minorY) ; vRightNeighs.clear() ; for ( Cell c : vCells) @@ -937,51 +973,51 @@ void Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) } //---------------------------------------------------------------------------- -int Tree::GetHeightLeaves( int nId, INTVECTOR& vnLeaves, int d) +int Tree::GetHeightLeaves( int nId, INTVECTOR& vnLeaves, int d) const { - if ( nId == -1 && m_mTree[-1].IsLeaf()) { + if ( nId == -1 && m_mTree.at(-1).IsLeaf()) { vnLeaves.push_back( -1) ; return 0 ; } else { if ( (int) vnLeaves.size() == 0) { - if ( m_mTree[nId].IsLeaf()) + if ( m_mTree.at(nId).IsLeaf()) return d ; else { - vnLeaves.push_back( m_mTree[nId].m_nChild1) ; - vnLeaves.push_back( m_mTree[nId].m_nChild2) ; - if ( ! m_mTree[m_mTree[nId].m_nChild1].IsLeaf() || ! m_mTree[m_mTree[nId].m_nChild2].IsLeaf()) + vnLeaves.push_back( m_mTree.at(nId).m_nChild1) ; + vnLeaves.push_back( m_mTree.at(nId).m_nChild2) ; + if ( ! m_mTree.at(m_mTree.at(nId).m_nChild1).IsLeaf() || ! m_mTree.at(m_mTree.at(nId).m_nChild2).IsLeaf()) // almeno un child non è leaf quindi devo richiamare ricorsivamente questa funzione sui child in questione - d = GetHeightLeaves( nId, vnLeaves, m_mTree[m_mTree[nId].m_nChild1].m_nDepth) ; + d = GetHeightLeaves( nId, vnLeaves, m_mTree.at(m_mTree.at(nId).m_nChild1).m_nDepth) ; } } else { for ( int j = 0 ; j != (int) vnLeaves.size() ; ++ j) { - int i = vnLeaves[j] ; - if ( m_mTree[i].IsLeaf() ) { + int i = vnLeaves.at(j) ; + if ( m_mTree.at(i).IsLeaf() ) { continue ; } else { // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child vnLeaves.erase( remove( vnLeaves.begin(),vnLeaves.end(),i)) ; -- j ; - vnLeaves.push_back( m_mTree[i].m_nChild1) ; - vnLeaves.push_back( m_mTree[i].m_nChild2) ; - d = max ( d, m_mTree[m_mTree[i].m_nChild1].m_nDepth) ; + vnLeaves.push_back( m_mTree.at(i).m_nChild1) ; + vnLeaves.push_back( m_mTree.at(i).m_nChild2) ; + d = max ( d, m_mTree.at(m_mTree.at(i).m_nChild1).m_nDepth) ; } } return d ; } - return d - m_mTree[nId].m_nDepth ; + return d - m_mTree.at(nId).m_nDepth ; } } //---------------------------------------------------------------------------- -int Tree::GetDepth( int nId, int nRef = -2) +int Tree::GetDepth( int nId, int nRef = -2) const { int c = 0 ; - while ( m_mTree[nId].m_nParent != nRef) { - nId = m_mTree[nId].m_nParent ; + while ( m_mTree.at(nId).m_nParent != nRef) { + nId = m_mTree.at(nId).m_nParent ; ++ c ; } return c ; @@ -998,12 +1034,12 @@ bool Tree::GetPolygons( POLYLINEVECTOR& vPolygons) for ( int nId : m_vnLeaves) { vVertices.clear() ; vNeigh.clear() ; - vVertices.push_back( m_mTree[nId].GetBottomLeft()) ; + vVertices.push_back( m_mTree.at(nId).GetBottomLeft()) ; GetBottomNeigh( nId, vNeigh) ; // aggiungo i vertici che sono sul lato bottom, solo se ho più di un vicino bottom if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1){ for ( int j : vNeigh ) - vVertices.push_back( m_mTree[j].GetTopRight()) ; + vVertices.push_back( m_mTree.at(j).GetTopRight()) ; bBottomRight = true ; } else @@ -1013,21 +1049,21 @@ bool Tree::GetPolygons( POLYLINEVECTOR& vPolygons) // aggiungo i vertici che sono sul lato right, solo se ho più di un vicino right if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1){ for ( int j : vNeigh ) - vVertices.push_back( m_mTree[j].GetBottomLeft()) ; + vVertices.push_back( m_mTree.at(j).GetBottomLeft()) ; } // se non l'ho già aggiunto tramite i vicini bottom aggiungo il punto bottom right else if ( ! bBottomRight ) { - Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + Point3d ptBr( m_mTree.at(nId).GetTopRight().x, m_mTree.at(nId).GetBottomLeft().y) ; vVertices.push_back( ptBr) ; } vNeigh.clear() ; - vVertices.push_back( m_mTree[nId].GetTopRight()) ; + vVertices.push_back( m_mTree.at(nId).GetTopRight()) ; GetTopNeigh ( nId, vNeigh) ; std::reverse( vNeigh.begin(), vNeigh.end()) ; // aggiungo i vertici che sono sul lato top, solo se ho più di un vicino top if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) { for ( int j : vNeigh) - vVertices.push_back( m_mTree[j].GetBottomLeft()) ; + vVertices.push_back( m_mTree.at(j).GetBottomLeft()) ; bTopLeft = true ; } else @@ -1038,39 +1074,39 @@ bool Tree::GetPolygons( POLYLINEVECTOR& vPolygons) // aggiungo i vertici che sono sul lato left, solo se ho più di un vicino left if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) { for ( int j : vNeigh) - vVertices.push_back( m_mTree[j].GetTopRight()) ; + vVertices.push_back( m_mTree.at(j).GetTopRight()) ; } // se non l'ho già aggiunto tramite i vicini top aggiungo il punto top left else if ( ! bTopLeft) { - Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + Point3d ptTl( m_mTree.at(nId).GetBottomLeft().x, m_mTree.at(nId).GetTopRight().y) ; vVertices.push_back( ptTl) ; } vNeigh.clear() ; - vVertices.push_back( m_mTree[nId].GetBottomLeft()) ; + vVertices.push_back( m_mTree.at(nId).GetBottomLeft()) ; // se ho una cella con vicino dello stesso grado ( quindi il poligono ha solo 5 punti) controllo la curvatura nella cella e // se necessario cambio l'ordine dei vertici per scegliere la diagonale di split migliore if ( vVertices.size() == 5) { Point3d ptPSrf, ptP00, ptP10, ptP11, ptP01; double dU, dV ; - dU = ( m_mTree[nId].GetBottomLeft().x + m_mTree[nId].GetTopRight().x) / 2 ; - dV = ( m_mTree[nId].GetBottomLeft().y + m_mTree[nId].GetTopRight().y) / 2 ; + dU = ( m_mTree.at(nId).GetBottomLeft().x + m_mTree.at(nId).GetTopRight().x) / 2 ; + dV = ( m_mTree.at(nId).GetBottomLeft().y + m_mTree.at(nId).GetTopRight().y) / 2 ; m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - ptP00 = m_mVert[nId][0] ; - ptP10 = m_mVert[nId][1] ; - ptP11 = m_mVert[nId][2] ; - ptP01 = m_mVert[nId][3] ; + ptP00 = m_mVert.at(nId).at(0) ; + ptP10 = m_mVert.at(nId).at(1) ; + ptP11 = m_mVert.at(nId).at(2) ; + ptP01 = m_mVert.at(nId).at(3) ; Point3d ptP00P11 = ( ptP00 + ptP11) / 2 ; Point3d ptP10P01 = ( ptP10 + ptP01) / 2 ; // ho la curvatura maggiore sulla diagonale tra P10 e P01, ruoto l'ordine dei vertici, in modo che triangulate prenda la diagonale giusta if ( Dist(ptP00P11, ptPSrf) + EPS_SMALL > Dist(ptP10P01, ptPSrf)) { rotate(vVertices.begin(), vVertices.begin() + 1,vVertices.end()) ; - vVertices.back() = vVertices[0] ; + vVertices.back() = vVertices.at(0) ; } } m_vPolygons.emplace_back() ; for ( int i = 0 ; i < (int) vVertices.size() ; ++i) { - m_vPolygons.back().AddUPoint( i, vVertices[i]) ; + m_vPolygons.back().AddUPoint( i, vVertices.at(i)) ; } } } diff --git a/Tree.h b/Tree.h index 7ccbc33..751c21f 100644 --- a/Tree.h +++ b/Tree.h @@ -24,18 +24,18 @@ class Cell public : ~Cell( void) ; Cell( void) ; - Cell( Point3d ptBL, Point3d ptTR) ; - inline bool IsSame( Cell cOtherCell) const ; + Cell( Point3d& ptBL, Point3d& ptTR) ; + inline bool IsSame( const Cell& cOtherCell) const ; void SetBottomLeft( Point3d ptBL) { m_ptPbl = ptBL ; } void SetTopRight( Point3d ptTR) { m_ptPtr = ptTR ; } void SetSplitDirVert( bool bVert) { m_bSplitVert = bVert ; } - void SetParent(int nParent) { m_nParent = nParent ; } + void SetParent( int nParent) { m_nParent = nParent ; } Point3d GetBottomLeft( void) const { return m_ptPbl ; } Point3d GetTopRight( void) const { return m_ptPtr ; } double GetSplitValue( void) const { return m_dSplit ; } - bool IsSplitVert( void) const { return m_bSplitVert ; } - bool IsLeaf( void) const ; - bool IsProcessed( void) const { return m_bProcessed ; } + bool IsSplitVert( void) const { return m_bSplitVert ; } // se true la cella verrebbe splittata verticalmente, sennò orizzontalmente + bool IsLeaf( void) const ; // flag che indica se la cella ha figli o se è una foglia + bool IsProcessed( void) const { return m_bProcessed ; } // flag che indica se tutti i figli della cella, se ce ne sono, sono stati processati void Processed( void) { m_bProcessed = true ; } static bool minorX ( const Cell& c1, const Cell& c2) { return c1.m_ptPbl.x < c2.m_ptPbl.x ; } static bool minorY ( const Cell& c1, const Cell& c2) { return c1.m_ptPbl.y < c2.m_ptPbl.y ; } @@ -69,18 +69,19 @@ public : void SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches = true) ; bool BuildTree( double dLinTol = LIN_TOL_STD, double dSideMin = 5, 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 GetPolygons( POLYLINEVECTOR& vPolygons) ; + bool GetPolygons( 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 private : - void Split( int nId, double dSplitValue) ; // funzione di split di una cella al parametro indicato nella direzione data da bVert - void Split( int nId) ; // funzione di split di una cella dell'albero a metà nella direzione data da bVert - void Balance () ; // creo rami in modo che tutte tutte le foglie abbiano come adiacenti foglie ad una profonditù di +- 1 - int GetHeightLeaves ( int nId, INTVECTOR& vnLeaves, int d = 0) ; // altezza del subtree a partire dal nodo nId - int GetDepth ( int nId, int nRef) ; // livello del nodo nId - void GetTopNeigh( int nId, INTVECTOR& vTopNeighs) ; // restituisce le celle foglie che sono adiacenti al lato top - void GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) ; // restituisce le celle foglie che sono adiacenti al lato bottom - void GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) ; // restituisce le celle foglie che sono adiacenti al lato left - void GetRightNeigh( int nId, INTVECTOR& vRightNeighs) ; // restituisce le celle foglie che sono adiacenti al lato right + void Split( int nId, double dSplitValue) ; // funzione di split di una cella al parametro indicato nella direzione data da bVert + void Split( int nId) ; // funzione di split di una cella dell'albero a metà nella direzione data da bVert + void Balance () ; // creo rami in modo che tutte tutte le foglie abbiano come adiacenti foglie ad una profonditù di +- 1 + int GetHeightLeaves ( int nId, INTVECTOR& vnLeaves, int d = 0) const ; // altezza del subtree a partire dal nodo nId + int GetDepth ( int nId, int nRef) const ; // livello del nodo nId + void GetTopNeigh( int nId, INTVECTOR& vTopNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato top + void GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato bottom + void GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato left + void GetRightNeigh( int nId, INTVECTOR& vRightNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato right private : const SurfBezier* m_pSrfBz ; // superficie di bezier @@ -89,6 +90,8 @@ private : bool m_bBilinear ; // superficie bilineare bool m_bMulti ; // superficie multi-patch bool m_bClosed ; // superficie chiusa + int m_nDegU ; // grado della superficie nel parametro U + int m_nDegV ; // grado della superficie nel parametro V POLYLINEVECTOR m_vPolygons ; // vettore dei poligoni del tree std::map m_mTree ; // mappa che contiene tutti i nodi e le foglie dell'albero. -2 è puntatore Null e -1 è root std::map m_mVert ; // mappa che contiene tutti i vertici 3d delle celle del tree. L'Id è lo stesso che la cella ha in m_mTree From e4243a2df30cecc90f0cbc8808eaacffa30e7ccb Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 29 May 2023 09:02:51 +0200 Subject: [PATCH 07/44] EgtGeomKernel : - implementato il trim dello spazio parametrico. Da aggiungere : - gestione delle celle non intersecate, interne ai loop Problematiche : - gestione di aree di trim nested in una cella --- EgtGeomKernel.vcxproj.filters | 3 + SurfBezier.cpp | 66 +- SurfBezier.h | 2 +- Tree.cpp | 1673 ++++++++++++++++++++++++++------- Tree.h | 72 +- 5 files changed, 1444 insertions(+), 372 deletions(-) diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index 13b53ad..ce7eb9f 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -473,6 +473,7 @@ File di origine\Base + File di origine\GeoInters @@ -1112,6 +1113,8 @@ File di intestazione + File di intestazione + File di intestazione diff --git a/SurfBezier.cpp b/SurfBezier.cpp index c1c5b3d..b0fb6c6 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -149,10 +149,12 @@ SurfBezier::SetTrimRegion( const ISurfFlatRegion& sfrTrimReg) } //---------------------------------------------------------------------------- -bool -SurfBezier::GetTrimRegion( ISurfFlatRegion& sfrTrimReg) +SurfFlatRegion* +SurfBezier::GetTrimRegion( void) const { - return true ; + if ( ! m_bTrimmed || m_pTrimReg == nullptr ) + return nullptr ; + return m_pTrimReg ; } //---------------------------------------------------------------------------- @@ -1228,39 +1230,62 @@ SurfBezier::GetCurveOnV( double dU) const CurveComposite* SurfBezier::GetLoop( int nLoop) const { - // Se superficie completa, basta concatenare le 4 isoparametriche di bordo - if ( ! m_bTrimmed) { - // Esiste solo il loop esterno - if ( nLoop != 0) + // Il primo loop sono le 4 isoparametriche di bordo concatenate + if ( ! m_bTrimmed ) { + if ( nLoop != 0 ) return nullptr ; - // Loop + // Loop PtrOwner pLoop( CreateBasicCurveComposite()) ; - // prima curva isoparametrica in U con V=0 + // prima curva isoparametrica in U con V=0 PtrOwner pCrvCoU0( GetCurveOnU( 0)) ; if ( ! IsNull( pCrvCoU0) && ! pCrvCoU0->IsAPoint()) pLoop->AddCurve( Release( pCrvCoU0)) ; - // seconda curva isoparametrica in V con U=m_nSpanU + // seconda curva isoparametrica in V con U=m_nSpanU PtrOwner pCrvCoV1( GetCurveOnV( m_nSpanU)) ; if ( ! IsNull( pCrvCoV1) && ! pCrvCoV1->IsAPoint()) pLoop->AddCurve( Release( pCrvCoV1)) ; - // terza curva isoparametrica in U con V=m_nSpanV invertita + // terza curva isoparametrica in U con V=m_nSpanV invertita PtrOwner pCrvCoU1( GetCurveOnU( m_nSpanV)) ; if ( ! IsNull( pCrvCoU1) && ! pCrvCoU1->IsAPoint()) { pCrvCoU1->Invert() ; pLoop->AddCurve( Release( pCrvCoU1)) ; } - // quarta curva isoparametrica in V con U=0 invertita + // quarta curva isoparametrica in V con U=0 invertita PtrOwner pCrvCoV0( GetCurveOnV( 0)) ; if ( ! IsNull( pCrvCoV0) && ! pCrvCoV0->IsAPoint()) { pCrvCoV0->Invert() ; pLoop->AddCurve( Release( pCrvCoV0)) ; } - // se loop chiuso lo restituisco, altrimenti errore + // se loop chiuso lo restituisco, altrimenti errore return ( pLoop->IsClosed() ? Release( pLoop) : nullptr) ; } - // altrimenti trimmata, per ora non gestita - else - return nullptr ; + // la superficie è trimmata, quindi devo cercare nei vari chunck il loop corrispondente + else { + if ( nLoop > m_pTrimReg->GetChunkCount()) + return nullptr ; + else { + int nLoopCount = 0 ; + int nChunck = 0, nLoopLoc = 0; + INTVECTOR nLoopCountPerChunck ; + for ( int i = 0 ; i < m_pTrimReg->GetChunkCount() && nLoopCount != nLoop ; ++ i) { + int nLoopCountLoc = 0 ; + for ( int j = 0 ; j < m_pTrimReg->GetLoopCount( i) ; ++ j) { + ++ nLoopCountLoc ; + ++ nLoopCount ; + if ( nLoopCount != nLoop ) { + nChunck = i ; + nLoopLoc = j ; + break ; + } + } + nLoopCountPerChunck.push_back( nLoopCountLoc) ; + } + if ( nLoopCount < nLoop ) + return nullptr ; + PtrOwner pLoop( GetBasicCurveComposite( m_pTrimReg->GetLoop( nChunck, nLoopLoc))) ; + return Release( pLoop) ; + } + } } //---------------------------------------------------------------------------- @@ -1473,21 +1498,22 @@ SurfBezier::GetAuxSurf( void) const return m_pSTM ; // costruttore della superficie + Tree Tree( this, true) ; Tree.BuildTree() ; - POLYLINEVECTOR vPL ; - Tree.GetPolygons( vPL) ; + vector vvPL ; + Tree.GetPolygons( vvPL) ; PtrOwner pSrfTm( CreateBasicSurfTriMesh()) ; StmFromTriangleSoup stmSoup ; if ( ! stmSoup.Start()) return nullptr ; // prendo i punti di ogni polyline dell'albero, li triangolo e li porto in 3d - for ( PolyLine i : vPL) { + for ( POLYLINEVECTOR vPL : vvPL) { PNTVECTOR vPnt ; INTVECTOR vTria ; Triangulate Tri ; - if ( ! Tri.Make( i, vPnt, vTria)) + if ( ! Tri.Make( vPL, vPnt, vTria)) return nullptr ; // porto i punti in 3d diff --git a/SurfBezier.h b/SurfBezier.h index 12149f8..6cfc9e2 100644 --- a/SurfBezier.h +++ b/SurfBezier.h @@ -83,7 +83,7 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW { return SetControlPoint( GetInd( nIndU, nIndV), ptCtrl, dW) ; } bool SetControlPoint( int nInd, const Point3d& ptCtrl, double dW) override ; bool SetTrimRegion( const ISurfFlatRegion& sfrTrimReg) override ; - bool GetTrimRegion( ISurfFlatRegion& sfrTrimReg) override ; + SurfFlatRegion* GetTrimRegion( void) const override ; bool GetInfo( int& nDegU, int& nDegV, int& nSpanU, int& nSpanV, bool& bIsRat, bool& bTrimmed) const override ; const Point3d& GetControlPoint( int nIndU, int nIndV, bool* pbOk) const override { return GetControlPoint( GetInd( nIndU, nIndV), pbOk) ; } diff --git a/Tree.cpp b/Tree.cpp index 3ef45ea..21a8aa1 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -18,15 +18,19 @@ #include "SurfBezier.h" #include "GeoConst.h" #include "CurveLine.h" +#include "CurveComposite.h" +#include "SurfFlatRegion.h" +#include "IntersLineLine.h" #include "/EgtDev/Include/EGkPolyLine.h" #include "/EgtDev/Include/EGkDistPointCurve.h" +#include "/EgtDev/Include/EGkCurve.h" using namespace std ; //---------------------------------------------------------------------------- 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_ptPbl( ORIG), m_ptPtr(), m_bProcessed ( false) , m_bSplitVert ( true) + m_nChild1( -2), m_nChild2( -2), m_nFlag( 0), m_nRightEdgeIn( 0), m_ptPbl(ORIG), m_ptPtr(), m_bProcessed(false), m_bSplitVert(true) { Point3d ptTr ( 1, 1) ; m_ptPtr = ptTr ; @@ -36,7 +40,7 @@ Cell::Cell( void) //---------------------------------------------------------------------------- Cell::Cell( Point3d& ptBL, 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_ptPbl( ptBL), m_ptPtr( ptTR), m_bProcessed ( false) , m_bSplitVert ( true) + m_nChild1( -2), m_nChild2( -2), m_nFlag( 0), m_nRightEdgeIn( 0), m_ptPbl(ptBL), m_ptPtr(ptTR), m_bProcessed(false), m_bSplitVert(true) {} @@ -87,7 +91,8 @@ Tree::~Tree( void) } //---------------------------------------------------------------------------- -void Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) +void +Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) { m_pSrfBz = pSrfBz ; // le coordinate delle celle sono nello spazio parametrico @@ -101,7 +106,56 @@ void Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) m_bBilinear = true ; if ( nSpanU * nSpanV != 1) m_bMulti = true ; - + // recupero i loop di trim e li divido per chunk + if ( m_bTrimmed) { + int nLoop = 0 ; + INTVECTOR vChunk ; + // dalla superficie recupero un vettore con i loop di trim + // + //PtrOwner pLoop( GetBasicCurveComposite( m_pSrfBz->GetLoop( nLoop))) ; + //while ( ! IsNull( pLoop) && pLoop->IsValid()) { + // if ( nLoop == 0) { + // m_vLoop.push_back( Release( pLoop)) ; + // vChunck.push_back( nLoop) ; + // ++ nLoop ; + // } + // else { + // // se il loop corrente è contenuto nel precedente e sono girati in verso opposto, allora lo aggiungo allo stesso chunk + // if ( ) { + + // } + // // salvo il precedente chunk e creo un nuovo chunk + // else { + // m_vChunk.push_back( vChunk) ; + // vChunk.clear() ; + // vChunk.push_back( nLoop) ; + // } + // ++ nLoop ; + // PtrOwner pLoop( GetBasicCurveComposite( m_pSrfBz->GetLoop( nLoop))) ; + // } + //} + + // recupero la superficie di trim per avere accesso diretto ai loop e mantenendo le informazioni sui chunk + + Frame3d frSurf ; + //const SurfFlatRegion* pTrimReg_( m_pSrfBz->GetTrimRegion()) ; + //PtrOwner pTrimReg( pTrimReg_->Clone()) ; + PtrOwner pTrimReg( m_pSrfBz->GetTrimRegion()->Clone()) ; + for ( int i = 0 ; i < pTrimReg->GetChunkCount() ; ++ i) { + PtrOwner pChunk( pTrimReg->CloneChunk( i)) ; + pChunk->Scale( frSurf, 1./ SBZ_TREG_COEFF, 1./ SBZ_TREG_COEFF, 1) ; + for ( int j = 0 ; j < pChunk->GetLoopCount( 0) ; ++ j) { + vChunk.push_back( nLoop) ; + // i chunk della superficie orignale non possono avere dei sub chunk + PtrOwner pLoop (pChunk->GetLoop(0, j)) ; + m_vLoop.emplace_back( Release( pLoop )) ; + m_mChunk[nLoop] = i ; + ++ nLoop ; + } + m_vChunk.push_back( vChunk) ; + vChunk.clear() ; + } + } // salvo i vertici 3d della cella root Point3d ptBottom ( 0, 0) ; Point3d ptTop( nSpanU, nSpanV) ; @@ -320,346 +374,390 @@ Tree::Split( int nId) } //---------------------------------------------------------------------------- -bool Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) +bool +Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) { - // suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri - int nCToSplit = -1 ; - double dLinTol = 0.2 ; - //double dSideMin = 1 ; - if ( ! m_bTrimmed) { - if ( ! m_bBilinear) { - while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { - // controllo che la cella non sia già stata preliminarmente splittata - if ( m_mTree[nCToSplit].IsLeaf()) { - // calcolo in quale direzione ho più curvatura - // ptP00P10 è un punto tra P00 e P10 - double dCurvU = 0, dCurvV = 0 ; - double dLenParU = m_mTree[nCToSplit].GetTopRight().x - m_mTree[nCToSplit].GetBottomLeft().x ; - double dLenParV = m_mTree[nCToSplit].GetTopRight().y - m_mTree[nCToSplit].GetBottomLeft().y ; - if ( dLenParU <= 1. / m_nDegV || dLenParV <= 1. / m_nDegU) { - double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; - double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; - double dULoc = 0.5, dVLoc = 0.5 ; - Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00 ; - m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; - m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; - Point3d ptV = ( 1 - dULoc) * ptP00P10 + dULoc * ptP11P01 ; - Point3d ptU = ( 1 - dVLoc) * ptP10P11 + dVLoc * ptP01P00 ; - dCurvV = Dist( ptV, ptPSrf) ; - dCurvU = Dist( ptU, ptPSrf) ; - } - // faccio un'analisi più fine della curvatura se almeno il grado di una curva di uno dei due parametri è alto e - // se sto ancora guardando una cella abbastanza grande - else{ - Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00, ptPSrfMid; - double dStep = 1. / m_nDegU ; - for ( double k = dStep ; k < 1 ; k = k + dStep) { - double dU = k * m_mTree[nCToSplit].GetTopRight().x + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().x ; - double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; - m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - if ( k == 0.5) - ptPSrfMid = ptPSrf ; - m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; - m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; - CurveLine clV ; - clV.Set( ptP00P10, ptP11P01) ; - DistPointCurve dpc( ptPSrf, clV) ; - double dDist ; - dpc.GetDist( dDist) ; - dCurvV = max( dCurvV, dDist) ; - } - dStep = 1. / m_nDegV ; - for ( double k = dStep ; k < 1 ; k = k + dStep) { - double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; - double dV = k * m_mTree[nCToSplit].GetTopRight().y + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().y ; - if ( k == 0.5) - ptPSrf = ptPSrfMid ; - else - m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; - CurveLine clU ; - clU.Set( ptP01P00, ptP10P11) ; - DistPointCurve dpc( ptPSrf, clU) ; - double dDist ; - dpc.GetDist( dDist) ; - dCurvU = max( dCurvU, dDist) ; - } - } + //int nCToSplit = -1 ; + //celle 0,1 + m_mTree[-1].SetSplitDirVert( true) ; + Split( -1) ; + //celle 2,3 + m_mTree[0].SetSplitDirVert( false) ; + Split( 0) ; + //celle 4,5 + m_mTree[2].SetSplitDirVert( false) ; + Split( 2) ; + //celle 6,7 + m_mTree[3].SetSplitDirVert( true) ; + Split( 3) ; + //celle 8,9 + m_mTree[1].SetSplitDirVert( false) ; + Split( 1) ; + //celle 10,11 + m_mTree[8].SetSplitDirVert( true) ; + Split( 8) ; + //celle 12,13 + m_mTree[9].SetSplitDirVert( false) ; + Split( 9) ; + m_vnLeaves.push_back( 4) ; + m_vnLeaves.push_back( 5) ; + m_vnLeaves.push_back( 6) ; + m_vnLeaves.push_back( 7) ; + m_vnLeaves.push_back( 10) ; + m_vnLeaves.push_back( 11) ; + m_vnLeaves.push_back( 12) ; + m_vnLeaves.push_back( 13) ; - // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza - // misura approssimativa della curvatura in una direzione - bool bVert ; - if ( dCurvV > dCurvU) { - // lungo la direzione V ho una curvatura maggiore - bVert = false ; - } - else { - // lungo la direzione U ho una curvatura maggiore - bVert = true ; - } - m_mTree[nCToSplit].SetSplitDirVert( bVert) ; - Point3d ptP00, ptP10, ptP11, ptP01 ; - // distanza reale tra i vertici della cella - ptP00 = m_mVert[nCToSplit][0] ; - ptP10 = m_mVert[nCToSplit][1] ; - ptP11 = m_mVert[nCToSplit][2] ; - ptP01 = m_mVert[nCToSplit][3] ; - double dLen0 = Dist( ptP00, ptP10) ; - double dLen1 = Dist( ptP10, ptP11) ; - double dLen2 = Dist( ptP01, ptP11) ; - double dLen3 = Dist( ptP00, ptP01) ; - // 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 = min( dLen0, dLen2) ; - else - dSideMinVal = max( dLen0, dLen2) ; - } - else { - if ( dLen1 != 0 && dLen3 != 0) - dSideMinVal = min( dLen1, dLen3) ; - else - dSideMinVal = max( dLen1, dLen3) ; - } - // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella - dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; - - // 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)) { - CurveLine cl0010, cl0001, cl1011, cl0111 ; - // U=0 - cl0010.Set( ptP00, ptP10) ; - // U=1 - cl0111.Set( ptP01, ptP11) ; - Point3d pt0010, pt0111, ptBz0, ptBz1, ptBzV ; - int nFlag ; - CurveLine clV ; - // determino quanti Step fare per ogni direzione parametrica - double dDimU = ( dLen0 >= dLen2 ? dLen0 / m_vDim[0] : dLen2 / m_vDim[2]) ; - dDimU = ( dDimU > 1 ? 1 : dDimU) ; - double dDimV = ( dLen1 >= dLen3 ? dLen1 / m_vDim[1] : dLen3 / m_vDim[3]) ; - dDimV = ( dDimV > 1 ? 1 : dDimV) ; - // numero di Step per campionare la superficie nelle due direzioni parametriche - int nStepsU = int( 51 * dDimU + 5 * ( 1 - dDimU)) ; - int nStepsV = int( 51 * dDimV + 5 * ( 1 - dDimV)) ; - for ( int u = 0 ; u < nStepsU && ! bSplit ; ++ u) { - double dU = double ( u) / double ( nStepsU - 1) ; - double dULoc = ( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x ; - if ( ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz0) || - ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetTopRight().y, 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) ; - clV.Set( pt0010, pt0111) ; - for ( int v = 0 ; v < nStepsV ; ++ v) { - double dV = double ( v) / double ( nStepsV - 1) ; - double dVLoc = ( 1 - dV) * m_mTree[nCToSplit].GetBottomLeft().y + dV * m_mTree[nCToSplit].GetTopRight().y ; - if ( ! m_pSrfBz->GetPointD1D2( dULoc, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBzV)) - return false ; - DistPointCurve dpc( ptBzV, clV) ; - // distanza di approssimazione locale - double dDist ; - dpc.GetDist( dDist) ; - if ( dDist > dLinTol) { - bSplit = true ; - break ; - } - } - } - } - - if ( bSplit || dSideMaxVal > dSideMax) { - m_mTree[nCToSplit].SetSplitDirVert( bVert) ; - // effettuo lo split - Split( nCToSplit) ; - - // procedo con lo split del Child1 - nCToSplit = m_mTree[nCToSplit].m_nChild1 ; - } - else { - // sono arrivato ad una cella Leaf, quindi salvo la cella - m_vnLeaves.push_back( nCToSplit) ; - m_mTree[nCToSplit].Processed() ; - // risalgo i parent finché non trovo il primo Child2 da processare - nCToSplit = m_mTree[nCToSplit].m_nParent ; - if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) - m_mTree[nCToSplit].Processed() ; - while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { - if ( m_mTree[nCToSplit].m_nParent != -2) - nCToSplit = m_mTree[nCToSplit].m_nParent ; - if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) - m_mTree[nCToSplit].Processed() ; - if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) - break ; - } - nCToSplit = m_mTree[nCToSplit].m_nChild2 ; - } - } - else { - nCToSplit = m_mTree[nCToSplit].m_nChild1 ; - } - } - Balance() ; // da implementare quando dividerò ad un parametro a scelta e non a metà - } - // bilineare - else { - while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { - if ( m_mTree[nCToSplit].IsLeaf()) { - // vertici della cella - Point3d ptP00, ptP10, ptP11, ptP01 ; - ptP00 = m_mVert[nCToSplit][0] ; - ptP10 = m_mVert[nCToSplit][1] ; - ptP11 = m_mVert[nCToSplit][2] ; - ptP01 = m_mVert[nCToSplit][3] ; - // distanza reale tra i vertici della cella - double dLen0 = Dist( ptP00, ptP10) ; - double dLen1 = Dist( ptP10, ptP11) ; - double dLen2 = Dist( ptP01, ptP11) ; - double dLen3 = Dist( ptP00, ptP01) ; - - bool bVert = false ; - // calcolo in quale direzione è meglio dividere in base allo stretch - Point3d ptPSrfU, ptPSrfV ; - double dU = 0, dV = 0 ; - double dDistU = 0, dDistV = 0 ; - PNTVECTOR vPtU, vPtV ; - if ( ! m_bMulti) { - if ( max(dLen0, dLen2) > max(dLen1, dLen3)) { - bVert = true ; - } - else { - bVert = false ; - } - } - else { - for ( double i = 0.25 ; i < 1 ; i = i + 0.25 ) { - dU = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().x + i * m_mTree[nCToSplit].GetTopRight().x ; - dV = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().y + i * m_mTree[nCToSplit].GetTopRight().y ; - double dVLoc = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 ; - double dULoc = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 ; - m_pSrfBz->GetPointD1D2( dU, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfU) ; - m_pSrfBz->GetPointD1D2( dULoc, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfV) ; - vPtU.push_back( ptPSrfU) ; - vPtV.push_back( ptPSrfV) ; - } - // devo guardare se i tre punti in vPtU e vPtV sono allineati - CurveLine clU, clV; - clU.Set(vPtU[0], vPtU[1]) ; - clV.Set(vPtV[0], vPtV[1]) ; - DistPointCurve dpcU( vPtU[2], clU, false) ; - DistPointCurve dpcV( vPtV[2], clV, false) ; - dpcU.GetDist( dDistU) ; - dpcV.GetDist( dDistV) ; - if ( dDistU > dDistV) { - bVert = true ; - } - else { - bVert = false ; - } - } - - // verifico che la cella sia abbastanza grande da poter essere splittata - double dSideMinVal = 0, dSideMaxVal = 0 ; - if ( bVert) { - if ( dLen0 != 0 && dLen2 != 0) - dSideMinVal = min( dLen0, dLen2) ; - else - dSideMinVal = max( dLen0, dLen2) ; - } - else { - if ( dLen1 != 0 && dLen3 != 0) - dSideMinVal = min( dLen1, dLen3) ; - else - dSideMinVal = max( dLen1, dLen3) ; - } - // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella - dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; - - - double dErr = 0 ; - if ( m_bMulti) { - Point3d ptPSrf ; - Plane3d plAppr ; - if ( ! AreSamePointApprox( ptP00, ptP10) && ! AreSamePointApprox( ptP00, ptP01)) - plAppr.Set( ptP00, ( ptP00 - ptP01) ^ ( ptP00 - ptP10)) ; - else if ( AreSamePointApprox( ptP00, ptP10)) { - plAppr.Set( ptP01, ( ptP00 - ptP01) ^ ( ptP01 - ptP11)) ; - } - else if ( AreSamePointApprox( ptP00, ptP01)) { - plAppr.Set( ptP10, ( ptP10 - ptP11) ^ ( ptP00 - ptP10)) ; - } - for ( double i = 0.25 ; i < 1 ; i = i + 0.25) { - for ( double j = 0.25 ; j < 1 ; j = j + 0.25) { - double dU = ( 1 - i) * m_mTree[nCToSplit].GetTopRight().x + i * m_mTree[nCToSplit].GetBottomLeft().x ; - double dV = ( 1 - j) * m_mTree[nCToSplit].GetTopRight().y + j * m_mTree[nCToSplit].GetBottomLeft().y ; - m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - dErr = max( abs( DistPointPlane( ptPSrf, plAppr)), dErr) ; - } - } - } - else { - dErr = 1. / 4. * ( (ptP00 - ptP01) + (ptP11 - ptP10)).Len() ; - } - // se la cella è abbastanza grande da poter essere divisa ancora e devo approssimare meglio, la divido - if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && dErr > dLinTol) { - m_mTree[nCToSplit].SetSplitDirVert( bVert) ; - // effettuo lo split - Split( nCToSplit) ; - - // procedo con lo split del Child1 - nCToSplit = m_mTree[nCToSplit].m_nChild1 ; - } - else { - // sono arrivato ad una cella Leaf, quindi salvo la cella - m_vnLeaves.push_back( nCToSplit) ; - m_mTree[nCToSplit].Processed() ; - // risalgo i parent finché non trovo il primo Child2 da processare - nCToSplit = m_mTree[nCToSplit].m_nParent ; - if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) - m_mTree[nCToSplit].Processed() ; - while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { - if ( m_mTree[nCToSplit].m_nParent != -2) - nCToSplit = m_mTree[nCToSplit].m_nParent ; - if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) - m_mTree[nCToSplit].Processed() ; - if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) - break ; - } - nCToSplit = m_mTree[nCToSplit].m_nChild2 ; - } - } - else { - nCToSplit = m_mTree[nCToSplit].m_nChild1 ; - } - } - } - } - // se la superficie è trimmata - else { - SurfFlatRegion sfrTrimReg ; - } return true ; } +////---------------------------------------------------------------------------- +//bool +//Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) +//{ +// // suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri +// int nCToSplit = -1 ; +// double dLinTol = 0.2 ; +// //double dSideMin = 1 ; +// if ( ! m_bTrimmed) { +// if ( ! m_bBilinear) { +// while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { +// // controllo che la cella non sia già stata preliminarmente splittata +// if ( m_mTree[nCToSplit].IsLeaf()) { +// // calcolo in quale direzione ho più curvatura +// // ptP00P10 è un punto tra P00 e P10 +// double dCurvU = 0, dCurvV = 0 ; +// double dLenParU = m_mTree[nCToSplit].GetTopRight().x - m_mTree[nCToSplit].GetBottomLeft().x ; +// double dLenParV = m_mTree[nCToSplit].GetTopRight().y - m_mTree[nCToSplit].GetBottomLeft().y ; +// if ( dLenParU <= 1. / m_nDegV || dLenParV <= 1. / m_nDegU) { +// double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; +// double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; +// double dULoc = 0.5, dVLoc = 0.5 ; +// Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00 ; +// m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; +// m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; +// m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; +// m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; +// m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; +// Point3d ptV = ( 1 - dULoc) * ptP00P10 + dULoc * ptP11P01 ; +// Point3d ptU = ( 1 - dVLoc) * ptP10P11 + dVLoc * ptP01P00 ; +// dCurvV = Dist( ptV, ptPSrf) ; +// dCurvU = Dist( ptU, ptPSrf) ; +// } +// // faccio un'analisi più fine della curvatura se almeno il grado di una curva di uno dei due parametri è alto e +// // se sto ancora guardando una cella abbastanza grande +// else{ +// Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00, ptPSrfMid; +// double dStep = 1. / m_nDegU ; +// for ( double k = dStep ; k < 1 ; k = k + dStep) { +// double dU = k * m_mTree[nCToSplit].GetTopRight().x + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().x ; +// double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; +// m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; +// if ( k == 0.5) +// ptPSrfMid = ptPSrf ; +// m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; +// m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; +// CurveLine clV ; +// clV.Set( ptP00P10, ptP11P01) ; +// DistPointCurve dpc( ptPSrf, clV) ; +// double dDist ; +// dpc.GetDist( dDist) ; +// dCurvV = max( dCurvV, dDist) ; +// } +// dStep = 1. / m_nDegV ; +// for ( double k = dStep ; k < 1 ; k = k + dStep) { +// double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; +// double dV = k * m_mTree[nCToSplit].GetTopRight().y + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().y ; +// if ( k == 0.5) +// ptPSrf = ptPSrfMid ; +// else +// m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; +// m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; +// m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; +// CurveLine clU ; +// clU.Set( ptP01P00, ptP10P11) ; +// DistPointCurve dpc( ptPSrf, clU) ; +// double dDist ; +// dpc.GetDist( dDist) ; +// dCurvU = max( dCurvU, dDist) ; +// } +// } +// +// // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza +// // misura approssimativa della curvatura in una direzione +// bool bVert ; +// if ( dCurvV > dCurvU) { +// // lungo la direzione V ho una curvatura maggiore +// bVert = false ; +// } +// else { +// // lungo la direzione U ho una curvatura maggiore +// bVert = true ; +// } +// m_mTree[nCToSplit].SetSplitDirVert( bVert) ; +// Point3d ptP00, ptP10, ptP11, ptP01 ; +// // distanza reale tra i vertici della cella +// ptP00 = m_mVert[nCToSplit][0] ; +// ptP10 = m_mVert[nCToSplit][1] ; +// ptP11 = m_mVert[nCToSplit][2] ; +// ptP01 = m_mVert[nCToSplit][3] ; +// double dLen0 = Dist( ptP00, ptP10) ; +// double dLen1 = Dist( ptP10, ptP11) ; +// double dLen2 = Dist( ptP01, ptP11) ; +// double dLen3 = Dist( ptP00, ptP01) ; +// // 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 = min( dLen0, dLen2) ; +// else +// dSideMinVal = max( dLen0, dLen2) ; +// } +// else { +// if ( dLen1 != 0 && dLen3 != 0) +// dSideMinVal = min( dLen1, dLen3) ; +// else +// dSideMinVal = max( dLen1, dLen3) ; +// } +// // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella +// dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; +// +// // 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)) { +// CurveLine cl0010, cl0001, cl1011, cl0111 ; +// // U=0 +// cl0010.Set( ptP00, ptP10) ; +// // U=1 +// cl0111.Set( ptP01, ptP11) ; +// Point3d pt0010, pt0111, ptBz0, ptBz1, ptBzV ; +// int nFlag ; +// CurveLine clV ; +// // determino quanti Step fare per ogni direzione parametrica +// double dDimU = ( dLen0 >= dLen2 ? dLen0 / m_vDim[0] : dLen2 / m_vDim[2]) ; +// dDimU = ( dDimU > 1 ? 1 : dDimU) ; +// double dDimV = ( dLen1 >= dLen3 ? dLen1 / m_vDim[1] : dLen3 / m_vDim[3]) ; +// dDimV = ( dDimV > 1 ? 1 : dDimV) ; +// // numero di Step per campionare la superficie nelle due direzioni parametriche +// int nStepsU = int( 51 * dDimU + 5 * ( 1 - dDimU)) ; +// int nStepsV = int( 51 * dDimV + 5 * ( 1 - dDimV)) ; +// for ( int u = 0 ; u < nStepsU && ! bSplit ; ++ u) { +// double dU = double ( u) / double ( nStepsU - 1) ; +// double dULoc = ( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x ; +// if ( ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz0) || +// ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetTopRight().y, 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) ; +// clV.Set( pt0010, pt0111) ; +// for ( int v = 0 ; v < nStepsV ; ++ v) { +// double dV = double ( v) / double ( nStepsV - 1) ; +// double dVLoc = ( 1 - dV) * m_mTree[nCToSplit].GetBottomLeft().y + dV * m_mTree[nCToSplit].GetTopRight().y ; +// if ( ! m_pSrfBz->GetPointD1D2( dULoc, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBzV)) +// return false ; +// DistPointCurve dpc( ptBzV, clV) ; +// // distanza di approssimazione locale +// double dDist ; +// dpc.GetDist( dDist) ; +// if ( dDist > dLinTol) { +// bSplit = true ; +// break ; +// } +// } +// } +// } +// +// if ( bSplit || dSideMaxVal > dSideMax) { +// m_mTree[nCToSplit].SetSplitDirVert( bVert) ; +// // effettuo lo split +// Split( nCToSplit) ; +// +// // procedo con lo split del Child1 +// nCToSplit = m_mTree[nCToSplit].m_nChild1 ; +// } +// else { +// // sono arrivato ad una cella Leaf, quindi salvo la cella +// m_vnLeaves.push_back( nCToSplit) ; +// m_mTree[nCToSplit].SetProcessed() ; +// // risalgo i parent finché non trovo il primo Child2 da processare +// nCToSplit = m_mTree[nCToSplit].m_nParent ; +// if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) +// m_mTree[nCToSplit].SetProcessed() ; +// while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { +// if ( m_mTree[nCToSplit].m_nParent != -2) +// nCToSplit = m_mTree[nCToSplit].m_nParent ; +// if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) +// m_mTree[nCToSplit].SetProcessed() ; +// if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) +// break ; +// } +// nCToSplit = m_mTree[nCToSplit].m_nChild2 ; +// } +// } +// else { +// nCToSplit = m_mTree[nCToSplit].m_nChild1 ; +// } +// } +// Balance() ; // da implementare quando dividerò ad un parametro a scelta e non a metà +// } +// // bilineare +// else { +// while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { +// if ( m_mTree[nCToSplit].IsLeaf()) { +// // vertici della cella +// Point3d ptP00, ptP10, ptP11, ptP01 ; +// ptP00 = m_mVert[nCToSplit][0] ; +// ptP10 = m_mVert[nCToSplit][1] ; +// ptP11 = m_mVert[nCToSplit][2] ; +// ptP01 = m_mVert[nCToSplit][3] ; +// // distanza reale tra i vertici della cella +// double dLen0 = Dist( ptP00, ptP10) ; +// double dLen1 = Dist( ptP10, ptP11) ; +// double dLen2 = Dist( ptP01, ptP11) ; +// double dLen3 = Dist( ptP00, ptP01) ; +// +// bool bVert = false ; +// // calcolo in quale direzione è meglio dividere in base allo stretch +// Point3d ptPSrfU, ptPSrfV ; +// double dU = 0, dV = 0 ; +// double dDistU = 0, dDistV = 0 ; +// PNTVECTOR vPtU, vPtV ; +// if ( ! m_bMulti) { +// if ( max(dLen0, dLen2) > max(dLen1, dLen3)) { +// bVert = true ; +// } +// else { +// bVert = false ; +// } +// } +// else { +// for ( double i = 0.25 ; i < 1 ; i = i + 0.25 ) { +// dU = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().x + i * m_mTree[nCToSplit].GetTopRight().x ; +// dV = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().y + i * m_mTree[nCToSplit].GetTopRight().y ; +// double dVLoc = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 ; +// double dULoc = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 ; +// m_pSrfBz->GetPointD1D2( dU, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfU) ; +// m_pSrfBz->GetPointD1D2( dULoc, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfV) ; +// vPtU.push_back( ptPSrfU) ; +// vPtV.push_back( ptPSrfV) ; +// } +// // devo guardare se i tre punti in vPtU e vPtV sono allineati +// CurveLine clU, clV; +// clU.Set(vPtU[0], vPtU[1]) ; +// clV.Set(vPtV[0], vPtV[1]) ; +// DistPointCurve dpcU( vPtU[2], clU, false) ; +// DistPointCurve dpcV( vPtV[2], clV, false) ; +// dpcU.GetDist( dDistU) ; +// dpcV.GetDist( dDistV) ; +// if ( dDistU > dDistV) { +// bVert = true ; +// } +// else { +// bVert = false ; +// } +// } +// +// // verifico che la cella sia abbastanza grande da poter essere splittata +// double dSideMinVal = 0, dSideMaxVal = 0 ; +// if ( bVert) { +// if ( dLen0 != 0 && dLen2 != 0) +// dSideMinVal = min( dLen0, dLen2) ; +// else +// dSideMinVal = max( dLen0, dLen2) ; +// } +// else { +// if ( dLen1 != 0 && dLen3 != 0) +// dSideMinVal = min( dLen1, dLen3) ; +// else +// dSideMinVal = max( dLen1, dLen3) ; +// } +// // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella +// dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; +// +// +// double dErr = 0 ; +// if ( m_bMulti) { +// Point3d ptPSrf ; +// Plane3d plAppr ; +// if ( ! AreSamePointApprox( ptP00, ptP10) && ! AreSamePointApprox( ptP00, ptP01)) +// plAppr.Set( ptP00, ( ptP00 - ptP01) ^ ( ptP00 - ptP10)) ; +// else if ( AreSamePointApprox( ptP00, ptP10)) { +// plAppr.Set( ptP01, ( ptP00 - ptP01) ^ ( ptP01 - ptP11)) ; +// } +// else if ( AreSamePointApprox( ptP00, ptP01)) { +// plAppr.Set( ptP10, ( ptP10 - ptP11) ^ ( ptP00 - ptP10)) ; +// } +// for ( double i = 0.25 ; i < 1 ; i = i + 0.25) { +// for ( double j = 0.25 ; j < 1 ; j = j + 0.25) { +// double dU = ( 1 - i) * m_mTree[nCToSplit].GetTopRight().x + i * m_mTree[nCToSplit].GetBottomLeft().x ; +// double dV = ( 1 - j) * m_mTree[nCToSplit].GetTopRight().y + j * m_mTree[nCToSplit].GetBottomLeft().y ; +// m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; +// dErr = max( abs( DistPointPlane( ptPSrf, plAppr)), dErr) ; +// } +// } +// } +// else { +// dErr = 1. / 4. * ( (ptP00 - ptP01) + (ptP11 - ptP10)).Len() ; +// } +// // se la cella è abbastanza grande da poter essere divisa ancora e devo approssimare meglio, la divido +// if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && dErr > dLinTol) { +// m_mTree[nCToSplit].SetSplitDirVert( bVert) ; +// // effettuo lo split +// Split( nCToSplit) ; +// +// // procedo con lo split del Child1 +// nCToSplit = m_mTree[nCToSplit].m_nChild1 ; +// } +// else { +// // sono arrivato ad una cella Leaf, quindi salvo la cella +// m_vnLeaves.push_back( nCToSplit) ; +// m_mTree[nCToSplit].SetProcessed() ; +// // risalgo i parent finché non trovo il primo Child2 da processare +// nCToSplit = m_mTree[nCToSplit].m_nParent ; +// if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) +// m_mTree[nCToSplit].SetProcessed() ; +// while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { +// if ( m_mTree[nCToSplit].m_nParent != -2) +// nCToSplit = m_mTree[nCToSplit].m_nParent ; +// if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) +// m_mTree[nCToSplit].SetProcessed() ; +// if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) +// break ; +// } +// nCToSplit = m_mTree[nCToSplit].m_nChild2 ; +// } +// } +// else { +// nCToSplit = m_mTree[nCToSplit].m_nChild1 ; +// } +// } +// } +// } +// // se la superficie è trimmata +// else { +// SurfFlatRegion sfrTrimReg ; +// } +// return true ; +//} + //---------------------------------------------------------------------------- -void Tree::Balance() +void +Tree::Balance() { //for ( int i : vCheck ) { // // non ancora implementato // // rendo il tree balanced : ogni foglia deve avere una profondità di +- 1 rispetto alle foglie adiacenti. //} + + // al momento il problema viene bypassato in fase di generazione dei poligoni, considerando per ogni cella, oltre ai propri vertici + // i vertici dei vicini che giacciono sui suoi lati } //---------------------------------------------------------------------------- -void Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) const +void +Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) const { if ( (int) vTopNeighs.size() == 0) { if ( m_mTree.at(nId).m_nTop == -2) @@ -738,7 +836,8 @@ void Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) const //---------------------------------------------------------------------------- -void Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) const +void +Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) const { if ( (int) vBottomNeighs.size() == 0) { if ( m_mTree.at(nId).m_nBottom == -2) @@ -817,7 +916,8 @@ void Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) const //---------------------------------------------------------------------------- -void Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) const +void +Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) const { if ( (int) vLeftNeighs.size() == 0) { if ( m_mTree.at(nId).m_nLeft == -2) @@ -895,7 +995,8 @@ void Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) const } //---------------------------------------------------------------------------- -void Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) const +void +Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) const { if ( (int) vRightNeighs.size() == 0) { if ( m_mTree.at(nId).m_nRight == -2) @@ -973,7 +1074,52 @@ void Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) const } //---------------------------------------------------------------------------- -int Tree::GetHeightLeaves( int nId, INTVECTOR& vnLeaves, int d) const +void +Tree::GetRootNeigh( int nEdge, INTVECTOR& vNeigh) +{ + int nId = -1 ; + bool bMod = false ; + if ( nEdge == 0 ) { + if ( m_mTree[nId].m_nBottom == -2 ) { + m_mTree[nId].m_nBottom = -1 ; + bMod = true; + } + GetBottomNeigh( nId, vNeigh) ; + if ( bMod) + m_mTree[nId].m_nBottom = -2 ; + } + else if ( nEdge == 1 ) { + if ( m_mTree[nId].m_nRight == -2 ) { + m_mTree[nId].m_nRight = -1 ; + bMod = true; + } + GetRightNeigh( nId, vNeigh) ; + if ( bMod) + m_mTree[nId].m_nRight = -2 ; + } + else if ( nEdge == 2 ) { + if ( m_mTree[nId].m_nTop == -2 ) { + m_mTree[nId].m_nTop = -1 ; + bMod = true; + } + GetTopNeigh( nId, vNeigh) ; + if ( bMod) + m_mTree[nId].m_nTop = -2 ; + } + else if ( nEdge == 3 ) { + if ( m_mTree[nId].m_nLeft == -2 ) { + m_mTree[nId].m_nLeft = -1 ; + bMod = true; + } + GetLeftNeigh( nId, vNeigh) ; + if ( bMod) + m_mTree[nId].m_nLeft = -2 ; + } +} + +//---------------------------------------------------------------------------- +int +Tree::GetHeightLeaves( int nId, INTVECTOR& vnLeaves, int d) const { if ( nId == -1 && m_mTree.at(-1).IsLeaf()) { vnLeaves.push_back( -1) ; @@ -1013,7 +1159,8 @@ int Tree::GetHeightLeaves( int nId, INTVECTOR& vnLeaves, int d) const } //---------------------------------------------------------------------------- -int Tree::GetDepth( int nId, int nRef = -2) const +int +Tree::GetDepth( int nId, int nRef = -2) const { int c = 0 ; while ( m_mTree.at(nId).m_nParent != nRef) { @@ -1024,7 +1171,352 @@ int Tree::GetDepth( int nId, int nRef = -2) const } //---------------------------------------------------------------------------- -bool Tree::GetPolygons( POLYLINEVECTOR& vPolygons) +bool +Tree::GetPolygons( std::vector& vPolygons) { + if ( ! m_bTrimmed) { + vPolygons.clear() ; + POLYLINEVECTOR vPolygonsBasic ; + GetPolygonsBasic( vPolygonsBasic) ; + for ( PolyLine pl : vPolygonsBasic) { + POLYLINEVECTOR vSinglePolygon ; + vSinglePolygon.push_back( pl) ; + vPolygons.push_back( vSinglePolygon) ; + } + return true ; + } + // trimmata + else { + TraceLoopLabelCell() ; + POLYLINEVECTOR vPolygonsBasic ; + GetPolygonsBasic( vPolygonsBasic) ; + // scorro sui poligoni delle celle non trimmate + int nCells = (int)vPolygonsBasic.size() ; + for ( int i = 0 ; i < nCells ; ++i ) { + // vettore dei poligoni ( loop) della cella nId + POLYLINEVECTOR vCellPolygons ; + // costruisco i poligoni partendo dal vettore delle intersezioni, come spiegato a pag15 di Cripps + int nId = m_vnLeaves[i] ; + PolyLine plTrimmedPoly ; + // numero di volte che la cella è stata attraversata da una curva di trim + int nPass = (int) m_mTree[nId].m_vInters.size() ; + // numero di vertici aggiunti al nuovo poligono + int c = 0 ; + // numero di poligoni aggiunti + int nPoly = 0 ; + // vettore in cui salvo il chunk di appartenenza di ogni loop che attraversa la cella + INTVECTOR vnParentChunk ; + // scorro sui vettori intersezione della cella nId e sui suoi vertici + // in questo for analizzo solo i loop che tagliano la cella + int nEdgeIn = -1 ; + for ( int j = 0 ; j < nPass ; ++ j) { + Inters inA = m_mTree[nId].m_vInters[j] ; + if ( inA.nIn != -1) { + int nEdge ; + if ( nEdgeIn == -1) + // salvo il lato di ingresso del primo lato del poligono che sto costruendo + nEdgeIn = inA.nIn ; + for ( Point3d ptInt : inA.vpt) { + plTrimmedPoly.AddUPoint( c, ptInt) ; + ++ c ; + } + nEdge = inA.nOut ; + // se la curva è CW devo verifica di non essere uscito in un vertice, con un tratto sovrapposto al lato che ripercorrerò tra poco + if ( ! inA.bCCW) { + Point3d ptLast , ptSecondToLast; + plTrimmedPoly.GetLastPoint( ptLast) ; + plTrimmedPoly.GetPrevPoint( ptSecondToLast) ; + Vector3d vLast = ptLast - ptSecondToLast ; + vLast.Normalize(); + Vector3d vEdge ; + if ( nEdge == 0) { + Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + if ( AreSamePointApprox ( ptLast, ptTl)) { + vEdge = m_mTree[nId].GetBottomLeft() - ptTl ; + vEdge.Normalize() ; + if ( AreOppositeVectorApprox( vLast, vEdge) ) { + plTrimmedPoly.EraseLastUPoint() ; + nEdge = 1 ; + } + } + } + else if ( nEdge == 1 && AreSamePointApprox ( ptLast, m_mTree[nId].GetBottomLeft())) { + Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + vEdge = ptBr - m_mTree[nId].GetBottomLeft() ; + vEdge.Normalize() ; + if ( AreOppositeVectorApprox( vLast, vEdge) ) { + plTrimmedPoly.EraseLastUPoint() ; + nEdge = 2 ; + } + } + else if ( nEdge == 2) { + Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + if ( AreSamePointApprox ( ptLast, ptBr)) { + vEdge = m_mTree[nId].GetTopRight() - ptBr ; + vEdge.Normalize() ; + if ( AreOppositeVectorApprox( vLast, vEdge) ) { + plTrimmedPoly.EraseLastUPoint() ; + nEdge = 3 ; + } + } + } + else if ( nEdge == 3 && AreSamePointApprox ( ptLast, m_mTree[nId].GetTopRight())) { + Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + vEdge = ptTl - m_mTree[nId].GetTopRight() ; + vEdge.Normalize() ; + if ( AreOppositeVectorApprox(vLast, vEdge) ) { + plTrimmedPoly.EraseLastUPoint() ; + nEdge = 0 ; + } + } + } + // se mi è rimasto solo un punto sulla polyline vuol dire che avevo solo un tratto parallelo ad lato + // quindi salto al prossimo loop + if ( plTrimmedPoly.GetPointNbr() == 1 ) { + plTrimmedPoly.Clear() ; + continue ; + } + if ( nEdge > 3 && nEdge != 7) { + nEdge = nEdge - 3 ; + } + else if ( nEdge == 7 ) { + nEdge = 0 ; + } + // se ho altri Pass vado avanti ad aggiungere vertici finché trovo il prossimo o finché non sono tornato sul lato di partenza + bool bNotCameBack = true ; + bool bValidNextStart = false ; + if ( j < nPass - 1 ) { + if ( m_mTree[nId].m_vInters[j].bCCW ) { + bValidNextStart = ( m_mTree[nId].m_vInters[j + 1].nIn == nEdge) && + ! CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[j + 1].vpt[0], nEdge) ; + bNotCameBack = m_mTree[nId].m_vInters[j].nIn != nEdge && // sono tornato al lato di ingresso di questo loop + nEdge != nEdgeIn ; // sono tornato sul lato di ingresso di questo poligono ( solo se la curva è CCW) + } + else { + // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline + if ( nEdge == nEdgeIn ) { + bValidNextStart = ( m_mTree[nId].m_vInters[j + 1].nIn == nEdge) && + CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[j + 1].vpt[0], nEdge) ; + bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; + bNotCameBack = bNotCameBack && ! bBefore ; + } + } + // devo controllare che su questo lato il prossimo punto di ingresso sia più avanti del punto di fine a cui sono arrivato!!!!////////////////////// + while ( m_mTree[nId].m_vInters[j + 1].nIn != nEdge && // loop successivo inizia su questo lato/// questa condizione devo spostarla nell'if qui sopra + // e differenziare per CCW e CW. sostituisco con bValidNextStart + bNotCameBack) { + Point3d ptVert ; + if ( nEdge == 0) { + ptVert.x = m_mTree[nId].GetBottomLeft().x ; + ptVert.y = m_mTree[nId].GetTopRight().y ; + } + else if ( nEdge == 1) + ptVert = m_mTree[nId].GetBottomLeft() ; + else if ( nEdge == 2) { + ptVert.x = m_mTree[nId].GetTopRight().x ; + ptVert.y = m_mTree[nId].GetBottomLeft().y ; + } + else if ( nEdge == 3) + ptVert = m_mTree[nId].GetTopRight() ; + plTrimmedPoly.AddUPoint( c, ptVert) ; + ++c ; + if ( nEdge != 3) + ++ nEdge ; + else + nEdge = 0 ; + // aggiorno le condizioni per il while + if ( m_mTree[nId].m_vInters[j].bCCW ) { + bNotCameBack = m_mTree[nId].m_vInters[j].nIn != nEdge && + nEdge != nEdgeIn ; + } + else { + if ( nEdge == nEdgeIn ) { + bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; + bNotCameBack = bNotCameBack && ! bBefore ; + } + } + } + // se ho trovato un altro loop salto all'inizio del for + if ( m_mTree[nId].m_vInters[j + 1].nIn == nEdge) { + continue ; + } + } + // non ho altri loop quindi aggiungo vertici finché torno al punto di partenza + else { + if ( m_mTree[nId].m_vInters[j].bCCW ) { + bNotCameBack = m_mTree[nId].m_vInters[j].nIn != nEdge && // sono tornato al lato di ingresso di questo loop + nEdge != nEdgeIn ; // sono tornato sul lato di ingresso di questo poligono ( solo se la curva è CCW) + } + else { + // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline + if ( nEdge == nEdgeIn ) { + bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; + bNotCameBack = bNotCameBack && ! bBefore ; + } + } + while ( bNotCameBack) { + Point3d ptVert ; + if ( nEdge == 0) { + ptVert.x = m_mTree[nId].GetBottomLeft().x ; + ptVert.y = m_mTree[nId].GetTopRight().y ; + } + else if ( nEdge == 1) + ptVert = m_mTree[nId].GetBottomLeft() ; + else if ( nEdge == 2) { + ptVert.x = m_mTree[nId].GetTopRight().x ; + ptVert.y = m_mTree[nId].GetBottomLeft().y ; + } + else if ( nEdge == 3) + ptVert = m_mTree[nId].GetTopRight() ; + plTrimmedPoly.AddUPoint( c, ptVert) ; + ++c ; + if ( nEdge != 3) + ++ nEdge ; + else + nEdge = 0 ; + // aggiorno le condizioni per il while + if ( m_mTree[nId].m_vInters[j].bCCW ) { + bNotCameBack = m_mTree[nId].m_vInters[j].nIn != nEdge && + nEdge != nEdgeIn ; + } + else { + if ( nEdge == nEdgeIn ) { + bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; + bNotCameBack = bNotCameBack && ! bBefore ; + } + } + } + } + plTrimmedPoly.Close() ; + vCellPolygons.push_back( plTrimmedPoly) ; + vPolygons.push_back( vCellPolygons) ; + ++ nPoly ; + vnParentChunk.push_back( inA.nChunk) ; + vCellPolygons.clear() ; + c = 0 ; + plTrimmedPoly.Clear() ; + nEdgeIn = -1 ; + } + else + continue ; + } + + // ora analizzo anche i loop che sono contenuti nella cella + // loop interni in una cella intersecata + // + // DA AGGIUNGERE //////// + // la cella è contenuta in un loop più grande della cella -> i loop esterni devono essere CW e devo aggiungere il bordo della cella ai loop///////////////////////////////// + if ( m_mTree[nId].m_nFlag == 3 || m_mTree[nId].m_nFlag == 2) { + // devo verificare se il loop è contenuto in un'altro loop ?////////////////////////////////////sì///////////////////////////////////////// + PolyLine plInLoop ; + // numero dei loop interni passati + int n = 0 ; + Inters inA = m_mTree[nId].m_vInters[n] ; + if ( m_mTree[nId].m_nFlag == 2 && inA.nOut == -3) { + // i loop esterni sono CW, quindi prima dei loop di trim aggiungo il bordo cella + Point3d ptVert = m_mTree[nId].GetTopRight() ; + plInLoop.AddUPoint( 0, ptVert) ; + ptVert.x = m_mTree[nId].GetBottomLeft().x ; + ptVert.y = m_mTree[nId].GetTopRight().y ; + plInLoop.AddUPoint( 1, ptVert) ; + ptVert = m_mTree[nId].GetBottomLeft() ; + plInLoop.AddUPoint( 2, ptVert) ; + ptVert.x = m_mTree[nId].GetTopRight().x ; + ptVert.y = m_mTree[nId].GetBottomLeft().y ; + plInLoop.AddUPoint( 3, ptVert) ; + plInLoop.Close(); + vCellPolygons.push_back( plInLoop) ; + vPolygons.push_back( vCellPolygons) ; + ++ nPoly ; + vnParentChunk.push_back( inA.nChunk) ; + vCellPolygons.clear() ; + plInLoop.Clear() ; + } + while ( inA.nIn == -1) { + // numero di vertici aggiunti al nuovo poligono + int k = 0 ; + for ( Point3d ptInt : inA.vpt) { + plInLoop.AddUPoint( c, ptInt) ; + ++ k ; + } + plInLoop.Close(); + bool bAdded = false ; + // se il loop è CW devo controllare in quale altro dei poligoni che ho già aggiunto è contenuto + if ( ! inA.bCCW) { + Point3d ptStart ; + plInLoop.GetFirstPoint( ptStart) ; + int nOtherPoly = (int)vPolygons.size() ; + for ( int r = 0 ; r < nPoly ; ++r ) { + if ( IsPointInsidePolyLine( ptStart, vPolygons[nOtherPoly - r - 1][0], -0.01) && vnParentChunk[nPoly - r - 1] == inA.nChunk ) { + vPolygons[r].push_back( plInLoop) ; + plInLoop.Clear() ; + ++ nPoly ; + vnParentChunk.push_back( inA.nChunk) ; + bAdded = true ; + break ; + } + } + } + if ( ! bAdded ) { + vCellPolygons.push_back( plInLoop) ; + vPolygons.push_back( vCellPolygons) ; + ++ nPoly ; + vnParentChunk.push_back( inA.nChunk) ; + plInLoop.Clear() ; + vCellPolygons.clear() ; + } + + plInLoop.Clear() ; + ++ n ; + inA = m_mTree[nId].m_vInters[n] ; + } + } + //// solo loop interni + //// o la cella è contenuta in un loop più grande della cella -> i loop esterni devono essere CW e devo aggiungere il bordo della cella ai loop + //// o bisogna tenere solo il contenuto dei loop -> i loop esterni sono CCW + //if ( m_mTree[nId].m_nFlag == 2) { + // PolyLine plInLoop ; + // int n = 0 ; + // Inters inA = m_mTree[nId].m_vInters[n] ; + // if ( inA.nOut == -3) { + // // i loop esterni sono CW, quindi prima dei loop di trim aggiungo il bordo cella + // Point3d ptVert = m_mTree[nId].GetTopRight() ; + // plInLoop.AddUPoint( 0, ptVert) ; + // ptVert.x = m_mTree[nId].GetBottomLeft().x ; + // ptVert.y = m_mTree[nId].GetTopRight().y ; + // plInLoop.AddUPoint( 1, ptVert) ; + // ptVert = m_mTree[nId].GetBottomLeft() ; + // plInLoop.AddUPoint( 2, ptVert) ; + // ptVert.x = m_mTree[nId].GetTopRight().x ; + // ptVert.y = m_mTree[nId].GetBottomLeft().y ; + // plInLoop.AddUPoint( 3, ptVert) ; + // vCellPolygons.push_back( plInLoop) ; + // plInLoop.Clear() ; + // } + // while ( inA.nIn == -1) { + // // numero di vertici aggiunti al nuovo poligono + // int k = 0 ; + // for ( Point3d ptInt : inA.vpt) { + // plInLoop.AddUPoint( c, ptInt) ; + // ++ k ; + // } + // ++ n ; + // inA = m_mTree[nId].m_vInters[n] ; + // vCellPolygons.push_back( plInLoop) ; + // plInLoop.Clear() ; + // } + //} + + // questo in teoria non serve più, perché aggiungo subito un vCellPolygons a vPolygons////////////////////////////////da controllare///////////////// + //if ( (int)vCellPolygons.size() != 0) + // vPolygons.push_back( vCellPolygons) ; + } + return true; + } +} + +//---------------------------------------------------------------------------- +bool +Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons) { if ( m_vPolygons.empty()) { PNTVECTOR vVertices ; @@ -1108,10 +1600,517 @@ bool Tree::GetPolygons( POLYLINEVECTOR& vPolygons) for ( int i = 0 ; i < (int) vVertices.size() ; ++i) { m_vPolygons.back().AddUPoint( i, vVertices.at(i)) ; } + } } // restituisco i poligoni delle celle del tree nello spazio parametrico vPolygons = m_vPolygons ; return true ; -} \ No newline at end of file +} + +//---------------------------------------------------------------------------- +void +Tree::ResetTree( void) +{ + //int nCToReset = -1 ; + //while ( nCToReset != -2 && m_mTree[nCToReset].IsProcessed() == true) { + // if ( m_mTree[nCToReset].IsLeaf()) { + // m_mTree[nCToReset].SetProcessed( false) ; + // + // // risalgo i parent finché non trovo il primo Child2 da deprocessare + // nCToReset = m_mTree[nCToReset].m_nParent ; + // if ( ! m_mTree[m_mTree[nCToReset].m_nChild1].IsProcessed() && ! m_mTree[m_mTree[nCToReset].m_nChild2].IsProcessed()) + // m_mTree[nCToReset].SetProcessed( false) ; + // while ( ! m_mTree[m_mTree[nCToReset].m_nChild2].IsProcessed()) { + // if ( m_mTree[nCToReset].m_nParent != -2) + // nCToReset = m_mTree[nCToReset].m_nParent ; + // if ( ! m_mTree[m_mTree[nCToReset].m_nChild1].IsProcessed() && ! m_mTree[m_mTree[nCToReset].m_nChild2].IsProcessed()) + // m_mTree[nCToReset].SetProcessed( false) ; + // if ( nCToReset == -1 && ! m_mTree[m_mTree[nCToReset].m_nChild2].IsProcessed()) + // break ; + // } + // nCToReset = m_mTree[nCToReset].m_nChild2 ; + + // } + // else { + // nCToReset = m_mTree[nCToReset].m_nChild1 ; + // } + //} + for ( int nC : m_vnLeaves ) { + m_mTree[nC].SetProcessed( false) ; + } +} + +//---------------------------------------------------------------------------- +int +Tree::FindCell( const Point3d& ptToAssign) const +{ + // se fallisce ritorna -2 + // verifico che il punto sia all'interno dello spazio parametrico + if ( ptToAssign.x < m_mTree.at(-1).GetBottomLeft().x || ptToAssign.x > m_mTree.at( -1).GetTopRight().x || + ptToAssign.y < m_mTree.at(-1).GetBottomLeft().y || ptToAssign.y > m_mTree.at( -1).GetTopRight().y ) + return -2 ; + + int nId = -1 ; + while ( ! m_mTree.at(nId).IsLeaf()) { + if ( m_mTree.at(nId).IsSplitVert()) { + double dMid = ( m_mTree.at(nId).GetBottomLeft().x + m_mTree.at(nId).GetTopRight().x) / 2 ; + if ( ptToAssign.x < dMid) { + nId = m_mTree.at(nId).m_nChild1 ; + } + else { + nId = m_mTree.at(nId).m_nChild2 ; + } + } + else { + double dMid = ( m_mTree.at(nId).GetBottomLeft().y + m_mTree.at(nId).GetTopRight().y) / 2 ; + if ( ptToAssign.y < dMid ) { + nId = m_mTree.at(nId).m_nChild2 ; + } + else { + nId = m_mTree.at(nId).m_nChild1 ; + } + } + } + if ( nId == -1) + nId = -2 ; + return nId ; +} + +//---------------------------------------------------------------------------- +bool +Tree::TraceLoopLabelCell( void) +{ + // approssimo i loop di trim con delle spezzate + POLYLINEVECTOR vPlApprox ; + //for ( PtrOwner pCrv : m_vLoop){ + for ( int p = 0 ; p < (int) m_vLoop.size(); ++ p){ + PtrOwner pCrv( m_vLoop[p]->Clone()) ; + double dLinTol = 0.01 ; // questo è riferito allo spazio parametrico perché le curve di loop sono già state riscalate!!!!!! + double dAngTolDeg = 5 ; + PolyLine plApprox ; + int nType = 0 ; + pCrv->ApproxWithLines( dLinTol,dAngTolDeg, nType, plApprox) ; + vPlApprox.push_back( plApprox) ; + } + // ora le curve di trim hanno lo stesso indice delle loro corrispondenti spezzate nel vettore vPlApprox + // come sono composte le plApprox?? + + // qui potrei aver trovato solo le celle che sono nelle box3d delle curve di trim. se ho delle curve in senso antiorario come le gestisco???? + double dLinTol = - 0.01 ; // questo è riferito allo spazio parametrico!!!!!! + POLYLINEVECTOR vplPolygons ; + GetPolygonsBasic( vplPolygons) ; + // percorro i loop trovando le interezioni con le celle e riempiendo i vettori m_vInters delle varie celle + //for ( PolyLine plLoop : vPlApprox) { + for ( int i = 0 ; i < (int) vPlApprox.size(); ++ i) { + PolyLine plLoop = vPlApprox[i] ; + // calcolo se il loop è CCW o Cw + double dArea ; + Plane3d plExtPlane ; + bool bCCW ; + plLoop.IsClosedAndFlat( plExtPlane, dArea, 50 * EPS_SMALL) ; + if ( plExtPlane.GetVersN().z > 0 ) + bCCW = true ; + else + bCCW = false ; + // trovo in quale cella è il ptStart + Point3d ptStart ; + plLoop.GetFirstPoint( ptStart) ; + int nId = FindCell( ptStart) ; + // 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 + // per poter fare il merge con l'ultimo vptInters della curva di trim, che sarà ancora in questa cella + // e terminerà nel punto di start + int nPass = (int) m_mTree[nId].m_vInters.size() ; + m_mTree[nId].m_vInters.emplace_back() ; + // salvo il verso del loop + m_mTree[nId].m_vInters.back().bCCW = bCCW ; + // salvo il chunk del loop + m_mTree[nId].m_vInters.back().nChunk = m_mChunk[i] ; + bool bLoopInside = true ; + // funziona la condizione del for ??///////////////////////////////////////////////////////////////////////////////////////////////////////////// + Point3d ptCurr ; + INTVECTOR :: iterator iter = find( m_vnLeaves.begin(), m_vnLeaves.end(), nId) ; + int nIdPolygon = std::distance( m_vnLeaves.begin(), iter) ; + //for ( Point3d ptCurr ; plLoop.GetNextPoint( ptCurr) ; ) { + while ( plLoop.GetNextPoint( ptCurr)) { + // sto uscendo dalla cella, quindi cerco l'intersezione + Point3d ptStart, ptEnd ; + plLoop.GetPrevPoint( ptStart) ; + plLoop.GetNextPoint( ptEnd) ; + CurveLine clTrim ; + clTrim.Set( ptStart, ptEnd) ; + while( ! IsPointInsidePolyLine( ptCurr, m_vPolygons[nIdPolygon], dLinTol)) { /// qui devo mettere una tolleranza negativa per poter tener conto anche dei punti che sono SULLA curva + bLoopInside = false ; + // trovo l'intersezione e passo alla cella successiva. nId viene aggiornato dalla funzione FindInters + FindInters( nId, clTrim, vptInters) ; + // ricalcolo la posizione di nId nel vettore delle foglie + iter = find( m_vnLeaves.begin(), m_vnLeaves.end(), nId) ; + nIdPolygon = std::distance( m_vnLeaves.begin(), iter) ; + // salvo il verso del loop + m_mTree[nId].m_vInters.back().bCCW = bCCW ; + // salvo il chunk del loop + m_mTree[nId].m_vInters.back().nChunk = m_mChunk[i] ; + } + // aggiungo la fine del segmento nel vettore delle intersezioni + vptInters.push_back( ptCurr) ; + } + vptInters.pop_back() ; + m_mTree[nId].m_vInters.back().vpt = vptInters ; + if ( bLoopInside) { + m_mTree[nId].m_vnLoop.push_back( i) ; + // setto la categoria della cella + if ( m_mTree[nId].m_nFlag == 0) + m_mTree[nId].m_nFlag = 2 ; + else if ( m_mTree[nId].m_nFlag == 1) + m_mTree[nId].m_nFlag = 3 ; + // setto i lati di ingresso e uscita a -1 per indicare che ho un loop interno alla cella + m_mTree[nId].m_vInters.back().nIn = -1 ; + m_mTree[nId].m_vInters.back().nOut = -1 ; + //// salvo il verso della curva di trim ///////////////////////////////////////////////////////////////////doppione////////////////// + //double dArea ; + //Plane3d plExtPlane ; + //plLoop.IsClosedAndFlat( plExtPlane, dArea, 50 * EPS_SMALL) ; + //if ( plExtPlane.GetVersN().z > 0 ) { + // m_mTree[nId].m_vInters.back().bCCW = true ; + //} + //else { + // m_mTree[nId].m_vInters.back().bCCW = false ; + //} + + } + // sono tornato alla cella di partenza, quindi devo fare il merge dei due vettori di intersezione che ho creato per questa cella + // per lo stesso loop + else { + //int nIn = m_mTree[nId].m_vInters.back().nIn ; + int nOut = m_mTree[nId].m_vInters[nPass].nOut ; + m_mTree[nId].m_vInters.back().vpt.insert( m_mTree[nId].m_vInters.back().vpt.end(), + m_mTree[nId].m_vInters[nPass].vpt.begin(), + m_mTree[nId].m_vInters[nPass].vpt.end()) ; + m_mTree[nId].m_vInters[nPass] = m_mTree[nId].m_vInters.back() ; + m_mTree[nId].m_vInters.pop_back() ; + // sistemo il lato d'uscita + m_mTree[nId].m_vInters[nPass].nOut = nOut ; + } + } + + // riordino i vettori di intersezione per ogni cella + for ( int nId : m_vnLeaves) { + std::sort( m_mTree[nId].m_vInters.begin( ), m_mTree[nId].m_vInters.end()) ; + } + + //// devo riconoscere le celle dentro i loop che sono ancora con label nFlag = -1 + //ResetTree() ; + //INTVECTOR vNeigh, vFirst ; + //GetRootNeigh( 1, vFirst) ; + //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 , bDone ; + //while ( nCell != nLastLeft && ! bAllDone) { + // // fintanto che la cella ha tra i vicini a destra una cella non elaborata mi sposto a destra + // bDone = false ; // ramo a destra tutto categorizzato + // while ( (int)vNeigh.size() > 0 || ! bDone) { + // // 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]].IsProcessed() ) { + // nCell = vNeigh[i] ; + // bProceeded = true ; + // break ; + // } + // } + // if ( ! bProceeded) + // bDone = true ; + // else { //categorizzo la cella/////////////////////////////////////////////////////////// + + // } + // + // if ( ! bDone) { + // // guardo i vicini a destra per passare alla prossima cella + // vNeigh.clear() ; + // GetRightNeigh( nCell, vNeigh) ; + // } + // } + // 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 ; + // while ( (int) vNeigh.size() == 0 || bDone) { + // // trovo il vicino a sinistra, già categorizzato, più basso + // vNeigh.clear() ; + // GetLeftNeigh( nCell, vNeigh) ; + // for ( int p = 0; p < (int)vNeigh.size() ; ++ p) { + // if ( m_mTree[vNeigh[p]].IsProcessed() ) { + // nCell = vNeigh[p] ; + // break ; + // } + // } + // // controllo se tutti i vicini di destra sono categorizzati + // vNeigh.clear() ; + // GetRightNeigh( nCell, vNeigh) ; + // for ( int k = 0; k < (int)vNeigh.size() ; ++ k) { + // if ( ! m_mTree[vNeigh[k]].IsProcessed() ) { + // nCell = vNeigh[k] ; + // bDone = false; + // break ; + // } + // } + // } + // // categorizzo la cella + + + + // // se sono all'ultimo elemento di vFirst controllo se ho fatto tutti i suoi vicini di destra + // if ( nCell == nLastLeft){ + // vNeigh.clear() ; + // GetRightNeigh( nCell, vNeigh) ; + // bAllDone = true ; + // for( int j = 0 ; j < (int) vNeigh.size(); ++ j) { + // if ( ! m_mTree[vNeigh[j]].IsProcessed() ) { + // bAllDone = false ; + // break ; + // } + // } + // } + + //} + + //// RIMETTI il valore di default di m_nFlag = -1 nella creazione di una cella // mi serve???////////////////////////////////////////////////////////// + + return true ; +} + +//---------------------------------------------------------------------------- +bool +Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters) +{ + CurveLine clEdge , clEdge2 ; + Point3d ptStart , ptEnd ; + clTrim.GetStartPoint( ptStart) ; + clTrim.GetEndPoint( ptEnd) ; + // trovo da quale lato sto uscendo + Point3d ptTR = m_mTree[nId].GetTopRight() ; + Point3d ptBL = m_mTree[nId].GetBottomLeft() ; + Point3d ptTl( ptBL.x , ptTR.y) ; + Point3d ptBr( ptTR.x , ptBL.y) ; + 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 + if ( ptEnd.y > ptTR.y && ptEnd.x <= ptTR.x) { + nEdge = 0 ; + // lato sopra + if ( ptEnd.x >= ptBL.x) + clEdge.Set( ptTR, ptTl) ; + // lato sinistro + else //if ( ptEnd.x < ptBL.x) + clEdge2.Set( ptTl, ptBL) ; + } + else if ( ptEnd.x < ptBL.x && ptEnd.y <= ptTR.y) { + nEdge = 1 ; + // lato sinistro + if ( ptEnd.y >= ptBL.y) + clEdge.Set( ptTl, ptBL) ; + // lato sotto + else //if ( ptEnd.y < ptBL.y) + clEdge2.Set( ptBL, ptBr) ; + } + else if ( ptEnd.y < ptBL.y && ptEnd.x >= ptBL.x) { + nEdge = 2 ; + // lato sotto + if ( ptEnd.x <= ptTR.x) + clEdge.Set( ptBL, ptBr) ; + // lato destro + else if ( ptEnd.x > ptTR.x) + clEdge2.Set( ptBr, ptTR) ; + } + else if ( ptEnd.x > ptTR.x && ptEnd.y >= ptBL.y) { + nEdge = 3 ; + // lato desto + if ( ptEnd.y <= ptTR.y) + clEdge.Set( ptBr, ptTR) ; + // lato sopra + if ( ptEnd.y > ptTR.y) + clEdge2.Set( ptTR, ptTl) ; + } + else + return false ; + + // intersezione e controlli + IntersLineLine illExit( clTrim, clEdge, true) ; + IntCrvCrvInfo aInfo, aInfo2 ; + Point3d ptInters ; + if ( ! illExit.GetIntCrvCrvInfo( aInfo) ) + return false ; + if ( clEdge2.IsValid()){ + IntersLineLine illExit2( clTrim, clEdge2, true) ; + if ( ! illExit2.GetIntCrvCrvInfo( aInfo2) ) + return false ; + // verifico su quale dei due lati ho l'intersezione + if ( illExit2.GetNumInters() == 0) + ptInters = aInfo.IciA[0].ptI ; + else { + // solo intersezione sul lato 2 + if ( illExit.GetNumInters() == 0) { + ptInters = aInfo2.IciA[0].ptI ; + if ( nEdge == 3) + nEdge = 0 ; + else + ++ nEdge ; + } + // intersezione sul vertice della cella + else { + // la cella adiacente in diagonale a quel vertice + nEdge = nEdge + 4 ; + } + } + } + else + ptInters = aInfo.IciA[0].ptI ; + 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 + m_mTree[nId].m_vInters.back().vpt = vptInters ; + vptInters.clear() ; + // setto la categoria della cella + if ( m_mTree[nId].m_nFlag == 0) + m_mTree[nId].m_nFlag = 1 ; + else if ( m_mTree[nId].m_nFlag == 2) + m_mTree[nId].m_nFlag = 3 ; + // seleziono la cella successiva da analizzare + INTVECTOR vNeigh ; + if ( nEdge == 0) { + GetTopNeigh( nId, vNeigh) ; + std::reverse( vNeigh.begin(), vNeigh.end()) ; + for ( int j : vNeigh ) { + if ( ptInters.x >= m_mTree[j].GetBottomLeft().x) { + nId = j ; + break ; + } + } + m_mTree[nId].m_vInters.emplace_back() ; + m_mTree[nId].m_vInters.back().nIn = 2 ; + } + else if ( nEdge == 1) { + GetLeftNeigh( nId, vNeigh) ; + std::reverse( vNeigh.begin(), vNeigh.end()) ; + for ( int j : vNeigh ) { + if ( ptInters.y >= m_mTree[j].GetBottomLeft().y) { + nId = j ; + break ; + } + } + m_mTree[nId].m_vInters.emplace_back() ; + m_mTree[nId].m_vInters.back().nIn = 3 ; + } + else if ( nEdge == 2) { + GetBottomNeigh( nId, vNeigh) ; + for ( int j : vNeigh ) { + if ( ptInters.x <= m_mTree[j].GetTopRight().x) { + nId = j ; + break ; + } + } + m_mTree[nId].m_vInters.emplace_back() ; + m_mTree[nId].m_vInters.back().nIn = 0 ; + } + else if ( nEdge == 3) { + GetRightNeigh( nId, vNeigh) ; + for ( int j : vNeigh ) { + if ( ptInters.y <= m_mTree[j].GetTopRight().y) { + nId = j ; + break ; + } + } + m_mTree[nId].m_vInters.emplace_back() ; + m_mTree[nId].m_vInters.back().nIn = 1 ; + } + else if ( nEdge == 4) { + GetTopNeigh( nId, vNeigh) ; + int nIdTemp = vNeigh[0] ; + vNeigh.clear() ; + GetLeftNeigh( nIdTemp, vNeigh) ; + nId = vNeigh[0] ; + m_mTree[nId].m_vInters.emplace_back() ; + m_mTree[nId].m_vInters.back().nIn = 6 ; + } + else if ( nEdge == 5) { + GetLeftNeigh( nId, vNeigh) ; + int nIdTemp = vNeigh[0] ; + vNeigh.clear() ; + GetBottomNeigh( nIdTemp, vNeigh) ; + nId = vNeigh.back() ; + m_mTree[nId].m_vInters.emplace_back() ; + m_mTree[nId].m_vInters.back().nIn = 7 ; + } + else if ( nEdge == 6) { + GetBottomNeigh( nId, vNeigh) ; + int nIdTemp = vNeigh.back() ; + vNeigh.clear() ; + GetRightNeigh( nIdTemp, vNeigh) ; + nId = vNeigh[0] ; + m_mTree[nId].m_vInters.emplace_back() ; + m_mTree[nId].m_vInters.back().nIn = 4 ; + } + else if ( nEdge == 7) { + GetRightNeigh( nId, vNeigh) ; + int nIdTemp = vNeigh.back() ; + vNeigh.clear() ; + GetTopNeigh( nIdTemp, vNeigh) ; + nId = vNeigh[0] ; + m_mTree[nId].m_vInters.emplace_back() ; + m_mTree[nId].m_vInters.back().nIn = 5 ; + } + // aggiungo l'intersezione al vettore delle intersezioni della prossima cella + vptInters.push_back( ptInters) ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +Tree::CheckIfBefore( PolyLine& pl, int nEdge) const +{ + Point3d ptStart, ptEnd ; + pl.GetFirstPoint( ptStart) ; + pl.GetLastPoint( ptEnd) ; + if ( nEdge == 0 ) { + return ptEnd.x > ptStart.x ; + } + else if ( nEdge == 1 ) { + return ptEnd.y > ptStart.y ; + } + else if ( nEdge == 2 ) { + return ptEnd.x < ptStart.x ; + } + else if ( nEdge == 3 ) { + return ptEnd.y < ptStart.y ; + } + return false ; +} + +//---------------------------------------------------------------------------- +bool +Tree::CheckIfAfter( PolyLine& pl, Point3d& ptNextStart, int nEdge) const +{ + Point3d ptEnd ; + pl.GetLastPoint( ptEnd) ; + if ( nEdge == 0 ) { + return ptEnd.x > ptNextStart.x ; + } + else if ( nEdge == 1 ) { + return ptEnd.y > ptNextStart.y ; + } + else if ( nEdge == 2 ) { + return ptEnd.x < ptNextStart.x ; + } + else if ( nEdge == 3 ) { + return ptEnd.y < ptNextStart.y ; + } + return false ; +} + diff --git a/Tree.h b/Tree.h index 751c21f..dbb8378 100644 --- a/Tree.h +++ b/Tree.h @@ -17,6 +17,28 @@ #include #include "SurfBezier.h" #include "GeoConst.h" +#include "CurveLine.h" + +struct Inters { + int nIn ; + PNTVECTOR vpt ; + int nOut ; + bool bCCW ; + 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 bEqIn = ( nIn == b.nIn) ; + return nIn < b.nIn || + ( 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) + ; } +} ; +// nIn e nOut sono flag che indicano da quale lato ho l'ingresso e l'uscita 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 //---------------------------------------------------------------------------- class Cell @@ -36,21 +58,28 @@ class Cell bool IsSplitVert( void) const { return m_bSplitVert ; } // se true la cella verrebbe splittata verticalmente, sennò orizzontalmente bool IsLeaf( void) const ; // flag che indica se la cella ha figli o se è una foglia bool IsProcessed( void) const { return m_bProcessed ; } // flag che indica se tutti i figli della cella, se ce ne sono, sono stati processati - void Processed( void) { m_bProcessed = true ; } + void SetProcessed( bool bProcessed = true) { m_bProcessed = bProcessed ; } static bool minorX ( const Cell& c1, const Cell& c2) { return c1.m_ptPbl.x < c2.m_ptPbl.x ; } static bool minorY ( const Cell& c1, const Cell& c2) { return c1.m_ptPbl.y < c2.m_ptPbl.y ; } - + public : - int m_nId ; // Id della cella - int m_nTop ; // cella adiacente al lato top - int m_nBottom ; // cella adiacente al lato bottom - int m_nLeft ; // cella adiacente al lato left - int m_nRight ; // cella adiacente al lato right - int m_nParent ; // cella genitore - int m_nDepth ; // profondità della cella rispetto a root - double m_dSplit ; // parametro a cui è stata splittata la cella - int m_nChild1 ; // prima cella figlio - int m_nChild2 ; // seconda cella figlio + int m_nId ; // Id della cella + int m_nTop ; // cella adiacente al lato top + int m_nBottom ; // cella adiacente al lato bottom + int m_nLeft ; // cella adiacente al lato left + int m_nRight ; // cella adiacente al lato right + int m_nParent ; // cella genitore + int m_nDepth ; // profondità della cella rispetto a root + double m_dSplit ; // parametro a cui è stata splittata la cella + int m_nChild1 ; // prima cella figlio + int m_nChild2 ; // seconda cella figlio + int m_nFlag ; // falg che indica la caratterizzazaione della cella rispetto ai loop di trim + // -1 non categorizzata + // 0 esterna, 1 intersecata, 2 contiene un loop, 3 intersecata e contenente un loop, 4 contenuta in un loop + int m_nRightEdgeIn ; // 0 right edge fuori, 1 right edge dentro, 2 metà e metà + INTVECTOR m_vnLoop ; // indice dei loop contenuti nella cella + 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 : Point3d m_ptPbl ; // punto bottom left @@ -69,9 +98,11 @@ public : void SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches = true) ; bool BuildTree( double dLinTol = LIN_TOL_STD, double dSideMin = 5, 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 GetPolygons( POLYLINEVECTOR& vPolygons) ; // restituisce il poligono corrispondente ad ogni cella foglia dell'albero + 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 + private : void Split( int nId, double dSplitValue) ; // funzione di split di una cella al parametro indicato nella direzione data da bVert void Split( int nId) ; // funzione di split di una cella dell'albero a metà nella direzione data da bVert @@ -82,17 +113,30 @@ private : void GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato bottom void GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato left void GetRightNeigh( int nId, INTVECTOR& vRightNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato right + void GetRootNeigh( int nEdge, INTVECTOR& vNeigh) ; // restituisce le foglie dell'albero che sono adiacenti al lato nEdge, numerato a partire dal top ( 0) in senso antiorario + void ResetTree ( void) ; // resetto m_bProcessed a false per tutti i nodi dell'albero + int FindCell ( const Point3d& ptToAssign) const ; // dato un punto, trova la cella foglia a cui appartiene + bool TraceLoopLabelCell( void) ; // tracing dei loop e labelling delle celle + bool FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters) ; // trova le intersezioni tra una cella e una linea di trim + // resituisce l'id della cella verso cui la curva di trim esce e il vettore delle intersezioni per la cella successiva con il primo punto + bool CheckIfBefore( PolyLine& pl, int nEdge) const ; + bool CheckIfAfter( PolyLine& pl, Point3d& ptNextStart, int nEdge) const ; private : const SurfBezier* m_pSrfBz ; // superficie di bezier - DBLVECTOR m_vDim ; // distanze tra i vertici della superficie di bezier in ordine antiorario a partire da ptP00 + DBLVECTOR m_vDim ; // distanze tra i vertici della superficie di bezier in 3d in ordine antiorario a partire da ptP00 bool m_bTrimmed ; // superficie trimmata + std::vector m_vChunk ; // elenco dei loop divisi per chunk + std::map m_mChunk ; + //std::vector m_vLoop ; + ICURVEPOVECTOR m_vLoop ; // curve di loop. la 0 è il bordo dello spazio parametrico, le altre sono i loop interni bool m_bBilinear ; // superficie bilineare bool m_bMulti ; // superficie multi-patch bool m_bClosed ; // superficie chiusa int m_nDegU ; // grado della superficie nel parametro U int m_nDegV ; // grado della superficie nel parametro V POLYLINEVECTOR m_vPolygons ; // vettore dei poligoni del tree + //std::map m_mPolygons ; // mappa dei poligoni std::map m_mTree ; // mappa che contiene tutti i nodi e le foglie dell'albero. -2 è puntatore Null e -1 è root std::map m_mVert ; // mappa che contiene tutti i vertici 3d delle celle del tree. L'Id è lo stesso che la cella ha in m_mTree INTVECTOR m_vnLeaves ; // vettore delle foglie From 470455472891290cc564e65c3c2a1410221fd5ea Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 30 May 2023 09:05:26 +0200 Subject: [PATCH 08/44] EgtGeomKernel : - aggiunta la gestione delle aree di trim nested Da aggiungere : - gestione delle celle non intersecate dai loop --- Tree.cpp | 966 +++++++++++++++++++++++++++++-------------------------- Tree.h | 8 +- 2 files changed, 522 insertions(+), 452 deletions(-) diff --git a/Tree.cpp b/Tree.cpp index 21a8aa1..8bbe74e 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -25,12 +25,10 @@ #include "/EgtDev/Include/EGkDistPointCurve.h" #include "/EgtDev/Include/EGkCurve.h" -using namespace std ; - //---------------------------------------------------------------------------- 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( 0), m_nRightEdgeIn( 0), m_ptPbl(ORIG), m_ptPtr(), m_bProcessed(false), m_bSplitVert(true) + m_nChild1( -2), m_nChild2( -2), m_nFlag( 0), m_nFlag2( 0), m_nRightEdgeIn( 0), m_ptPbl(ORIG), m_ptPtr(), m_bProcessed(false), m_bSplitVert(true) { Point3d ptTr ( 1, 1) ; m_ptPtr = ptTr ; @@ -40,7 +38,7 @@ Cell::Cell( void) //---------------------------------------------------------------------------- Cell::Cell( Point3d& ptBL, 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( 0), m_nRightEdgeIn( 0), m_ptPbl(ptBL), m_ptPtr(ptTR), m_bProcessed(false), m_bSplitVert(true) + m_nChild1( -2), m_nChild2( -2), m_nFlag( 0), m_nFlag2( 0), m_nRightEdgeIn( 0), m_ptPbl(ptBL), m_ptPtr(ptTR), m_bProcessed(false), m_bSplitVert(true) {} @@ -75,7 +73,7 @@ Tree::Tree( void) { Point3d ptBl( 0, 0), ptTr ( 1, 1) ; Cell cRoot( ptBl, ptTr) ; - m_mTree.insert( pair< int, Cell>( -1, cRoot)) ; + m_mTree.insert( std::pair< int, Cell>( -1, cRoot)) ; } //---------------------------------------------------------------------------- @@ -160,7 +158,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) Point3d ptBottom ( 0, 0) ; Point3d ptTop( nSpanU, nSpanV) ; Cell cRoot( ptBottom, ptTop) ; - m_mTree.insert( pair< int, Cell>( -1, cRoot)) ; + m_mTree.insert( std::pair< int, Cell>( -1, cRoot)) ; Point3d ptP00, ptP10, ptP11, ptP01 ; bool bOk = false ; PNTVECTOR vVert ; @@ -172,7 +170,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) vVert.push_back( ptP11) ; ptP01 = m_pSrfBz->GetControlPoint( ( nDegU * nSpanU + 1 ) * ( nDegV * nSpanV), &bOk) ; vVert.push_back( ptP01) ; - m_mVert.insert( pair( -1, vVert)) ; + m_mVert.insert( std::pair( -1, vVert)) ; // se richiesto divido preliminarmente le patches if ( bSplitPatches && ( nSpanU > 1 || nSpanV > 1)) { int nId = -1 ; @@ -291,12 +289,12 @@ Tree::Split( int nId, double dSplitValue) m_mTree[nId].m_nChild1 = nNodes - 1 ; cChild2.m_nId = nNodes ; m_mTree[nId].m_nChild2 = nNodes ; - m_mTree.insert( pair( nNodes - 1, cChild1)) ; - m_mTree.insert( pair( nNodes, cChild2)) ; + m_mTree.insert( std::pair( nNodes - 1, cChild1)) ; + m_mTree.insert( std::pair( nNodes, cChild2)) ; Point3d ptVert1, ptVert2 ; PNTVECTOR vVert ; - m_mVert.insert( pair( nNodes - 1, vVert)) ; - m_mVert.insert( pair( nNodes, vVert)) ; + m_mVert.insert( std::pair( nNodes - 1, vVert)) ; + m_mVert.insert( std::pair( nNodes, vVert)) ; if ( ! m_mTree[nId].IsSplitVert()) { // la cella figlio 1 è quella sopra @@ -825,7 +823,7 @@ Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) const } } } - vector vCells ; + std::vector vCells ; for ( int k : vTopNeighs) vCells.push_back( m_mTree.at(k)) ; std::sort( vCells.begin(), vCells.end(), Cell::minorX) ; @@ -905,7 +903,7 @@ Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) const } } } - vector vCells ; + std::vector vCells ; for ( int k : vBottomNeighs) vCells.push_back( m_mTree.at(k)) ; std::sort( vCells.begin(), vCells.end(), Cell::minorX) ; @@ -985,7 +983,7 @@ Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) const } } } - vector vCells ; + std::vector vCells ; for ( int k : vLeftNeighs) vCells.push_back( m_mTree.at(k)) ; std::sort( vCells.begin(), vCells.end(), Cell::minorY) ; @@ -1064,7 +1062,7 @@ Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) const } } } - vector vCells ; + std::vector vCells ; for ( int k : vRightNeighs) vCells.push_back( m_mTree.at(k)) ; std::sort( vCells.begin(), vCells.end(), Cell::minorY) ; @@ -1149,7 +1147,7 @@ Tree::GetHeightLeaves( int nId, INTVECTOR& vnLeaves, int d) const -- j ; vnLeaves.push_back( m_mTree.at(i).m_nChild1) ; vnLeaves.push_back( m_mTree.at(i).m_nChild2) ; - d = max ( d, m_mTree.at(m_mTree.at(i).m_nChild1).m_nDepth) ; + d = std::max ( d, m_mTree.at(m_mTree.at(i).m_nChild1).m_nDepth) ; } } return d ; @@ -1170,347 +1168,65 @@ Tree::GetDepth( int nId, int nRef = -2) const return c ; } +struct generator +{ + int value ; + generator() { value = -1 ;} + int operator() () { return ++value ; } +} ; + //---------------------------------------------------------------------------- bool Tree::GetPolygons( std::vector& vPolygons) { - if ( ! m_bTrimmed) { - vPolygons.clear() ; - POLYLINEVECTOR vPolygonsBasic ; - GetPolygonsBasic( vPolygonsBasic) ; - for ( PolyLine pl : vPolygonsBasic) { - POLYLINEVECTOR vSinglePolygon ; - vSinglePolygon.push_back( pl) ; - vPolygons.push_back( vSinglePolygon) ; + if ( (int) m_vPolygons.size() == 0 ) { + if ( ! m_bTrimmed) { + vPolygons.clear() ; + POLYLINEVECTOR vPolygonsBasic ; + GetPolygonsBasic( vPolygonsBasic) ; + for ( PolyLine pl : vPolygonsBasic) { + POLYLINEVECTOR vSinglePolygon ; + vSinglePolygon.push_back( pl) ; + vPolygons.push_back( vSinglePolygon) ; + } + return true ; + } + // trimmata + else { + TraceLoopLabelCell() ; + POLYLINEVECTOR vPolygonsBasic ; + GetPolygonsBasic( vPolygonsBasic) ; + // scorro sui poligoni delle celle non trimmate + int nCells = (int)vPolygonsBasic.size() ; + for ( int i = 0 ; i < nCells ; ++i ) { + // vettore dei poligoni ( loop) della cella nId + POLYLINEVECTOR vCellPolygons ; + // costruisco i poligoni partendo dal vettore delle intersezioni, come spiegato a pag15 di Cripps + int nId = m_vnLeaves[i] ; + // vettore in cui salvo il chunk di appartenenza di ogni loop che attraversa la cella + INTVECTOR vnParentChunk ; + int nEdgeIn = -1 ; + // vettore in cui salvo i loop che non appartengono al poligono che sto cotruendo nel ciclo attuale e da cui ripasserò dopo + INTVECTOR vToCheck( (int) m_mTree[nId].m_vInters.size()) ; + std::generate_n( vToCheck.begin(), (int) m_mTree[nId].m_vInters.size(), generator()) ; + // numero di poligoni aggiunti + int nPoly = 0 ; + // scorro sui vettori intersezione della cella nId e sui suoi vertici + // in questo for analizzo solo i loop che tagliano la cella + while( nPoly == 0 || (int)vToCheck.size() != 0) { + int nPolyBefore = nPoly ; + CreateCellPolygons( i, vPolygons, vToCheck, nPoly, vnParentChunk) ; + if ( nPolyBefore == nPoly) + break ; + } + // ora analizzo anche i loop che sono contenuti nella cella + CreateIslandAndHoles( i, vPolygons, nPoly, vnParentChunk) ; + } + return true; } - return true ; } - // trimmata else { - TraceLoopLabelCell() ; - POLYLINEVECTOR vPolygonsBasic ; - GetPolygonsBasic( vPolygonsBasic) ; - // scorro sui poligoni delle celle non trimmate - int nCells = (int)vPolygonsBasic.size() ; - for ( int i = 0 ; i < nCells ; ++i ) { - // vettore dei poligoni ( loop) della cella nId - POLYLINEVECTOR vCellPolygons ; - // costruisco i poligoni partendo dal vettore delle intersezioni, come spiegato a pag15 di Cripps - int nId = m_vnLeaves[i] ; - PolyLine plTrimmedPoly ; - // numero di volte che la cella è stata attraversata da una curva di trim - int nPass = (int) m_mTree[nId].m_vInters.size() ; - // numero di vertici aggiunti al nuovo poligono - int c = 0 ; - // numero di poligoni aggiunti - int nPoly = 0 ; - // vettore in cui salvo il chunk di appartenenza di ogni loop che attraversa la cella - INTVECTOR vnParentChunk ; - // scorro sui vettori intersezione della cella nId e sui suoi vertici - // in questo for analizzo solo i loop che tagliano la cella - int nEdgeIn = -1 ; - for ( int j = 0 ; j < nPass ; ++ j) { - Inters inA = m_mTree[nId].m_vInters[j] ; - if ( inA.nIn != -1) { - int nEdge ; - if ( nEdgeIn == -1) - // salvo il lato di ingresso del primo lato del poligono che sto costruendo - nEdgeIn = inA.nIn ; - for ( Point3d ptInt : inA.vpt) { - plTrimmedPoly.AddUPoint( c, ptInt) ; - ++ c ; - } - nEdge = inA.nOut ; - // se la curva è CW devo verifica di non essere uscito in un vertice, con un tratto sovrapposto al lato che ripercorrerò tra poco - if ( ! inA.bCCW) { - Point3d ptLast , ptSecondToLast; - plTrimmedPoly.GetLastPoint( ptLast) ; - plTrimmedPoly.GetPrevPoint( ptSecondToLast) ; - Vector3d vLast = ptLast - ptSecondToLast ; - vLast.Normalize(); - Vector3d vEdge ; - if ( nEdge == 0) { - Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; - if ( AreSamePointApprox ( ptLast, ptTl)) { - vEdge = m_mTree[nId].GetBottomLeft() - ptTl ; - vEdge.Normalize() ; - if ( AreOppositeVectorApprox( vLast, vEdge) ) { - plTrimmedPoly.EraseLastUPoint() ; - nEdge = 1 ; - } - } - } - else if ( nEdge == 1 && AreSamePointApprox ( ptLast, m_mTree[nId].GetBottomLeft())) { - Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; - vEdge = ptBr - m_mTree[nId].GetBottomLeft() ; - vEdge.Normalize() ; - if ( AreOppositeVectorApprox( vLast, vEdge) ) { - plTrimmedPoly.EraseLastUPoint() ; - nEdge = 2 ; - } - } - else if ( nEdge == 2) { - Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; - if ( AreSamePointApprox ( ptLast, ptBr)) { - vEdge = m_mTree[nId].GetTopRight() - ptBr ; - vEdge.Normalize() ; - if ( AreOppositeVectorApprox( vLast, vEdge) ) { - plTrimmedPoly.EraseLastUPoint() ; - nEdge = 3 ; - } - } - } - else if ( nEdge == 3 && AreSamePointApprox ( ptLast, m_mTree[nId].GetTopRight())) { - Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; - vEdge = ptTl - m_mTree[nId].GetTopRight() ; - vEdge.Normalize() ; - if ( AreOppositeVectorApprox(vLast, vEdge) ) { - plTrimmedPoly.EraseLastUPoint() ; - nEdge = 0 ; - } - } - } - // se mi è rimasto solo un punto sulla polyline vuol dire che avevo solo un tratto parallelo ad lato - // quindi salto al prossimo loop - if ( plTrimmedPoly.GetPointNbr() == 1 ) { - plTrimmedPoly.Clear() ; - continue ; - } - if ( nEdge > 3 && nEdge != 7) { - nEdge = nEdge - 3 ; - } - else if ( nEdge == 7 ) { - nEdge = 0 ; - } - // se ho altri Pass vado avanti ad aggiungere vertici finché trovo il prossimo o finché non sono tornato sul lato di partenza - bool bNotCameBack = true ; - bool bValidNextStart = false ; - if ( j < nPass - 1 ) { - if ( m_mTree[nId].m_vInters[j].bCCW ) { - bValidNextStart = ( m_mTree[nId].m_vInters[j + 1].nIn == nEdge) && - ! CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[j + 1].vpt[0], nEdge) ; - bNotCameBack = m_mTree[nId].m_vInters[j].nIn != nEdge && // sono tornato al lato di ingresso di questo loop - nEdge != nEdgeIn ; // sono tornato sul lato di ingresso di questo poligono ( solo se la curva è CCW) - } - else { - // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline - if ( nEdge == nEdgeIn ) { - bValidNextStart = ( m_mTree[nId].m_vInters[j + 1].nIn == nEdge) && - CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[j + 1].vpt[0], nEdge) ; - bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; - bNotCameBack = bNotCameBack && ! bBefore ; - } - } - // devo controllare che su questo lato il prossimo punto di ingresso sia più avanti del punto di fine a cui sono arrivato!!!!////////////////////// - while ( m_mTree[nId].m_vInters[j + 1].nIn != nEdge && // loop successivo inizia su questo lato/// questa condizione devo spostarla nell'if qui sopra - // e differenziare per CCW e CW. sostituisco con bValidNextStart - bNotCameBack) { - Point3d ptVert ; - if ( nEdge == 0) { - ptVert.x = m_mTree[nId].GetBottomLeft().x ; - ptVert.y = m_mTree[nId].GetTopRight().y ; - } - else if ( nEdge == 1) - ptVert = m_mTree[nId].GetBottomLeft() ; - else if ( nEdge == 2) { - ptVert.x = m_mTree[nId].GetTopRight().x ; - ptVert.y = m_mTree[nId].GetBottomLeft().y ; - } - else if ( nEdge == 3) - ptVert = m_mTree[nId].GetTopRight() ; - plTrimmedPoly.AddUPoint( c, ptVert) ; - ++c ; - if ( nEdge != 3) - ++ nEdge ; - else - nEdge = 0 ; - // aggiorno le condizioni per il while - if ( m_mTree[nId].m_vInters[j].bCCW ) { - bNotCameBack = m_mTree[nId].m_vInters[j].nIn != nEdge && - nEdge != nEdgeIn ; - } - else { - if ( nEdge == nEdgeIn ) { - bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; - bNotCameBack = bNotCameBack && ! bBefore ; - } - } - } - // se ho trovato un altro loop salto all'inizio del for - if ( m_mTree[nId].m_vInters[j + 1].nIn == nEdge) { - continue ; - } - } - // non ho altri loop quindi aggiungo vertici finché torno al punto di partenza - else { - if ( m_mTree[nId].m_vInters[j].bCCW ) { - bNotCameBack = m_mTree[nId].m_vInters[j].nIn != nEdge && // sono tornato al lato di ingresso di questo loop - nEdge != nEdgeIn ; // sono tornato sul lato di ingresso di questo poligono ( solo se la curva è CCW) - } - else { - // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline - if ( nEdge == nEdgeIn ) { - bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; - bNotCameBack = bNotCameBack && ! bBefore ; - } - } - while ( bNotCameBack) { - Point3d ptVert ; - if ( nEdge == 0) { - ptVert.x = m_mTree[nId].GetBottomLeft().x ; - ptVert.y = m_mTree[nId].GetTopRight().y ; - } - else if ( nEdge == 1) - ptVert = m_mTree[nId].GetBottomLeft() ; - else if ( nEdge == 2) { - ptVert.x = m_mTree[nId].GetTopRight().x ; - ptVert.y = m_mTree[nId].GetBottomLeft().y ; - } - else if ( nEdge == 3) - ptVert = m_mTree[nId].GetTopRight() ; - plTrimmedPoly.AddUPoint( c, ptVert) ; - ++c ; - if ( nEdge != 3) - ++ nEdge ; - else - nEdge = 0 ; - // aggiorno le condizioni per il while - if ( m_mTree[nId].m_vInters[j].bCCW ) { - bNotCameBack = m_mTree[nId].m_vInters[j].nIn != nEdge && - nEdge != nEdgeIn ; - } - else { - if ( nEdge == nEdgeIn ) { - bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; - bNotCameBack = bNotCameBack && ! bBefore ; - } - } - } - } - plTrimmedPoly.Close() ; - vCellPolygons.push_back( plTrimmedPoly) ; - vPolygons.push_back( vCellPolygons) ; - ++ nPoly ; - vnParentChunk.push_back( inA.nChunk) ; - vCellPolygons.clear() ; - c = 0 ; - plTrimmedPoly.Clear() ; - nEdgeIn = -1 ; - } - else - continue ; - } - - // ora analizzo anche i loop che sono contenuti nella cella - // loop interni in una cella intersecata - // - // DA AGGIUNGERE //////// - // la cella è contenuta in un loop più grande della cella -> i loop esterni devono essere CW e devo aggiungere il bordo della cella ai loop///////////////////////////////// - if ( m_mTree[nId].m_nFlag == 3 || m_mTree[nId].m_nFlag == 2) { - // devo verificare se il loop è contenuto in un'altro loop ?////////////////////////////////////sì///////////////////////////////////////// - PolyLine plInLoop ; - // numero dei loop interni passati - int n = 0 ; - Inters inA = m_mTree[nId].m_vInters[n] ; - if ( m_mTree[nId].m_nFlag == 2 && inA.nOut == -3) { - // i loop esterni sono CW, quindi prima dei loop di trim aggiungo il bordo cella - Point3d ptVert = m_mTree[nId].GetTopRight() ; - plInLoop.AddUPoint( 0, ptVert) ; - ptVert.x = m_mTree[nId].GetBottomLeft().x ; - ptVert.y = m_mTree[nId].GetTopRight().y ; - plInLoop.AddUPoint( 1, ptVert) ; - ptVert = m_mTree[nId].GetBottomLeft() ; - plInLoop.AddUPoint( 2, ptVert) ; - ptVert.x = m_mTree[nId].GetTopRight().x ; - ptVert.y = m_mTree[nId].GetBottomLeft().y ; - plInLoop.AddUPoint( 3, ptVert) ; - plInLoop.Close(); - vCellPolygons.push_back( plInLoop) ; - vPolygons.push_back( vCellPolygons) ; - ++ nPoly ; - vnParentChunk.push_back( inA.nChunk) ; - vCellPolygons.clear() ; - plInLoop.Clear() ; - } - while ( inA.nIn == -1) { - // numero di vertici aggiunti al nuovo poligono - int k = 0 ; - for ( Point3d ptInt : inA.vpt) { - plInLoop.AddUPoint( c, ptInt) ; - ++ k ; - } - plInLoop.Close(); - bool bAdded = false ; - // se il loop è CW devo controllare in quale altro dei poligoni che ho già aggiunto è contenuto - if ( ! inA.bCCW) { - Point3d ptStart ; - plInLoop.GetFirstPoint( ptStart) ; - int nOtherPoly = (int)vPolygons.size() ; - for ( int r = 0 ; r < nPoly ; ++r ) { - if ( IsPointInsidePolyLine( ptStart, vPolygons[nOtherPoly - r - 1][0], -0.01) && vnParentChunk[nPoly - r - 1] == inA.nChunk ) { - vPolygons[r].push_back( plInLoop) ; - plInLoop.Clear() ; - ++ nPoly ; - vnParentChunk.push_back( inA.nChunk) ; - bAdded = true ; - break ; - } - } - } - if ( ! bAdded ) { - vCellPolygons.push_back( plInLoop) ; - vPolygons.push_back( vCellPolygons) ; - ++ nPoly ; - vnParentChunk.push_back( inA.nChunk) ; - plInLoop.Clear() ; - vCellPolygons.clear() ; - } - - plInLoop.Clear() ; - ++ n ; - inA = m_mTree[nId].m_vInters[n] ; - } - } - //// solo loop interni - //// o la cella è contenuta in un loop più grande della cella -> i loop esterni devono essere CW e devo aggiungere il bordo della cella ai loop - //// o bisogna tenere solo il contenuto dei loop -> i loop esterni sono CCW - //if ( m_mTree[nId].m_nFlag == 2) { - // PolyLine plInLoop ; - // int n = 0 ; - // Inters inA = m_mTree[nId].m_vInters[n] ; - // if ( inA.nOut == -3) { - // // i loop esterni sono CW, quindi prima dei loop di trim aggiungo il bordo cella - // Point3d ptVert = m_mTree[nId].GetTopRight() ; - // plInLoop.AddUPoint( 0, ptVert) ; - // ptVert.x = m_mTree[nId].GetBottomLeft().x ; - // ptVert.y = m_mTree[nId].GetTopRight().y ; - // plInLoop.AddUPoint( 1, ptVert) ; - // ptVert = m_mTree[nId].GetBottomLeft() ; - // plInLoop.AddUPoint( 2, ptVert) ; - // ptVert.x = m_mTree[nId].GetTopRight().x ; - // ptVert.y = m_mTree[nId].GetBottomLeft().y ; - // plInLoop.AddUPoint( 3, ptVert) ; - // vCellPolygons.push_back( plInLoop) ; - // plInLoop.Clear() ; - // } - // while ( inA.nIn == -1) { - // // numero di vertici aggiunti al nuovo poligono - // int k = 0 ; - // for ( Point3d ptInt : inA.vpt) { - // plInLoop.AddUPoint( c, ptInt) ; - // ++ k ; - // } - // ++ n ; - // inA = m_mTree[nId].m_vInters[n] ; - // vCellPolygons.push_back( plInLoop) ; - // plInLoop.Clear() ; - // } - //} - - // questo in teoria non serve più, perché aggiungo subito un vCellPolygons a vPolygons////////////////////////////////da controllare///////////////// - //if ( (int)vCellPolygons.size() != 0) - // vPolygons.push_back( vCellPolygons) ; - } - return true; + vPolygons = m_vPolygons ; + return true ; } } @@ -1597,15 +1313,20 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons) } m_vPolygons.emplace_back() ; + m_vPolygons.back().emplace_back() ; for ( int i = 0 ; i < (int) vVertices.size() ; ++i) { - m_vPolygons.back().AddUPoint( i, vVertices.at(i)) ; + m_vPolygons.back().back().AddUPoint(i, vVertices.at(i)) ; } } } // restituisco i poligoni delle celle del tree nello spazio parametrico - vPolygons = m_vPolygons ; + for ( int t = 0 ; t < (int)m_vPolygons.size() ; ++ t) { + for ( int z = 0 ; z < (int)m_vPolygons[t].size(); ++z ) { + vPolygons.push_back( m_vPolygons[t][z]) ; + } + } return true ; } @@ -1637,6 +1358,8 @@ Tree::ResetTree( void) // nCToReset = m_mTree[nCToReset].m_nChild1 ; // } //} + + // setto tutte le foglie a Processed = false for ( int nC : m_vnLeaves ) { m_mTree[nC].SetProcessed( false) ; } @@ -1695,14 +1418,12 @@ Tree::TraceLoopLabelCell( void) vPlApprox.push_back( plApprox) ; } // ora le curve di trim hanno lo stesso indice delle loro corrispondenti spezzate nel vettore vPlApprox - // come sono composte le plApprox?? - // qui potrei aver trovato solo le celle che sono nelle box3d delle curve di trim. se ho delle curve in senso antiorario come le gestisco???? - double dLinTol = - 0.01 ; // questo è riferito allo spazio parametrico!!!!!! + double dLinTol = - 0.01 ; // 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 POLYLINEVECTOR vplPolygons ; GetPolygonsBasic( vplPolygons) ; // percorro i loop trovando le interezioni con le celle e riempiendo i vettori m_vInters delle varie celle - //for ( PolyLine plLoop : vPlApprox) { for ( int i = 0 ; i < (int) vPlApprox.size(); ++ i) { PolyLine plLoop = vPlApprox[i] ; // calcolo se il loop è CCW o Cw @@ -1731,11 +1452,9 @@ Tree::TraceLoopLabelCell( void) // salvo il chunk del loop m_mTree[nId].m_vInters.back().nChunk = m_mChunk[i] ; bool bLoopInside = true ; - // funziona la condizione del for ??///////////////////////////////////////////////////////////////////////////////////////////////////////////// Point3d ptCurr ; INTVECTOR :: iterator iter = find( m_vnLeaves.begin(), m_vnLeaves.end(), nId) ; int nIdPolygon = std::distance( m_vnLeaves.begin(), iter) ; - //for ( Point3d ptCurr ; plLoop.GetNextPoint( ptCurr) ; ) { while ( plLoop.GetNextPoint( ptCurr)) { // sto uscendo dalla cella, quindi cerco l'intersezione Point3d ptStart, ptEnd ; @@ -1743,7 +1462,7 @@ Tree::TraceLoopLabelCell( void) plLoop.GetNextPoint( ptEnd) ; CurveLine clTrim ; clTrim.Set( ptStart, ptEnd) ; - while( ! IsPointInsidePolyLine( ptCurr, m_vPolygons[nIdPolygon], dLinTol)) { /// qui devo mettere una tolleranza negativa per poter tener conto anche dei punti che sono SULLA curva + while( ! IsPointInsidePolyLine( ptCurr, vplPolygons[nIdPolygon], dLinTol)) { /// qui devo mettere una tolleranza negativa per poter tener conto anche dei punti che sono SULLA curva bLoopInside = false ; // trovo l'intersezione e passo alla cella successiva. nId viene aggiornato dalla funzione FindInters FindInters( nId, clTrim, vptInters) ; @@ -1770,22 +1489,10 @@ Tree::TraceLoopLabelCell( void) // setto i lati di ingresso e uscita a -1 per indicare che ho un loop interno alla cella m_mTree[nId].m_vInters.back().nIn = -1 ; m_mTree[nId].m_vInters.back().nOut = -1 ; - //// salvo il verso della curva di trim ///////////////////////////////////////////////////////////////////doppione////////////////// - //double dArea ; - //Plane3d plExtPlane ; - //plLoop.IsClosedAndFlat( plExtPlane, dArea, 50 * EPS_SMALL) ; - //if ( plExtPlane.GetVersN().z > 0 ) { - // m_mTree[nId].m_vInters.back().bCCW = true ; - //} - //else { - // m_mTree[nId].m_vInters.back().bCCW = false ; - //} - } // sono tornato alla cella di partenza, quindi devo fare il merge dei due vettori di intersezione che ho creato per questa cella // per lo stesso loop else { - //int nIn = m_mTree[nId].m_vInters.back().nIn ; int nOut = m_mTree[nId].m_vInters[nPass].nOut ; m_mTree[nId].m_vInters.back().vpt.insert( m_mTree[nId].m_vInters.back().vpt.end(), m_mTree[nId].m_vInters[nPass].vpt.begin(), @@ -1802,86 +1509,105 @@ Tree::TraceLoopLabelCell( void) std::sort( m_mTree[nId].m_vInters.begin( ), m_mTree[nId].m_vInters.end()) ; } - //// devo riconoscere le celle dentro i loop che sono ancora con label nFlag = -1 - //ResetTree() ; - //INTVECTOR vNeigh, vFirst ; - //GetRootNeigh( 1, vFirst) ; - //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 , bDone ; - //while ( nCell != nLastLeft && ! bAllDone) { - // // fintanto che la cella ha tra i vicini a destra una cella non elaborata mi sposto a destra - // bDone = false ; // ramo a destra tutto categorizzato - // while ( (int)vNeigh.size() > 0 || ! bDone) { - // // 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]].IsProcessed() ) { - // nCell = vNeigh[i] ; - // bProceeded = true ; - // break ; - // } - // } - // if ( ! bProceeded) - // bDone = true ; - // else { //categorizzo la cella/////////////////////////////////////////////////////////// + // devo riconoscere le celle dentro i loop che sono ancora con label nFlag = -1 + ResetTree() ; + INTVECTOR vNeigh, vFirst ; + GetRootNeigh( 1, vFirst) ; + 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 ; + while ( nCell != nLastLeft && ! bAllDone) { + // categorizzo la cella + m_mTree[nCell].m_nFlag2 = 1 ; - // } - // - // if ( ! bDone) { - // // guardo i vicini a destra per passare alla prossima cella - // vNeigh.clear() ; - // GetRightNeigh( nCell, vNeigh) ; - // } - // } - // 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 ; - // while ( (int) vNeigh.size() == 0 || bDone) { - // // trovo il vicino a sinistra, già categorizzato, più basso - // vNeigh.clear() ; - // GetLeftNeigh( nCell, vNeigh) ; - // for ( int p = 0; p < (int)vNeigh.size() ; ++ p) { - // if ( m_mTree[vNeigh[p]].IsProcessed() ) { - // nCell = vNeigh[p] ; - // break ; - // } - // } - // // controllo se tutti i vicini di destra sono categorizzati - // vNeigh.clear() ; - // GetRightNeigh( nCell, vNeigh) ; - // for ( int k = 0; k < (int)vNeigh.size() ; ++ k) { - // if ( ! m_mTree[vNeigh[k]].IsProcessed() ) { - // nCell = vNeigh[k] ; - // bDone = false; - // break ; - // } - // } - // } - // // categorizzo la cella + // 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()) { + // 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] ; + bProceeded = true ; + break ; + } + } + if ( ! bProceeded ) { + m_mTree[nCell].SetProcessed() ; + } + else { //categorizzo la cella/////////////////////////////////////////////////////////// + m_mTree[nCell].m_nFlag2 = 1 ; + } + + if ( ! m_mTree[nCell].IsProcessed()) { + // guardo i vicini a destra per passare alla prossima cella + vNeigh.clear() ; + GetRightNeigh( nCell, vNeigh) ; + } + } + 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 ; + while ( (int) vNeigh.size() == 0 || m_mTree[nCell].IsProcessed()) { + // trovo il vicino a sinistra, già categorizzato, più basso + vNeigh.clear() ; + GetLeftNeigh( nCell, vNeigh) ; + for ( int p = 0; p < (int)vNeigh.size() ; ++ p) { + if ( m_mTree[vNeigh[p]].m_nFlag2 != 0 ) { + nCell = vNeigh[p] ; + 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] ; + break ; + } + } + if ( nCell == nLastLeft && m_mTree[nCell].IsProcessed() ) { + // categorizzo//////////////////////////////////////////////////////////////////////////// + m_mTree[nCell].m_nFlag2 = 1 ; + bAllDone = true ; + break ; + } + } + // controllo se tutti i vicini di destra sono categorizzati + vNeigh.clear() ; + GetRightNeigh( nCell, vNeigh) ; + bool bDone = true ; + for ( int k = 0; k < (int)vNeigh.size() ; ++ k) { + if ( ! m_mTree[vNeigh[k]].IsProcessed() ) { + //nCell = vNeigh[k] ; + bDone = false ; + break ; + } + } + if ( bDone) + m_mTree[nCell].SetProcessed( bDone) ; + } + vNeigh.clear() ; + GetRightNeigh( nCell, vNeigh) ; + //// se sono all'ultimo elemento di vFirst controllo se ho processato tutti i suoi vicini di destra + //if ( nCell == nLastLeft){ + // vNeigh.clear() ; + // GetRightNeigh( nCell, vNeigh) ; + // bAllDone = true ; + // for( int j = 0 ; j < (int) vNeigh.size(); ++ j) { + // if ( ! m_mTree[vNeigh[j]].IsProcessed() ) { + // bAllDone = false ; + // break ; + // } + // } + //} - - // // se sono all'ultimo elemento di vFirst controllo se ho fatto tutti i suoi vicini di destra - // if ( nCell == nLastLeft){ - // vNeigh.clear() ; - // GetRightNeigh( nCell, vNeigh) ; - // bAllDone = true ; - // for( int j = 0 ; j < (int) vNeigh.size(); ++ j) { - // if ( ! m_mTree[vNeigh[j]].IsProcessed() ) { - // bAllDone = false ; - // break ; - // } - // } - // } - - //} - - //// RIMETTI il valore di default di m_nFlag = -1 nella creazione di una cella // mi serve???////////////////////////////////////////////////////////// + } return true ; } @@ -2030,6 +1756,8 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters) m_mTree[nId].m_vInters.emplace_back() ; m_mTree[nId].m_vInters.back().nIn = 1 ; } + // per nEdge > 3 sto parlando di intersezioni sui vertici, che vengono attraversati in diagonale e non paralleli ad uno dei due lati + // se attraversati adiacenti ad uno dei due lati, viene considerata l'intersezione col lato perpendicolare else if ( nEdge == 4) { GetTopNeigh( nId, vNeigh) ; int nIdTemp = vNeigh[0] ; @@ -2071,6 +1799,346 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters) return true ; } +//---------------------------------------------------------------------------- +bool +Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk) +{ + INTVECTOR vToCheckNow = vToCheck ; + vToCheck.clear() ; + // vettore dei poligoni ( loop) della cella nId + POLYLINEVECTOR vCellPolygons ; + // costruisco i poligoni partendo dal vettore delle intersezioni, come spiegato a pag15 di Cripps + int nId = m_vnLeaves[nLeafId] ; + PolyLine plTrimmedPoly ; + // numero di volte che la cella è stata attraversata da una curva di trim + int nPassToCheck = (int) vToCheckNow.size() ; + // numero di vertici aggiunti al nuovo poligono + int c = 0 ; + // scorro sui vettori intersezione della cella nId e sui suoi vertici + // in questo for analizzo solo i loop che tagliano la cella + int nEdgeIn = -1 ; + for ( int w = 0 ; w < (int)vToCheckNow.size() ; ++ w) { + int j = vToCheckNow[w] ; + Inters inA = m_mTree[nId].m_vInters[j] ; + if ( inA.nIn != -1 ) { + int nEdge ; + if ( nEdgeIn == -1 ) + // salvo il lato di ingresso del primo lato del poligono che sto costruendo + nEdgeIn = inA.nIn ; + for ( Point3d ptInt : inA.vpt ) { + plTrimmedPoly.AddUPoint(c, ptInt) ; + ++c ; + } + nEdge = inA.nOut ; + // se la curva è CW devo verifica di non essere uscito in un vertice, con un tratto sovrapposto al lato che ripercorrerò tra poco + if ( !inA.bCCW ) { + Point3d ptLast, ptSecondToLast; + plTrimmedPoly.GetLastPoint(ptLast) ; + plTrimmedPoly.GetPrevPoint(ptSecondToLast) ; + Vector3d vLast = ptLast - ptSecondToLast ; + vLast.Normalize(); + Vector3d vEdge ; + if ( nEdge == 0 ) { + Point3d ptTl(m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + if ( AreSamePointApprox(ptLast, ptTl) ) { + vEdge = m_mTree[nId].GetBottomLeft() - ptTl ; + vEdge.Normalize() ; + if ( AreOppositeVectorApprox(vLast, vEdge) ) { + plTrimmedPoly.EraseLastUPoint() ; + nEdge = 1 ; + } + } + } + else if ( nEdge == 1 && AreSamePointApprox(ptLast, m_mTree[nId].GetBottomLeft()) ) { + Point3d ptBr(m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + vEdge = ptBr - m_mTree[nId].GetBottomLeft() ; + vEdge.Normalize() ; + if ( AreOppositeVectorApprox(vLast, vEdge) ) { + plTrimmedPoly.EraseLastUPoint() ; + nEdge = 2 ; + } + } + else if ( nEdge == 2 ) { + Point3d ptBr(m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + if ( AreSamePointApprox(ptLast, ptBr) ) { + vEdge = m_mTree[nId].GetTopRight() - ptBr ; + vEdge.Normalize() ; + if ( AreOppositeVectorApprox(vLast, vEdge) ) { + plTrimmedPoly.EraseLastUPoint() ; + nEdge = 3 ; + } + } + } + else if ( nEdge == 3 && AreSamePointApprox(ptLast, m_mTree[nId].GetTopRight()) ) { + Point3d ptTl(m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + vEdge = ptTl - m_mTree[nId].GetTopRight() ; + vEdge.Normalize() ; + if ( AreOppositeVectorApprox(vLast, vEdge) ) { + plTrimmedPoly.EraseLastUPoint() ; + nEdge = 0 ; + } + } + } + // se mi è rimasto solo un punto sulla polyline vuol dire che avevo solo un tratto parallelo ad lato + // quindi salto al prossimo loop + if ( plTrimmedPoly.GetPointNbr() == 1 ) { + plTrimmedPoly.Clear() ; + continue ; + } + if ( nEdge > 3 && nEdge != 7 ) { + nEdge = nEdge - 3 ; + } + else if ( nEdge == 7 ) { + nEdge = 0 ; + } + // se ho altri Pass vado avanti ad aggiungere vertici finché trovo il prossimo o finché non sono tornato sul lato di partenza + bool bNotCameBack = true ; + bool bValidNextStart = false ; + if ( j < nPassToCheck - 1) { + int nSecondCheck = 0 ; + + // ciclo sui loop successivi per vedere se ne ho uno su questo lato con un valid start + for ( int t = w ; t < nPassToCheck -1 ; ++ t) { + if ( nEdge == m_mTree[nId].m_vInters[j].nIn ) { + if ( m_mTree[nId].m_vInters[j].bCCW) { + bValidNextStart = ( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn == nEdge) && // loop successivo inizia su questo lato + ! CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; // in posizione giusta da essere concatenato + } + else { + // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline + bValidNextStart = ( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn == nEdge) && + CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; + } + } + else + bValidNextStart = true ; + if ( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn != nEdge || bValidNextStart) + break ; + // se ho trovato un loop successivo che devo saltare, lo salvo e considero i loop più avanti. + if ( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn == nEdge && ! bValidNextStart){ + ++ nSecondCheck ; + vToCheck.push_back( t + 1) ; + } + } + if ( m_mTree[nId].m_vInters[j].bCCW) { + bNotCameBack = m_mTree[nId].m_vInters[j].nIn != nEdge && // sono tornato al lato di ingresso di questo loop + nEdge != nEdgeIn ; // sono tornato sul lato di ingresso di questo poligono ( solo se la curva è CCW) + } + else { + // il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline + if ( nEdge == nEdgeIn ) { + bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; + bNotCameBack = bNotCameBack && !bBefore ; + } + } + + while ( ! bValidNextStart && bNotCameBack) { + Point3d ptVert ; + if ( nEdge == 0) { + ptVert.x = m_mTree[nId].GetBottomLeft().x ; + ptVert.y = m_mTree[nId].GetTopRight().y ; + } + else if ( nEdge == 1) + ptVert = m_mTree[nId].GetBottomLeft() ; + else if ( nEdge == 2) { + ptVert.x = m_mTree[nId].GetTopRight().x ; + ptVert.y = m_mTree[nId].GetBottomLeft().y ; + } + else if ( nEdge == 3) + ptVert = m_mTree[nId].GetTopRight() ; + plTrimmedPoly.AddUPoint( c, ptVert) ; + ++c ; + if ( nEdge != 3) + ++ nEdge ; + else + nEdge = 0 ; + + // aggiorno le condizioni per il while + // ciclo sui loop successivi per vedere se ne ho uno su questo lato con un valid start + for ( int t = w ; t < nPassToCheck -1 ; ++ t) { + if ( nEdge == m_mTree[nId].m_vInters[j].nIn ) { + if ( m_mTree[nId].m_vInters[j].bCCW) { + bValidNextStart = ( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn == nEdge) && // loop successivo inizia su questo lato + ! CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; // in posizione giusta da essere concatenato + } + else { + // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline + bValidNextStart = ( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn == nEdge) && + CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; + } + } + else + bValidNextStart = true ; + if ( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn != nEdge || bValidNextStart) + break ; + // se ho trovato un loop successivo che devo saltare, lo salvo e considero i loop più avanti. + if ( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn == nEdge && ! bValidNextStart){ + ++ nSecondCheck ; + vToCheck.push_back( t + 1) ; + } + } + if ( m_mTree[nId].m_vInters[j].bCCW) { + bNotCameBack = m_mTree[nId].m_vInters[j].nIn != nEdge && // sono tornato al lato di ingresso di questo loop + nEdge != nEdgeIn ; // sono tornato sul lato di ingresso di questo poligono ( solo se la curva è CCW) + } + else { + // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline + if ( nEdge == nEdgeIn ) { + bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; + bNotCameBack = bNotCameBack && !bBefore ; + } + } + + } + // se ho trovato un altro loop salto all'inizio del for + if ( m_mTree[nId].m_vInters[vToCheckNow[w + 1 + nSecondCheck]].nIn == nEdge) { + w = w + nSecondCheck ; + continue ; + } + } + // non ho altri loop quindi aggiungo vertici finché torno al punto di partenza + else { + if ( m_mTree[nId].m_vInters[j].bCCW ) { + bNotCameBack = m_mTree[nId].m_vInters[j].nIn != nEdge && // sono tornato al lato di ingresso di questo loop + nEdge != nEdgeIn ; // sono tornato sul lato di ingresso di questo poligono ( solo se la curva è CCW) + } + else { + // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline + if ( nEdge == nEdgeIn ) { + bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; + bNotCameBack = bNotCameBack && ! bBefore ; + } + } + while ( bNotCameBack) { + Point3d ptVert ; + if ( nEdge == 0) { + ptVert.x = m_mTree[nId].GetBottomLeft().x ; + ptVert.y = m_mTree[nId].GetTopRight().y ; + } + else if ( nEdge == 1) + ptVert = m_mTree[nId].GetBottomLeft() ; + else if ( nEdge == 2) { + ptVert.x = m_mTree[nId].GetTopRight().x ; + ptVert.y = m_mTree[nId].GetBottomLeft().y ; + } + else if ( nEdge == 3) + ptVert = m_mTree[nId].GetTopRight() ; + plTrimmedPoly.AddUPoint( c, ptVert) ; + ++c ; + if ( nEdge != 3) + ++ nEdge ; + else + nEdge = 0 ; + // aggiorno le condizioni per il while + if ( m_mTree[nId].m_vInters[j].bCCW ) { + bNotCameBack = m_mTree[nId].m_vInters[j].nIn != nEdge && + nEdge != nEdgeIn ; + } + else { + if ( nEdge == nEdgeIn ) { + bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; + bNotCameBack = bNotCameBack && ! bBefore ; + } + } + } + } + plTrimmedPoly.Close() ; + vCellPolygons.push_back( plTrimmedPoly) ; + vPolygons.push_back( vCellPolygons) ; + ++ nPoly ; + vnParentChunk.push_back( inA.nChunk) ; + vCellPolygons.clear() ; + c = 0 ; + plTrimmedPoly.Clear() ; + nEdgeIn = -1 ; + } + else + continue ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Tree::CreateIslandAndHoles( int nLeafId, std::vector& vPolygons, int& nPoly, INTVECTOR& vnParentChunk) +{ + // vettore dei poligoni ( loop) della cella nId + POLYLINEVECTOR vCellPolygons ; + // costruisco i poligoni partendo dal vettore delle intersezioni, come spiegato a pag15 di Cripps + int nId = m_vnLeaves[nLeafId] ; + PolyLine plTrimmedPoly ; + // numero di volte che la cella è stata attraversata da una curva di trim + int nPass = (int) m_mTree[nId].m_vInters.size() ; + // numero di vertici aggiunti al nuovo poligono + int c = 0 ; + + // loop interni in una cella intersecata + if ( m_mTree[nId].m_nFlag == 3 || m_mTree[nId].m_nFlag == 2) { + PolyLine plInLoop ; + // numero dei loop interni passati + int n = 0 ; + Inters inA = m_mTree[nId].m_vInters[n] ; + if ( m_mTree[nId].m_nFlag == 2 && inA.nOut == -3) { + // i loop esterni sono CW, quindi prima dei loop di trim aggiungo il bordo cella + Point3d ptVert = m_mTree[nId].GetTopRight() ; + plInLoop.AddUPoint( 0, ptVert) ; + ptVert.x = m_mTree[nId].GetBottomLeft().x ; + ptVert.y = m_mTree[nId].GetTopRight().y ; + plInLoop.AddUPoint( 1, ptVert) ; + ptVert = m_mTree[nId].GetBottomLeft() ; + plInLoop.AddUPoint( 2, ptVert) ; + ptVert.x = m_mTree[nId].GetTopRight().x ; + ptVert.y = m_mTree[nId].GetBottomLeft().y ; + plInLoop.AddUPoint( 3, ptVert) ; + plInLoop.Close(); + vCellPolygons.push_back( plInLoop) ; + vPolygons.push_back( vCellPolygons) ; + ++ nPoly ; + vnParentChunk.push_back( inA.nChunk) ; + vCellPolygons.clear() ; + plInLoop.Clear() ; + } + while ( inA.nIn == -1) { + // numero di vertici aggiunti al nuovo poligono + int k = 0 ; + for ( Point3d ptInt : inA.vpt) { + plInLoop.AddUPoint( c, ptInt) ; + ++ k ; + } + plInLoop.Close(); + bool bAdded = false ; + // se il loop è CW devo controllare in quale altro dei poligoni che ho già aggiunto è contenuto + if ( ! inA.bCCW) { + Point3d ptStart ; + plInLoop.GetFirstPoint( ptStart) ; + int nOtherPoly = (int)vPolygons.size() ; + for ( int r = 0 ; r < nPoly ; ++r ) { + if ( IsPointInsidePolyLine( ptStart, vPolygons[nOtherPoly - r - 1][0], -0.01) && vnParentChunk[nPoly - r - 1] == inA.nChunk ) { + vPolygons[nOtherPoly - r - 1].push_back( plInLoop) ; + plInLoop.Clear() ; + vnParentChunk.push_back( inA.nChunk) ; + bAdded = true ; + break ; + } + } + } + if ( ! bAdded ) { + vCellPolygons.push_back( plInLoop) ; + vPolygons.push_back( vCellPolygons) ; + ++ nPoly ; + vnParentChunk.push_back( inA.nChunk) ; + plInLoop.Clear() ; + vCellPolygons.clear() ; + } + + plInLoop.Clear() ; + ++ n ; + inA = m_mTree[nId].m_vInters[n] ; + } + } + return true ; +} + //---------------------------------------------------------------------------- bool Tree::CheckIfBefore( PolyLine& pl, int nEdge) const diff --git a/Tree.h b/Tree.h index dbb8378..b442371 100644 --- a/Tree.h +++ b/Tree.h @@ -73,8 +73,8 @@ class Cell double m_dSplit ; // parametro a cui è stata splittata la cella int m_nChild1 ; // prima cella figlio int m_nChild2 ; // seconda cella figlio - int m_nFlag ; // falg che indica la caratterizzazaione della cella rispetto ai loop di trim - // -1 non categorizzata + int m_nFlag ; // falg che indica la caratterizzazione della cella rispetto ai loop di trim + int m_nFlag2 ; // falg che indica se la cella è stata attraversata durante l'ultima fase del labelling // 0 esterna, 1 intersecata, 2 contiene un loop, 3 intersecata e contenente un loop, 4 contenuta in un loop int m_nRightEdgeIn ; // 0 right edge fuori, 1 right edge dentro, 2 metà e metà INTVECTOR m_vnLoop ; // indice dei loop contenuti nella cella @@ -119,6 +119,8 @@ private : bool TraceLoopLabelCell( void) ; // tracing dei loop e labelling delle celle bool FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters) ; // trova le intersezioni tra una cella e una linea di trim // resituisce l'id della cella verso cui la curva di trim esce e il vettore delle intersezioni per la cella successiva con il primo punto + bool CreateCellPolygons ( int nLeafId, std::vector& vPolygons, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk) ; + bool CreateIslandAndHoles ( int nLeafId, std::vector& vPolygons, int& nPoly, INTVECTOR& vnParentChunk) ; bool CheckIfBefore( PolyLine& pl, int nEdge) const ; bool CheckIfAfter( PolyLine& pl, Point3d& ptNextStart, int nEdge) const ; @@ -135,7 +137,7 @@ private : bool m_bClosed ; // superficie chiusa int m_nDegU ; // grado della superficie nel parametro U int m_nDegV ; // grado della superficie nel parametro V - POLYLINEVECTOR m_vPolygons ; // vettore dei poligoni del tree + std::vector m_vPolygons ; // vettore dei poligoni del tree //std::map m_mPolygons ; // mappa dei poligoni std::map m_mTree ; // mappa che contiene tutti i nodi e le foglie dell'albero. -2 è puntatore Null e -1 è root std::map m_mVert ; // mappa che contiene tutti i vertici 3d delle celle del tree. L'Id è lo stesso che la cella ha in m_mTree From 56d80f5bdd7c4467dd9f1fe22cdfc2a729afa50b Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Thu, 1 Jun 2023 15:32:05 +0200 Subject: [PATCH 09/44] EgtGeomKernel : - aggiustati dei bug - implementati gli strumenti per la gestione delle celle non intersecate Da aggiungere : - categorizzazione celle rispetto ai loop. --- Tree.cpp | 1005 +++++++++++++++++++++++++++++++++++++++++++++--------- Tree.h | 15 +- 2 files changed, 851 insertions(+), 169 deletions(-) diff --git a/Tree.cpp b/Tree.cpp index 8bbe74e..f64fdf3 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -28,7 +28,7 @@ //---------------------------------------------------------------------------- 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( 0), m_nFlag2( 0), m_nRightEdgeIn( 0), 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_ptPbl(ORIG), m_ptPtr(), m_bProcessed(false), m_bSplitVert(true) { Point3d ptTr ( 1, 1) ; m_ptPtr = ptTr ; @@ -38,7 +38,7 @@ Cell::Cell( void) //---------------------------------------------------------------------------- Cell::Cell( Point3d& ptBL, 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( 0), m_nFlag2( 0), m_nRightEdgeIn( 0), 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_ptPbl(ptBL), m_ptPtr(ptTR), m_bProcessed(false), m_bSplitVert(true) {} @@ -1204,7 +1204,7 @@ Tree::GetPolygons( std::vector& vPolygons) { int nId = m_vnLeaves[i] ; // vettore in cui salvo il chunk di appartenenza di ogni loop che attraversa la cella INTVECTOR vnParentChunk ; - int nEdgeIn = -1 ; + //int nEdgeIn = -1 ; // vettore in cui salvo i loop che non appartengono al poligono che sto cotruendo nel ciclo attuale e da cui ripasserò dopo INTVECTOR vToCheck( (int) m_mTree[nId].m_vInters.size()) ; std::generate_n( vToCheck.begin(), (int) m_mTree[nId].m_vInters.size(), generator()) ; @@ -1214,7 +1214,7 @@ Tree::GetPolygons( std::vector& vPolygons) { // in questo for analizzo solo i loop che tagliano la cella while( nPoly == 0 || (int)vToCheck.size() != 0) { int nPolyBefore = nPoly ; - CreateCellPolygons( i, vPolygons, vToCheck, nPoly, vnParentChunk) ; + CreateCellPolygons( i, vPolygons, vToCheck, nPoly, vnParentChunk, vPolygonsBasic[i]) ; if ( nPolyBefore == nPoly) break ; } @@ -1291,24 +1291,26 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons) } vNeigh.clear() ; vVertices.push_back( m_mTree.at(nId).GetBottomLeft()) ; - // se ho una cella con vicino dello stesso grado ( quindi il poligono ha solo 5 punti) controllo la curvatura nella cella e - // se necessario cambio l'ordine dei vertici per scegliere la diagonale di split migliore - if ( vVertices.size() == 5) { - Point3d ptPSrf, ptP00, ptP10, ptP11, ptP01; - double dU, dV ; - dU = ( m_mTree.at(nId).GetBottomLeft().x + m_mTree.at(nId).GetTopRight().x) / 2 ; - dV = ( m_mTree.at(nId).GetBottomLeft().y + m_mTree.at(nId).GetTopRight().y) / 2 ; - m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - ptP00 = m_mVert.at(nId).at(0) ; - ptP10 = m_mVert.at(nId).at(1) ; - ptP11 = m_mVert.at(nId).at(2) ; - ptP01 = m_mVert.at(nId).at(3) ; - Point3d ptP00P11 = ( ptP00 + ptP11) / 2 ; - Point3d ptP10P01 = ( ptP10 + ptP01) / 2 ; - // ho la curvatura maggiore sulla diagonale tra P10 e P01, ruoto l'ordine dei vertici, in modo che triangulate prenda la diagonale giusta - if ( Dist(ptP00P11, ptPSrf) + EPS_SMALL > Dist(ptP10P01, ptPSrf)) { - rotate(vVertices.begin(), vVertices.begin() + 1,vVertices.end()) ; - vVertices.back() = vVertices.at(0) ; + if ( ! m_bTrimmed) { + // se ho una cella con vicino dello stesso grado ( quindi il poligono ha solo 5 punti) controllo la curvatura nella cella e + // se necessario cambio l'ordine dei vertici per scegliere la diagonale di split migliore + if ( vVertices.size() == 5) { + Point3d ptPSrf, ptP00, ptP10, ptP11, ptP01; + double dU, dV ; + dU = ( m_mTree.at(nId).GetBottomLeft().x + m_mTree.at(nId).GetTopRight().x) / 2 ; + dV = ( m_mTree.at(nId).GetBottomLeft().y + m_mTree.at(nId).GetTopRight().y) / 2 ; + m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + ptP00 = m_mVert.at(nId).at(0) ; + ptP10 = m_mVert.at(nId).at(1) ; + ptP11 = m_mVert.at(nId).at(2) ; + ptP01 = m_mVert.at(nId).at(3) ; + Point3d ptP00P11 = ( ptP00 + ptP11) / 2 ; + Point3d ptP10P01 = ( ptP10 + ptP01) / 2 ; + // ho la curvatura maggiore sulla diagonale tra P10 e P01, ruoto l'ordine dei vertici, in modo che triangulate prenda la diagonale giusta + if ( Dist(ptP00P11, ptPSrf) + EPS_SMALL > Dist(ptP10P01, ptPSrf)) { + rotate(vVertices.begin(), vVertices.begin() + 1,vVertices.end()) ; + vVertices.back() = vVertices.at(0) ; + } } } @@ -1333,7 +1335,8 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons) //---------------------------------------------------------------------------- void Tree::ResetTree( void) -{ +{ + //// setto tutti i nodi (foglie comprese) a Processed = false //int nCToReset = -1 ; //while ( nCToReset != -2 && m_mTree[nCToReset].IsProcessed() == true) { // if ( m_mTree[nCToReset].IsLeaf()) { @@ -1366,20 +1369,25 @@ Tree::ResetTree( void) } //---------------------------------------------------------------------------- -int -Tree::FindCell( const Point3d& ptToAssign) const +INTVECTOR +Tree::FindCell( const Point3d& ptToAssign, CurveLine& clTrim) const { - // se fallisce ritorna -2 + // riordino le celle da sinistra a destra ( rispetto al verso della cl) + // devo ancora aggiungerla questa feature!!!//////////////////////////////////////////////////////////////////////////////////////////////////////////// + INTVECTOR nCells ; + int nId = -1 ; + // se fallisce ritorna un vettore vuoto // verifico che il punto sia all'interno dello spazio parametrico if ( ptToAssign.x < m_mTree.at(-1).GetBottomLeft().x || ptToAssign.x > m_mTree.at( -1).GetTopRight().x || - ptToAssign.y < m_mTree.at(-1).GetBottomLeft().y || ptToAssign.y > m_mTree.at( -1).GetTopRight().y ) - return -2 ; + ptToAssign.y < m_mTree.at(-1).GetBottomLeft().y || ptToAssign.y > m_mTree.at( -1).GetTopRight().y ) { + //nCells.push_back( - 2) ; + return nCells ; + } - int nId = -1 ; while ( ! m_mTree.at(nId).IsLeaf()) { if ( m_mTree.at(nId).IsSplitVert()) { double dMid = ( m_mTree.at(nId).GetBottomLeft().x + m_mTree.at(nId).GetTopRight().x) / 2 ; - if ( ptToAssign.x < dMid) { + if ( ptToAssign.x < dMid + EPS_SMALL) { nId = m_mTree.at(nId).m_nChild1 ; } else { @@ -1388,7 +1396,7 @@ Tree::FindCell( const Point3d& ptToAssign) const } else { double dMid = ( m_mTree.at(nId).GetBottomLeft().y + m_mTree.at(nId).GetTopRight().y) / 2 ; - if ( ptToAssign.y < dMid ) { + if ( ptToAssign.y < dMid + EPS_SMALL ) { nId = m_mTree.at(nId).m_nChild2 ; } else { @@ -1396,9 +1404,95 @@ Tree::FindCell( const Point3d& ptToAssign) const } } } - if ( nId == -1) - nId = -2 ; - return nId ; + if ( nId != -1) + nCells.push_back( nId) ; + //if ( nId == -1) + // nId = -2 ; + + //// devo verificare se sono sul bordo di una cella: in questo caso dovrei restituire anche il vicino con cui condivido quel lato!! ///////////////////// + + 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) ; + //IntCrvCrvInfo aInfo, bInfo ; + //CurveLine clEdge, clEdge2 ; + //if ( AreSamePointApprox(ptToAssign, ptTl)){ + // // lato top + // clEdge.Set( m_mTree.at(nId).GetTopRight(), ptTl) ; + // IntersLineLine illTrimEdge( clTrim, clEdge, true) ; + // illTrimEdge.GetIntCrvCrvInfo( aInfo) ; + // // lato sinistro + // clEdge2.Set( ptTl, m_mTree.at(nId).GetBottomLeft()) ; + // IntersLineLine illTrimEdge2( clTrim, clEdge2, true) ; + // illTrimEdge2.GetIntCrvCrvInfo( bInfo) ; + // if ( aInfo.bOverlap) { + // if ( aInfo.bCBOverEq ) { + + // } + // } + //} + //else if ( AreSamePointApprox( ptToAssign, m_mTree.at(nId).GetBottomLeft())) { + + //} + //else if ( AreSamePointApprox(ptToAssign, ptBr)) { + + //} + //else if (AreSamePointApprox( ptToAssign, ptTl)) { + + //} + + + if ( AreSamePointApprox(ptToAssign, ptTl) || + AreSamePointApprox( ptToAssign, m_mTree.at(nId).GetBottomLeft()) || + AreSamePointApprox(ptToAssign, ptBr) || + AreSamePointApprox( ptToAssign, ptTl)) + { + Point3d ptToAssignPlus ; + double dParam ; + Vector3d vDir ; + clTrim.GetParamAtPoint( ptToAssign, dParam, EPS_SMALL) ; + 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 ; + } + nCells = FindCell( ptToAssignPlus, clTrim) ; + if ( nCells.empty()) { + ptToAssignPlus = ptToAssignPlus - 2 * vDir * EPS_SMALL ; + nCells = FindCell( ptToAssignPlus, clTrim) ; + } + } + return nCells ; +} + +//---------------------------------------------------------------------------- +INTVECTOR +Tree::FindCell( const Point3d& ptToAssign, CurveLine& cl, INTVECTOR vCells) const +{ + // se non trova nulla restituisce un vettore vuoto + // restituisce sempre solo una cella + + // la CurveLine è il segmento di trim su cui giace ptToAssign + // devo usare ptInters + qualcosa/////////////////////////////////////////////// + Point3d ptIntersPlus ; + double dParam ; + Vector3d vDir ; + cl.GetParamAtPoint( ptToAssign, dParam, EPS_SMALL) ; + cl.GetPointTang( dParam + EPS_SMALL, ICurve::FROM_MINUS, ptIntersPlus, vDir) ; + INTVECTOR nCells ; + int nId = -1 ; + bool bFound = false ; + for ( int nCell : vCells ) { + if ( ptIntersPlus.x >= m_mTree.at(nCell).GetBottomLeft().x && ptIntersPlus.x <= m_mTree.at(nCell).GetTopRight().x && + ptIntersPlus.y >= m_mTree.at(nCell).GetBottomLeft().y && ptIntersPlus.y <= m_mTree.at(nCell).GetTopRight().y) { + nId = nCell ; + nCells.push_back( nId) ; + } + //if ( bFound) + // break ; + //if ( nCells.size() > 0) + // bFound = true ; + } + return nCells ; } //---------------------------------------------------------------------------- @@ -1438,7 +1532,22 @@ Tree::TraceLoopLabelCell( void) // trovo in quale cella è il ptStart Point3d ptStart ; plLoop.GetFirstPoint( ptStart) ; - int nId = FindCell( ptStart) ; + PNTULIST lPt = plLoop.GetUPointList() ; + PNTULIST:: iterator ptFirst = lPt.begin(); + PNTULIST:: iterator ptSecond = ptFirst ; + std::advance( ptSecond, 1) ; + CurveLine clFirst ; + clFirst.Set( ptFirst->first, ptSecond->first) ; + INTVECTOR nCells = FindCell( ptStart, clFirst) ; + int nId ; + if ( (int)nCells.size() == 1) { + nId = nCells[0] ; + } + 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 ; vptInters.push_back( ptStart) ; @@ -1455,6 +1564,7 @@ Tree::TraceLoopLabelCell( void) Point3d ptCurr ; INTVECTOR :: iterator iter = find( m_vnLeaves.begin(), m_vnLeaves.end(), nId) ; int nIdPolygon = std::distance( m_vnLeaves.begin(), iter) ; + bool bVertex = false ; while ( plLoop.GetNextPoint( ptCurr)) { // sto uscendo dalla cella, quindi cerco l'intersezione Point3d ptStart, ptEnd ; @@ -1465,7 +1575,8 @@ Tree::TraceLoopLabelCell( void) while( ! IsPointInsidePolyLine( ptCurr, vplPolygons[nIdPolygon], dLinTol)) { /// qui devo mettere una tolleranza negativa per poter tener conto anche dei punti che sono SULLA curva bLoopInside = false ; // trovo l'intersezione e passo alla cella successiva. nId viene aggiornato dalla funzione FindInters - FindInters( nId, clTrim, vptInters) ; + bVertex = false ; + FindInters( nId, clTrim, vptInters, bVertex) ; // ricalcolo la posizione di nId nel vettore delle foglie iter = find( m_vnLeaves.begin(), m_vnLeaves.end(), nId) ; nIdPolygon = std::distance( m_vnLeaves.begin(), iter) ; @@ -1482,7 +1593,7 @@ Tree::TraceLoopLabelCell( void) if ( bLoopInside) { m_mTree[nId].m_vnLoop.push_back( i) ; // setto la categoria della cella - if ( m_mTree[nId].m_nFlag == 0) + if ( m_mTree[nId].m_nFlag == -1) m_mTree[nId].m_nFlag = 2 ; else if ( m_mTree[nId].m_nFlag == 1) m_mTree[nId].m_nFlag = 3 ; @@ -1493,6 +1604,22 @@ Tree::TraceLoopLabelCell( void) // sono tornato alla cella di partenza, quindi devo fare il merge dei due vettori di intersezione che ho creato per questa cella // per lo stesso loop else { + // devo verificare se il loop finisce in un vertice! in questo caso sono nella penultima cella! e devo fare un FindInters di nuovo per sistemare + Point3d ptLast = m_mTree[nId].m_vInters.back().vpt.back() ; + Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + if ( AreSamePointApprox( m_mTree[nId].GetTopRight(), ptLast) || + AreSamePointApprox( ptTl, ptLast) || + AreSamePointApprox( m_mTree[nId].GetBottomLeft(), ptLast) || + AreSamePointApprox( ptBr, ptLast)) { + Point3d ptStart, ptEnd ; + plLoop.GetPrevPoint( ptEnd) ; + plLoop.GetPrevPoint( ptStart) ; + CurveLine clTrim ; + clTrim.Set( ptStart, ptEnd) ; + vptInters.clear() ; + FindInters( nId, clTrim, vptInters, bVertex) ; + } int nOut = m_mTree[nId].m_vInters[nPass].nOut ; m_mTree[nId].m_vInters.back().vpt.insert( m_mTree[nId].m_vInters.back().vpt.end(), m_mTree[nId].m_vInters[nPass].vpt.begin(), @@ -1504,12 +1631,13 @@ Tree::TraceLoopLabelCell( void) } } - // riordino i vettori di intersezione per ogni cella + // riordino i vettori di intersezione per ogni cella e setto il flag RightEdgeIn for ( int nId : m_vnLeaves) { std::sort( m_mTree[nId].m_vInters.begin( ), m_mTree[nId].m_vInters.end()) ; + SetRightEdgeIn( nId) ; } - // devo riconoscere le celle dentro i loop che sono ancora con label nFlag = -1 + // devo riconoscere le celle dentro i loop che sono ancora con label nFlag2 = 0 ResetTree() ; INTVECTOR vNeigh, vFirst ; GetRootNeigh( 1, vFirst) ; @@ -1521,6 +1649,7 @@ Tree::TraceLoopLabelCell( void) while ( nCell != nLastLeft && ! bAllDone) { // categorizzo la cella m_mTree[nCell].m_nFlag2 = 1 ; + CategorizeCell( nCell) ; // 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 @@ -1614,7 +1743,7 @@ Tree::TraceLoopLabelCell( void) //---------------------------------------------------------------------------- bool -Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters) +Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVertex) { CurveLine clEdge , clEdge2 ; Point3d ptStart , ptEnd ; @@ -1628,39 +1757,46 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters) 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 - if ( ptEnd.y > ptTR.y && ptEnd.x <= ptTR.x) { + if ( ptEnd.y >= ptTR.y && ptEnd.x <= ptTR.x) { nEdge = 0 ; // lato sopra - if ( ptEnd.x >= ptBL.x) - clEdge.Set( ptTR, ptTl) ; - // lato sinistro - else //if ( ptEnd.x < ptBL.x) + clEdge.Set( ptTR, ptTl) ; + //if ( ptEnd.x >= ptBL.x) + // ;// lato sinistro + //else //if ( ptEnd.x < ptBL.x) + if ( ptEnd.x < ptBL.x) clEdge2.Set( ptTl, ptBL) ; } - else if ( ptEnd.x < ptBL.x && ptEnd.y <= ptTR.y) { + else if ( ptEnd.x <= ptBL.x && ptEnd.y <= ptTR.y) { nEdge = 1 ; // lato sinistro - if ( ptEnd.y >= ptBL.y) - clEdge.Set( ptTl, ptBL) ; - // lato sotto - else //if ( ptEnd.y < ptBL.y) + clEdge.Set( ptTl, ptBL) ; + //if ( ptEnd.y >= ptBL.y) + // ; + //// lato sotto + //else //if ( ptEnd.y < ptBL.y) + if ( ptEnd.y < ptBL.y) clEdge2.Set( ptBL, ptBr) ; } - else if ( ptEnd.y < ptBL.y && ptEnd.x >= ptBL.x) { + else if ( ptEnd.y <= ptBL.y && ptEnd.x >= ptBL.x) { nEdge = 2 ; // lato sotto - if ( ptEnd.x <= ptTR.x) - clEdge.Set( ptBL, ptBr) ; - // lato destro - else if ( ptEnd.x > ptTR.x) + clEdge.Set( ptBL, ptBr) ; + //if ( ptEnd.x <= ptTR.x) + // ; + //// lato destro + //else //if ( ptEnd.x > ptTR.x) + if ( ptEnd.x > ptTR.x) clEdge2.Set( ptBr, ptTR) ; } - else if ( ptEnd.x > ptTR.x && ptEnd.y >= ptBL.y) { + else if ( ptEnd.x >= ptTR.x && ptEnd.y >= ptBL.y) { nEdge = 3 ; // lato desto - if ( ptEnd.y <= ptTR.y) - clEdge.Set( ptBr, ptTR) ; - // lato sopra + clEdge.Set( ptBr, ptTR) ; + //if ( ptEnd.y <= ptTR.y) + // ; + //// lato sopra + //else //if ( ptEnd.y > ptTR.y) if ( ptEnd.y > ptTR.y) clEdge2.Set( ptTR, ptTl) ; } @@ -1671,26 +1807,31 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters) IntersLineLine illExit( clTrim, clEdge, true) ; IntCrvCrvInfo aInfo, aInfo2 ; Point3d ptInters ; - if ( ! illExit.GetIntCrvCrvInfo( aInfo) ) - return false ; + //if ( ! illExit.GetIntCrvCrvInfo( aInfo) ) + // return false ; + illExit.GetIntCrvCrvInfo( aInfo) ; if ( clEdge2.IsValid()){ IntersLineLine illExit2( clTrim, clEdge2, true) ; - if ( ! illExit2.GetIntCrvCrvInfo( aInfo2) ) - return false ; + //if ( ! illExit2.GetIntCrvCrvInfo( aInfo2) ) + // return false ; // verifico su quale dei due lati ho l'intersezione - if ( illExit2.GetNumInters() == 0) + if ( ! illExit2.GetIntCrvCrvInfo( aInfo2)) ptInters = aInfo.IciA[0].ptI ; else { // solo intersezione sul lato 2 - if ( illExit.GetNumInters() == 0) { + if ( illExit.GetNumInters() == 0 ) { ptInters = aInfo2.IciA[0].ptI ; - if ( nEdge == 3) - nEdge = 0 ; - else + if ( nEdge > 3 && nEdge != 7) + nEdge = nEdge - 4 ; + else if ( nEdge < 3 ) ++ nEdge ; + else + nEdge = 0 ; } // intersezione sul vertice della cella else { + ptInters = aInfo2.IciA[0].ptI ; + bVertex = true ; // la cella adiacente in diagonale a quel vertice nEdge = nEdge + 4 ; } @@ -1704,12 +1845,12 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters) m_mTree[nId].m_vInters.back().vpt = vptInters ; vptInters.clear() ; // setto la categoria della cella - if ( m_mTree[nId].m_nFlag == 0) + if ( m_mTree[nId].m_nFlag == -1) m_mTree[nId].m_nFlag = 1 ; else if ( m_mTree[nId].m_nFlag == 2) m_mTree[nId].m_nFlag = 3 ; // seleziono la cella successiva da analizzare - INTVECTOR vNeigh ; + INTVECTOR vNeigh, vNeigh1 ; if ( nEdge == 0) { GetTopNeigh( nId, vNeigh) ; std::reverse( vNeigh.begin(), vNeigh.end()) ; @@ -1720,7 +1861,13 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters) } } m_mTree[nId].m_vInters.emplace_back() ; - m_mTree[nId].m_vInters.back().nIn = 2 ; + Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + if ( ptInters.x > m_mTree[nId].GetBottomLeft().x && ptInters.x < m_mTree[nId].GetTopRight().x ) + m_mTree[nId].m_vInters.back().nIn = 2 ; + else if ( AreSamePointApprox( ptInters, m_mTree[nId].GetBottomLeft())) + m_mTree[nId].m_vInters.back().nIn = 5 ; + else if ( AreSamePointApprox( ptInters, ptBr)) + m_mTree[nId].m_vInters.back().nIn = 6 ; } else if ( nEdge == 1) { GetLeftNeigh( nId, vNeigh) ; @@ -1732,7 +1879,13 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters) } } m_mTree[nId].m_vInters.emplace_back() ; - m_mTree[nId].m_vInters.back().nIn = 3 ; + Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + if ( ptInters.y > m_mTree[nId].GetBottomLeft().y && ptInters.y < m_mTree[nId].GetTopRight().y ) + m_mTree[nId].m_vInters.back().nIn = 3 ; + else if ( AreSamePointApprox( ptInters, ptBr)) + m_mTree[nId].m_vInters.back().nIn = 6 ; + else if ( AreSamePointApprox( ptInters, m_mTree[nId].GetTopRight())) + m_mTree[nId].m_vInters.back().nIn = 7 ; } else if ( nEdge == 2) { GetBottomNeigh( nId, vNeigh) ; @@ -1743,7 +1896,13 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters) } } m_mTree[nId].m_vInters.emplace_back() ; - m_mTree[nId].m_vInters.back().nIn = 0 ; + Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + if ( ptInters.x > m_mTree[nId].GetBottomLeft().x && ptInters.x < m_mTree[nId].GetTopRight().x ) + m_mTree[nId].m_vInters.back().nIn = 0 ; + else if ( AreSamePointApprox( ptInters, ptTl)) + m_mTree[nId].m_vInters.back().nIn = 4 ; + else if ( AreSamePointApprox( ptInters, m_mTree[nId].GetTopRight())) + m_mTree[nId].m_vInters.back().nIn = 7 ; } else if ( nEdge == 3) { GetRightNeigh( nId, vNeigh) ; @@ -1754,45 +1913,155 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters) } } m_mTree[nId].m_vInters.emplace_back() ; - m_mTree[nId].m_vInters.back().nIn = 1 ; + Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + if ( ptInters.y > m_mTree[nId].GetBottomLeft().y && ptInters.y < m_mTree[nId].GetTopRight().y ) + m_mTree[nId].m_vInters.back().nIn = 1 ; + else if ( AreSamePointApprox( ptInters, m_mTree[nId].GetBottomLeft())) + m_mTree[nId].m_vInters.back().nIn = 5 ; + else if ( AreSamePointApprox( ptInters, ptTl)) + m_mTree[nId].m_vInters.back().nIn = 4 ; } - // per nEdge > 3 sto parlando di intersezioni sui vertici, che vengono attraversati in diagonale e non paralleli ad uno dei due lati - // se attraversati adiacenti ad uno dei due lati, viene considerata l'intersezione col lato perpendicolare + // esco da uno dei vertici else if ( nEdge == 4) { GetTopNeigh( nId, vNeigh) ; - int nIdTemp = vNeigh[0] ; - vNeigh.clear() ; - GetLeftNeigh( nIdTemp, vNeigh) ; - nId = vNeigh[0] ; - m_mTree[nId].m_vInters.emplace_back() ; - m_mTree[nId].m_vInters.back().nIn = 6 ; + GetLeftNeigh( nId, vNeigh1) ; + INTVECTOR nPossible, nPossible1 ; + nPossible = FindCell( ptInters, clTrim, vNeigh) ; + nPossible1 = FindCell( ptInters, clTrim, vNeigh1) ; + // ingresso dal basso + if ( ! nPossible.empty()) { + nId = nPossible[0] ; + m_mTree[nId].m_vInters.emplace_back() ; + 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 ; + } + // ingresso in diagonale + else { + if ( ! vNeigh.empty()) { + int nIdTemp = vNeigh[0] ; + vNeigh.clear() ; + GetLeftNeigh( nIdTemp, vNeigh) ; + nId = vNeigh[0] ; + m_mTree[nId].m_vInters.emplace_back() ; + m_mTree[nId].m_vInters.back().nIn = 6 ; + } + else { + nId = vNeigh1.back() ; + m_mTree[nId].m_vInters.emplace_back() ; + m_mTree[nId].m_vInters.back().nIn = 7 ; + } + } } else if ( nEdge == 5) { GetLeftNeigh( nId, vNeigh) ; - int nIdTemp = vNeigh[0] ; - vNeigh.clear() ; - GetBottomNeigh( nIdTemp, vNeigh) ; - nId = vNeigh.back() ; - m_mTree[nId].m_vInters.emplace_back() ; - m_mTree[nId].m_vInters.back().nIn = 7 ; + GetBottomNeigh( nId, vNeigh1) ; + INTVECTOR nPossible, nPossible1 ; + nPossible = FindCell( ptInters, clTrim, vNeigh) ; + nPossible1 = FindCell( ptInters, clTrim, vNeigh1) ; + // ingresso dal destra + if ( ! nPossible.empty()) { + nId = nPossible[0] ; + m_mTree[nId].m_vInters.emplace_back() ; + 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 ; + } + // ingresso in diagonale + else { + if ( ! vNeigh.empty()) { + int nIdTemp = vNeigh[0] ; + vNeigh.clear() ; + GetBottomNeigh( nIdTemp, vNeigh) ; + nId = vNeigh.back() ; + m_mTree[nId].m_vInters.emplace_back() ; + m_mTree[nId].m_vInters.back().nIn = 7 ; + } + else { + nId = vNeigh[0] ; + m_mTree[nId].m_vInters.emplace_back() ; + m_mTree[nId].m_vInters.back().nIn = 4 ; + } + } } else if ( nEdge == 6) { GetBottomNeigh( nId, vNeigh) ; - int nIdTemp = vNeigh.back() ; - vNeigh.clear() ; - GetRightNeigh( nIdTemp, vNeigh) ; - nId = vNeigh[0] ; - m_mTree[nId].m_vInters.emplace_back() ; - m_mTree[nId].m_vInters.back().nIn = 4 ; + GetRightNeigh( nId, vNeigh1) ; + INTVECTOR nPossible, nPossible1 ; + nPossible = FindCell( ptInters, clTrim, vNeigh) ; + nPossible1 = FindCell( ptInters, clTrim, vNeigh1) ; + // ingresso dall'alto + if ( ! nPossible.empty()) { + nId = nPossible.back() ; + m_mTree[nId].m_vInters.emplace_back() ; + 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 ; + } + // ingresso in diagonale + else { + if ( ! vNeigh.empty()){ + int nIdTemp = vNeigh.back() ; + vNeigh.clear() ; + GetRightNeigh( nIdTemp, vNeigh) ; + nId = vNeigh.back() ; + m_mTree[nId].m_vInters.emplace_back() ; + m_mTree[nId].m_vInters.back().nIn = 4 ; + } + else { + GetRightNeigh( nId, vNeigh) ; + nId = vNeigh[0] ; + m_mTree[nId].m_vInters.emplace_back() ; + m_mTree[nId].m_vInters.back().nIn = 5 ; + } + } } else if ( nEdge == 7) { GetRightNeigh( nId, vNeigh) ; - int nIdTemp = vNeigh.back() ; - vNeigh.clear() ; - GetTopNeigh( nIdTemp, vNeigh) ; - nId = vNeigh[0] ; - m_mTree[nId].m_vInters.emplace_back() ; - m_mTree[nId].m_vInters.back().nIn = 5 ; + GetTopNeigh( nId, vNeigh1) ; + INTVECTOR nPossible, nPossible1 ; + nPossible = FindCell( ptInters, clTrim, vNeigh) ; + nPossible1 = FindCell( ptInters, clTrim, vNeigh1) ; + // ingresso da sinistra + if ( ! nPossible.empty()) { + nId = nPossible.back() ; + m_mTree[nId].m_vInters.emplace_back() ; + 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 ; + } + // ingresso in diagonale + else { + if ( ! vNeigh.empty()) { + int nIdTemp = vNeigh.back() ; + vNeigh.clear() ; + GetTopNeigh( nIdTemp, vNeigh) ; + nId = vNeigh[0] ; + m_mTree[nId].m_vInters.emplace_back() ; + m_mTree[nId].m_vInters.back().nIn = 5 ; + } + else { + nId = vNeigh.back() ; + m_mTree[nId].m_vInters.emplace_back() ; + m_mTree[nId].m_vInters.back().nIn = 6 ; + } + } } // aggiungo l'intersezione al vettore delle intersezioni della prossima cella vptInters.push_back( ptInters) ; @@ -1801,14 +2070,42 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters) //---------------------------------------------------------------------------- bool -Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk) +Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk, PolyLine plCell) { + // conto quanti vertici in più ho per lato e creo un vettore dei vertici per lato + int nId = m_vnLeaves[nLeafId] ; + std::vector vEdgeVertex ; + Point3d ptTl(m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + Point3d ptBr(m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + vEdgeVertex.emplace_back() ; + vEdgeVertex.back().push_back( m_mTree[nId].GetTopRight()) ; + vEdgeVertex.emplace_back() ; + vEdgeVertex.back().push_back( ptTl) ; + vEdgeVertex.emplace_back() ; + vEdgeVertex.back().push_back( m_mTree[nId].GetBottomLeft()) ; + vEdgeVertex.emplace_back() ; + vEdgeVertex.back().push_back( ptBr) ; + // la PolyLine è riempita a partire dal lato bottom + Point3d ptStart ; + plCell.GetFirstPoint( ptStart) ; + INTVECTOR vEdge = { 2, 3, 0, 1} ; + for ( int p = 0 ; p < 4 ; ++ p) { + int j = vEdge[p] ; + int next = j +1 ; + if ( j == 3) + next = 0 ; + Point3d ptToAdd ; + while ( plCell.GetNextPoint( ptToAdd) && ! AreSamePointExact( ptToAdd, vEdgeVertex[next][0])) { + vEdgeVertex[j].push_back( ptToAdd) ; + } + } + + // comincio a costruire il poligono INTVECTOR vToCheckNow = vToCheck ; vToCheck.clear() ; // vettore dei poligoni ( loop) della cella nId POLYLINEVECTOR vCellPolygons ; // costruisco i poligoni partendo dal vettore delle intersezioni, come spiegato a pag15 di Cripps - int nId = m_vnLeaves[nLeafId] ; PolyLine plTrimmedPoly ; // numero di volte che la cella è stata attraversata da una curva di trim int nPassToCheck = (int) vToCheckNow.size() ; @@ -1817,6 +2114,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I // scorro sui vettori intersezione della cella nId e sui suoi vertici // in questo for analizzo solo i loop che tagliano la cella int nEdgeIn = -1 ; + int nFirstLoopInPoly = -1 ; for ( int w = 0 ; w < (int)vToCheckNow.size() ; ++ w) { int j = vToCheckNow[w] ; Inters inA = m_mTree[nId].m_vInters[j] ; @@ -1826,8 +2124,9 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I // salvo il lato di ingresso del primo lato del poligono che sto costruendo nEdgeIn = inA.nIn ; for ( Point3d ptInt : inA.vpt ) { - plTrimmedPoly.AddUPoint(c, ptInt) ; - ++c ; + AddVertex( nId, vEdgeVertex, plTrimmedPoly, c, ptInt) ; + //plTrimmedPoly.AddUPoint(c, ptInt) ; + //++c ; } nEdge = inA.nOut ; // se la curva è CW devo verifica di non essere uscito in un vertice, con un tratto sovrapposto al lato che ripercorrerò tra poco @@ -1838,8 +2137,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I Vector3d vLast = ptLast - ptSecondToLast ; vLast.Normalize(); Vector3d vEdge ; - if ( nEdge == 0 ) { - Point3d ptTl(m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + if ( AreSameEdge( nEdge, 0)) { if ( AreSamePointApprox(ptLast, ptTl) ) { vEdge = m_mTree[nId].GetBottomLeft() - ptTl ; vEdge.Normalize() ; @@ -1849,8 +2147,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I } } } - else if ( nEdge == 1 && AreSamePointApprox(ptLast, m_mTree[nId].GetBottomLeft()) ) { - Point3d ptBr(m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + else if ( AreSameEdge( nEdge, 1) && AreSamePointApprox(ptLast, m_mTree[nId].GetBottomLeft()) ) { vEdge = ptBr - m_mTree[nId].GetBottomLeft() ; vEdge.Normalize() ; if ( AreOppositeVectorApprox(vLast, vEdge) ) { @@ -1858,8 +2155,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I nEdge = 2 ; } } - else if ( nEdge == 2 ) { - Point3d ptBr(m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + else if ( AreSameEdge( nEdge, 2) ) { if ( AreSamePointApprox(ptLast, ptBr) ) { vEdge = m_mTree[nId].GetTopRight() - ptBr ; vEdge.Normalize() ; @@ -1869,8 +2165,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I } } } - else if ( nEdge == 3 && AreSamePointApprox(ptLast, m_mTree[nId].GetTopRight()) ) { - Point3d ptTl(m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + else if ( AreSameEdge( nEdge, 3) && AreSamePointApprox(ptLast, m_mTree[nId].GetTopRight()) ) { vEdge = ptTl - m_mTree[nId].GetTopRight() ; vEdge.Normalize() ; if ( AreOppositeVectorApprox(vLast, vEdge) ) { @@ -1899,34 +2194,35 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I // ciclo sui loop successivi per vedere se ne ho uno su questo lato con un valid start for ( int t = w ; t < nPassToCheck -1 ; ++ t) { - if ( nEdge == m_mTree[nId].m_vInters[j].nIn ) { + if ( AreSameEdge( nEdge, m_mTree[nId].m_vInters[j].nIn) ) { if ( m_mTree[nId].m_vInters[j].bCCW) { - bValidNextStart = ( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn == nEdge) && // loop successivo inizia su questo lato + bValidNextStart = ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge)) && // loop successivo inizia su questo lato ! CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; // in posizione giusta da essere concatenato } else { // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline - bValidNextStart = ( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn == nEdge) && + bValidNextStart = ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge)) && CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; } } else - bValidNextStart = true ; - if ( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn != nEdge || bValidNextStart) + bValidNextStart = CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; + if ( ! AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge) || bValidNextStart) break ; // se ho trovato un loop successivo che devo saltare, lo salvo e considero i loop più avanti. - if ( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn == nEdge && ! bValidNextStart){ + if ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge) && ! bValidNextStart){ ++ nSecondCheck ; vToCheck.push_back( t + 1) ; } } if ( m_mTree[nId].m_vInters[j].bCCW) { - bNotCameBack = m_mTree[nId].m_vInters[j].nIn != nEdge && // sono tornato al lato di ingresso di questo loop - nEdge != nEdgeIn ; // sono tornato sul lato di ingresso di questo poligono ( solo se la curva è CCW) + //bNotCameBack = ! AreSameEdge( m_mTree[nId].m_vInters[j].nIn, nEdge) && // sono tornato al lato di ingresso di questo loop + // ! AreSameEdge( nEdge, nEdgeIn) ; // sono tornato sul lato di ingresso di questo poligono ( solo se la curva è CCW) + bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ; } else { // il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline - if ( nEdge == nEdgeIn ) { + if ( AreSameEdge( nEdge, nEdgeIn)) { bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; bNotCameBack = bNotCameBack && !bBefore ; } @@ -1935,20 +2231,27 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I while ( ! bValidNextStart && bNotCameBack) { Point3d ptVert ; if ( nEdge == 0) { - ptVert.x = m_mTree[nId].GetBottomLeft().x ; - ptVert.y = m_mTree[nId].GetTopRight().y ; + //ptVert.x = m_mTree[nId].GetBottomLeft().x ; + //ptVert.y = m_mTree[nId].GetTopRight().y ; + ptVert = ptTl ; } - else if ( nEdge == 1) + else if ( nEdge == 1) { ptVert = m_mTree[nId].GetBottomLeft() ; - else if ( nEdge == 2) { - ptVert.x = m_mTree[nId].GetTopRight().x ; - ptVert.y = m_mTree[nId].GetBottomLeft().y ; } - else if ( nEdge == 3) + else if ( nEdge == 2) { + //ptVert.x = m_mTree[nId].GetTopRight().x ; + //ptVert.y = m_mTree[nId].GetBottomLeft().y ; + ptVert = ptBr ; + } + else if ( nEdge == 3) { ptVert = m_mTree[nId].GetTopRight() ; - plTrimmedPoly.AddUPoint( c, ptVert) ; - ++c ; - if ( nEdge != 3) + } + AddVertex( nId, vEdgeVertex, plTrimmedPoly, c, ptVert) ; + //plTrimmedPoly.AddUPoint( c, ptVert) ; + //++c ; + if ( nEdge > 3 && nEdge != 7) + nEdge = nEdge - 4 ; + else if ( nEdge < 3 ) ++ nEdge ; else nEdge = 0 ; @@ -1956,34 +2259,35 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I // aggiorno le condizioni per il while // ciclo sui loop successivi per vedere se ne ho uno su questo lato con un valid start for ( int t = w ; t < nPassToCheck -1 ; ++ t) { - if ( nEdge == m_mTree[nId].m_vInters[j].nIn ) { + if ( AreSameEdge( nEdge, m_mTree[nId].m_vInters[j].nIn) ) { if ( m_mTree[nId].m_vInters[j].bCCW) { - bValidNextStart = ( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn == nEdge) && // loop successivo inizia su questo lato + bValidNextStart = ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge)) && // loop successivo inizia su questo lato ! CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; // in posizione giusta da essere concatenato } else { // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline - bValidNextStart = ( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn == nEdge) && + bValidNextStart = ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge)) && CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; } } else - bValidNextStart = true ; - if ( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn != nEdge || bValidNextStart) + bValidNextStart = CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; + if ( ! AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge) || bValidNextStart) break ; // se ho trovato un loop successivo che devo saltare, lo salvo e considero i loop più avanti. - if ( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn == nEdge && ! bValidNextStart){ + if ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge) && ! bValidNextStart){ ++ nSecondCheck ; vToCheck.push_back( t + 1) ; } } if ( m_mTree[nId].m_vInters[j].bCCW) { - bNotCameBack = m_mTree[nId].m_vInters[j].nIn != nEdge && // sono tornato al lato di ingresso di questo loop - nEdge != nEdgeIn ; // sono tornato sul lato di ingresso di questo poligono ( solo se la curva è CCW) + //bNotCameBack = ! AreSameEdge( m_mTree[nId].m_vInters[j].nIn, nEdge) && // sono tornato al lato di ingresso di questo loop + // ! AreSameEdge( nEdge, nEdgeIn) ; // sono tornato sul lato di ingresso di questo poligono ( solo se la curva è CCW) + bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ; } else { - // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline - if ( nEdge == nEdgeIn ) { + // il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline + if ( AreSameEdge( nEdge, nEdgeIn)) { bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; bNotCameBack = bNotCameBack && !bBefore ; } @@ -1991,20 +2295,22 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I } // se ho trovato un altro loop salto all'inizio del for - if ( m_mTree[nId].m_vInters[vToCheckNow[w + 1 + nSecondCheck]].nIn == nEdge) { - w = w + nSecondCheck ; + // + //if ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[w + 1 + nSecondCheck]].nIn, nEdge) && bValidNextStart) { // qui ho aggiunto bValidNextStart///////////////////////// + if ( bValidNextStart) { /////////////////////////////// + w = w + nSecondCheck ; continue ; } } // non ho altri loop quindi aggiungo vertici finché torno al punto di partenza else { if ( m_mTree[nId].m_vInters[j].bCCW ) { - bNotCameBack = m_mTree[nId].m_vInters[j].nIn != nEdge && // sono tornato al lato di ingresso di questo loop - nEdge != nEdgeIn ; // sono tornato sul lato di ingresso di questo poligono ( solo se la curva è CCW) + bNotCameBack = ! AreSameEdge( m_mTree[nId].m_vInters[j].nIn, nEdge) && // sono tornato al lato di ingresso di questo loop + ! AreSameEdge( nEdge, nEdgeIn) ; // sono tornato sul lato di ingresso di questo poligono ( solo se la curva è CCW) } else { // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline - if ( nEdge == nEdgeIn ) { + if ( AreSameEdge( nEdge, nEdgeIn) ) { bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; bNotCameBack = bNotCameBack && ! bBefore ; } @@ -2012,30 +2318,35 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I while ( bNotCameBack) { Point3d ptVert ; if ( nEdge == 0) { - ptVert.x = m_mTree[nId].GetBottomLeft().x ; - ptVert.y = m_mTree[nId].GetTopRight().y ; + //ptVert.x = m_mTree[nId].GetBottomLeft().x ; + //ptVert.y = m_mTree[nId].GetTopRight().y ; + ptVert = ptTl ; } else if ( nEdge == 1) ptVert = m_mTree[nId].GetBottomLeft() ; else if ( nEdge == 2) { - ptVert.x = m_mTree[nId].GetTopRight().x ; - ptVert.y = m_mTree[nId].GetBottomLeft().y ; + //ptVert.x = m_mTree[nId].GetTopRight().x ; + //ptVert.y = m_mTree[nId].GetBottomLeft().y ; + ptVert = ptBr ; } else if ( nEdge == 3) ptVert = m_mTree[nId].GetTopRight() ; - plTrimmedPoly.AddUPoint( c, ptVert) ; - ++c ; - if ( nEdge != 3) + AddVertex( nId, vEdgeVertex, plTrimmedPoly, c, ptVert) ; + //plTrimmedPoly.AddUPoint( c, ptVert) ; + //++c ; + if ( nEdge > 3 && nEdge != 7) + nEdge = nEdge - 4 ; + else if ( nEdge < 3 ) ++ nEdge ; else nEdge = 0 ; // aggiorno le condizioni per il while if ( m_mTree[nId].m_vInters[j].bCCW ) { - bNotCameBack = m_mTree[nId].m_vInters[j].nIn != nEdge && - nEdge != nEdgeIn ; + bNotCameBack = ! AreSameEdge( m_mTree[nId].m_vInters[j].nIn, nEdge) && + ! AreSameEdge( nEdge, nEdgeIn) ; } else { - if ( nEdge == nEdgeIn ) { + if ( AreSameEdge( nEdge, nEdgeIn)) { bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; bNotCameBack = bNotCameBack && ! bBefore ; } @@ -2043,11 +2354,15 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I } } plTrimmedPoly.Close() ; - vCellPolygons.push_back( plTrimmedPoly) ; - vPolygons.push_back( vCellPolygons) ; - ++ nPoly ; - vnParentChunk.push_back( inA.nChunk) ; - vCellPolygons.clear() ; + double dArea ; + plTrimmedPoly.GetAreaXY( dArea) ; + if ( dArea > EPS_SMALL ) { + vCellPolygons.push_back( plTrimmedPoly) ; + vPolygons.push_back( vCellPolygons) ; + ++ nPoly ; + vnParentChunk.push_back( inA.nChunk) ; + vCellPolygons.clear() ; + } c = 0 ; plTrimmedPoly.Clear() ; nEdgeIn = -1 ; @@ -2078,7 +2393,7 @@ Tree::CreateIslandAndHoles( int nLeafId, std::vector& vPolygons, // numero dei loop interni passati int n = 0 ; Inters inA = m_mTree[nId].m_vInters[n] ; - if ( m_mTree[nId].m_nFlag == 2 && inA.nOut == -3) { + 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() ; plInLoop.AddUPoint( 0, ptVert) ; @@ -2143,6 +2458,7 @@ Tree::CreateIslandAndHoles( int nLeafId, std::vector& vPolygons, bool Tree::CheckIfBefore( PolyLine& pl, int nEdge) const { + // controllo se ptEnd è prima di ptStart sul lato nEdge rispetto al senso antiorario ( quindi se è dopo in senso orario) Point3d ptStart, ptEnd ; pl.GetFirstPoint( ptStart) ; pl.GetLastPoint( ptEnd) ; @@ -2161,24 +2477,381 @@ Tree::CheckIfBefore( PolyLine& pl, int nEdge) const return false ; } +//---------------------------------------------------------------------------- +bool +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[0]) ; + pl.AddUPoint( 1, inA.vpt.back()) ; + INTVECTOR vEdges = { 7, 0, 4, 1, 5, 2, 6} ; + // controllo se nEdge1 viene prima di nEdge2. la partenza è da ptTR e l'arrivo è ptBr + + INTVECTOR :: iterator iter1 = find( vEdges.begin(), vEdges.end(), nEdge1) ; + int nPos1 = std::distance( vEdges.begin(), iter1) ; + INTVECTOR :: iterator iter2 = find( vEdges.begin(), vEdges.end(), nEdge2) ; + int nPos2 = std::distance( vEdges.begin(), iter2) ; + if ( nPos1 < nPos2) + return true ; + else if ( nPos1 > nPos2) + return false ; + // nPos1 == nPos2 + else { + if ( CheckIfBefore( pl, vEdges[nPos1])) { + return true ; + } + else + return false ; + } +} + +//---------------------------------------------------------------------------- +bool +Tree::CheckIfBefore( int& nEdge1, Point3d& ptP1, int& nEdge2, Point3d& ptP2) const +{ + INTVECTOR vEdges = { 7, 0, 4, 1, 5, 2, 6} ; + // controllo se nEdge1 viene prima di nEdge2. la partenza è da ptTR e l'arrivo è ptBr + INTVECTOR :: iterator iter1 = find( vEdges.begin(), vEdges.end(), nEdge1) ; + int nPos1 = std::distance( vEdges.begin(), iter1) ; + INTVECTOR :: iterator iter2 = find( vEdges.begin(), vEdges.end(), nEdge2) ; + int nPos2 = std::distance( vEdges.begin(), iter2) ; + if ( nPos1 < nPos2) + return true ; + else if ( nPos1 > nPos2) + return false ; + // ( nPos1 == nPos2) + else { + PolyLine pl ; + pl.AddUPoint( 0, ptP2) ; + pl.AddUPoint( 1, ptP1) ; + if ( CheckIfBefore( pl, vEdges[nPos1])) + return true ; + else + return false ; + } +} + //---------------------------------------------------------------------------- bool Tree::CheckIfAfter( PolyLine& pl, Point3d& ptNextStart, int nEdge) const { + // controllo se ptNextStart è più avanti rispetto a ptEnd in senso antiorario + + // se i punti non sono sullo stesso lato ritorno false Point3d ptEnd ; pl.GetLastPoint( ptEnd) ; if ( nEdge == 0 ) { - return ptEnd.x > ptNextStart.x ; + if ( ptNextStart.y > ptEnd.y - EPS_SMALL && ptNextStart.y < ptEnd.y + EPS_SMALL) + return ptEnd.x > ptNextStart.x ; + else + return false ; } else if ( nEdge == 1 ) { - return ptEnd.y > ptNextStart.y ; + if ( ptNextStart.x > ptEnd.x - EPS_SMALL && ptNextStart.x < ptEnd.x + EPS_SMALL) + return ptEnd.y > ptNextStart.y ; + else + return false ; } else if ( nEdge == 2 ) { - return ptEnd.x < ptNextStart.x ; + if ( ptNextStart.y > ptEnd.y - EPS_SMALL && ptNextStart.y < ptEnd.y + EPS_SMALL) + return ptEnd.x < ptNextStart.x ; + else + return false ; } else if ( nEdge == 3 ) { - return ptEnd.y < ptNextStart.y ; + if ( ptNextStart.x > ptEnd.x - EPS_SMALL && ptNextStart.x < ptEnd.x + EPS_SMALL) + return ptEnd.y < ptNextStart.y ; + else + return false ; } return false ; } +//---------------------------------------------------------------------------- +bool +Tree::AreSameEdge( int nEdge1, int nEdge2) const +{ + if ( nEdge1 == 0) { + if ( nEdge2 == 4 || nEdge2 == 0 || nEdge2 == 7) + return true; + else + return false ; + } + else if ( nEdge1 == 1) { + if ( nEdge2 == 4 || nEdge2 == 1 || nEdge2 == 5) + return true; + else + return false ; + } + else if ( nEdge1 == 2) { + if ( nEdge2 == 6 || nEdge2 == 2 || nEdge2 == 5) + return true; + else + return false ; + } + else if ( nEdge1 == 3) { + if ( nEdge2 == 6 || nEdge2 == 3 || nEdge2 == 7) + return true; + else + return false ; + } + else if ( nEdge1 == 4) { + if ( nEdge2 == 0 || nEdge2 == 1 || nEdge2 == 7 || nEdge2 == 5) + return true; + else + return false ; + } + else if ( nEdge1 == 5) { + if ( nEdge2 == 2 || nEdge2 == 1 || nEdge2 == 4 || nEdge2 == 6) + return true; + else + return false ; + } + else if ( nEdge1 == 6) { + if ( nEdge2 == 2 || nEdge2 == 3 || nEdge2 == 5 || nEdge2 == 7) + return true; + else + return false ; + } + else if ( nEdge1 == 7) { + if ( nEdge2 == 0 || nEdge2 == 3 || nEdge2 == 4 || nEdge2 == 6) + return true; + else + return false ; + } + else + return false ; +} + +//---------------------------------------------------------------------------- +bool +Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimmedPoly, int& c, Point3d& ptToAdd) const +{ + 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) ; + Point3d ptBL = m_mTree.at(nId).GetBottomLeft() ; + Point3d ptTR = m_mTree.at(nId).GetTopRight() ; + Point3d ptLast ; + plTrimmedPoly.GetLastPoint( ptLast) ; + // verifico di essere allineato con un lato, sennò aggiungo e basta + Vector3d vDir = ptToAdd - ptLast ; + vDir.Normalize() ; + if ( abs( vDir.x) > 1 - EPS_SMALL || abs( vDir.y) > 1 - EPS_SMALL) { + // se su un edge devo fare dei controlli + // edge 0 + if ( ptToAdd.x >= ptBL.x && ptToAdd.x <= ptTR.x && ptToAdd.y == ptTR.y && abs(vDir.x) > 1 - EPS_SMALL) { + for ( int t = 0 ; t < (int)vEdgeVertex[0].size() ; ++ t) { + Point3d ptIntermed = vEdgeVertex[0][t] ; + if ( ptIntermed.x > ptToAdd.x ) { + plTrimmedPoly.AddUPoint( c, ptIntermed) ; + ++ c ; + } + else + break ; + } + plTrimmedPoly.AddUPoint( c, ptToAdd) ; + ++ c ; + } + // edge 1 + else if ( ptToAdd.y >= ptBL.y && ptToAdd.y <= ptTR.y && ptToAdd.x == ptBL.x && abs(vDir.y) > 1 - EPS_SMALL) { + for ( int t = 0 ; t < (int)vEdgeVertex[1].size() ; ++ t) { + Point3d ptIntermed = vEdgeVertex[1][t] ; + if ( ptIntermed.y > ptToAdd.y ) { + plTrimmedPoly.AddUPoint( c, ptIntermed) ; + ++ c ; + } + else + break ; + } + plTrimmedPoly.AddUPoint( c, ptToAdd) ; + ++ c ; + } + // edge 2 + else if ( ptToAdd.x >= ptBL.x && ptToAdd.x <= ptTR.x && ptToAdd.y == ptBL.y && abs(vDir.x) > 1 - EPS_SMALL) { + for ( int t = 0 ; t < (int)vEdgeVertex[2].size() ; ++ t) { + Point3d ptIntermed = vEdgeVertex[2][t] ; + if ( ptIntermed.x < ptToAdd.x ) { + plTrimmedPoly.AddUPoint( c, ptIntermed) ; + ++ c ; + } + else + break ; + } + plTrimmedPoly.AddUPoint( c, ptToAdd) ; + ++ c ; + } + // edge 3 + else if ( ptToAdd.y >= ptBL.y && ptToAdd.y <= ptTR.y && ptToAdd.x == ptTR.x && abs(vDir.y) > 1 - EPS_SMALL) { + for ( int t = 0 ; t < (int)vEdgeVertex[3].size() ; ++ t) { + Point3d ptIntermed = vEdgeVertex[3][t] ; + if ( ptIntermed.y < ptToAdd.y ) { + plTrimmedPoly.AddUPoint( c, ptIntermed) ; + ++ c ; + } + else + break ; + } + plTrimmedPoly.AddUPoint( c, ptToAdd) ; + ++ c ; + } + // sono allineato con un lato, ma NON sono su un lato + // aggiungo e basta + else { + plTrimmedPoly.AddUPoint( c, ptToAdd); + ++ c ; + } + } + // non su un edge, quindi aggiungo e basta + else { + plTrimmedPoly.AddUPoint( c, ptToAdd); + ++ c ; + } + return true ; +} + +////---------------------------------------------------------------------------- +//bool +//Tree::SetRightEdgeIn( int nId, std::vector& vEdgeVertex, PolyLine& plTrimmedPoly) +//{ +// Point3d ptBr( m_mTree.at(nId).GetTopRight().x , m_mTree.at(nId).GetBottomLeft().y) ; +// Point3d ptTR = m_mTree.at(nId).GetTopRight() ; +// int nPos0 = -1 , nPos1 = -1 ; +// bool bSave = false ; +// PNTLIST lPtInt ; +// for ( int k = 0 ; k < plTrimmedPoly.GetPointNbr() ; ++ k) { +// Point3d ptIter ; +// plTrimmedPoly. GetNextPoint( ptIter) ; +// if ( AreSamePointExact( ptIter, ptBr) ) { +// nPos0 = k ; +// bSave = bSave ^ true ; +// } +// if ( AreSamePointExact( ptIter, ptTR) ) { +// nPos1 = k ; +// bSave = bSave ^ true ; +// } +// if ( bSave) { +// lPtInt.push_back( ptIter) ; +// } +// } +// lPtInt.pop_front() ; +// // verifico se ci sono tutti e due i punti +// if ( nPos0 != -1 && nPos1 != -1 ) { +// // se sono di seguito tutto il lato destro è dentro +// if ( nPos1 == nPos0 + 1 || nPos0 == nPos1 + 1) { +// m_mTree[nId].m_nRightEdgeIn = 1 ; +// } +// // ci sono dei punti in mezzo, devo capire se sono allineati o no +// else { +// // verifico se tutti i punti intermedi sono allineati o no +// CurveLine clRightEdge ; +// clRightEdge.Set( ptBr, ptTR) ; +// bool bAllOn = true ; +// +// PNTLIST::iterator lIter = lPtInt.begin() ; +// std::advance(lIter, 0) ; +// for ( int p = 0 ; p < (int)lPtInt.size() ; ++ p) { +// if ( ! clRightEdge.IsPointOn( *lIter)) { +// bAllOn = false ; +// break ; +// } +// } +// // divisi da punti allineati e quindi lato dentro +// if ( bAllOn) { +// m_mTree[nId].m_nRightEdgeIn = 1 ; +// } +// // se sono dentro, ma non allineati, allora solo in parte +// else { +// m_mTree[nId].m_nRightEdgeIn = 2 ; +// } +// } +// } +// // il lato destro è sicuramente esterno +// else { +// m_mTree[nId].m_nRightEdgeIn = 0 ; +// } +// return true ; +//} + +//---------------------------------------------------------------------------- +bool +Tree::SetRightEdgeIn( int nId) +{ + Point3d ptBr( m_mTree.at(nId).GetTopRight().x , m_mTree.at(nId).GetBottomLeft().y) ; + Point3d ptTR = m_mTree.at(nId).GetTopRight() ; + // se ho inters sul lato destro allora in parte è dentro + 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 ) { + 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 ; + bDone = true ; + break ; + } + } + // se non ho inters sul lato destro devo verificare se è tutto dentro o tutto fuori + if ( ! bDone) { + // ciclo sulle inters e cerco se ho dei passaggi con un'uscita più bassa di un'entrata e se eventualmente è la più a destra! + bool bFound = false ; + bool bRightMost = false ; + int nEdgeIn = 6, nEdgeOut = 7, nLoop ; + Point3d ptIn, ptOut ; + for ( int k = 0 ; k < nPass ; ++ k) { + // trovo il loop che ha l'ingresso o l'uscita più a destra + if ( CheckIfBefore( m_mTree[nId].m_vInters[k].nIn, m_mTree[nId].m_vInters[k].vpt[0], nEdgeIn, ptIn) || + CheckIfBefore( nEdgeOut, ptOut, m_mTree[nId].m_vInters[k].nOut, m_mTree[nId].m_vInters[k].vpt.back())) { + nLoop = k ; + nEdgeIn = m_mTree[nId].m_vInters[k].nIn ; + ptIn = m_mTree[nId].m_vInters[k].vpt[0] ; + nEdgeOut = m_mTree[nId].m_vInters[k].nOut ; + ptOut = m_mTree[nId].m_vInters[k].vpt.back() ; + bFound = true ; + } + } + if ( bFound && CheckIfBefore( m_mTree[nId].m_vInters[nLoop])) { + bRightMost = true ; + } + // se il mio campione attraversa dall'alto al basso allora il lato destro è dentro!!! + if ( bFound && bRightMost) + m_mTree[nId].m_nRightEdgeIn = 1 ; + else + m_mTree[nId].m_nRightEdgeIn = 0 ; + + } + + if ( m_mTree[nId].m_nRightEdgeIn != -1) + return true ; + else + return false ; +} + +//---------------------------------------------------------------------------- +bool +Tree::CategorizeCell( int& nId) +{ + //if ( m_mTree[nId].m_nFlag != -1) { + // return true ; + //} + //INTVECTOR vNeigh ; + //GetLeftNeigh( nId, vNeigh) ; + //// mi servono i vicini di sinistra per capire se sono dentro il loop o fuori + //// 0 right edge fuori, 1 right edge dentro, 2 metà e metà + //if ( ) { + + //} + // m_mTree[nId].m_nFlag2 = 1 ; + return true ; +} diff --git a/Tree.h b/Tree.h index b442371..d3ab143 100644 --- a/Tree.h +++ b/Tree.h @@ -24,6 +24,7 @@ struct Inters { PNTVECTOR vpt ; int nOut ; bool bCCW ; + bool bVertex ; 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 @@ -115,14 +116,22 @@ private : void GetRightNeigh( int nId, INTVECTOR& vRightNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato right void GetRootNeigh( int nEdge, INTVECTOR& vNeigh) ; // restituisce le foglie dell'albero che sono adiacenti al lato nEdge, numerato a partire dal top ( 0) in senso antiorario void ResetTree ( void) ; // resetto m_bProcessed a false per tutti i nodi dell'albero - int FindCell ( const Point3d& ptToAssign) const ; // dato un punto, trova la cella foglia a cui appartiene + INTVECTOR FindCell ( const Point3d& ptToAssign, CurveLine& cl) const ; // dato un punto, trova la cella foglia a cui appartiene + INTVECTOR FindCell ( const Point3d& ptToAssign, CurveLine& cl, INTVECTOR vCells) const ; // dato un punto, trova la cella foglia a cui appartiene bool TraceLoopLabelCell( void) ; // tracing dei loop e labelling delle celle - bool FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters) ; // trova le intersezioni tra una cella e una linea di trim + bool FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVertex) ; // trova le intersezioni tra una cella e una linea di trim // resituisce l'id della cella verso cui la curva di trim esce e il vettore delle intersezioni per la cella successiva con il primo punto - bool CreateCellPolygons ( int nLeafId, std::vector& vPolygons, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk) ; + bool CreateCellPolygons ( int nLeafId, std::vector& vPolygons, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk, PolyLine plCell) ; bool CreateIslandAndHoles ( int nLeafId, std::vector& vPolygons, int& nPoly, INTVECTOR& vnParentChunk) ; bool CheckIfBefore( PolyLine& pl, int nEdge) const ; + bool CheckIfBefore( Inters& inA) const ; + bool CheckIfBefore( int& nEdge1, Point3d& ptP1, int& nEdge2, Point3d& ptP2) const ; bool CheckIfAfter( PolyLine& pl, Point3d& ptNextStart, int nEdge) const ; + bool AreSameEdge( int nEdge1, int nEdge2) const ; + bool AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimmedPoly, int& c, Point3d& ptToAdd) const ; + //bool SetRightEdgeIn( int nId, std::vector& vEdgeVertex, PolyLine& plTrimmedPoly) ; + bool SetRightEdgeIn( int nId) ; + bool CategorizeCell( int& nId) ; private : const SurfBezier* m_pSrfBz ; // superficie di bezier From 71ac2fde826e96549b9f26233d5f96eefd6d48a1 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 5 Jun 2023 12:12:47 +0200 Subject: [PATCH 10/44] =?UTF-8?q?EgtGeomKernel=20:=20-=20aggiunte=20tutte?= =?UTF-8?q?=20le=20funzionalit=C3=A0=20per=20la=20gestione=20delle=20super?= =?UTF-8?q?fici=20di=20bezier=20con=20spazio=20parametrico=20trimmato=20Ma?= =?UTF-8?q?nca=20:=20-=20debug.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Tree.cpp | 264 +++++++++++++++++++++++++++++++++++++++++-------------- Tree.h | 2 +- 2 files changed, 200 insertions(+), 66 deletions(-) diff --git a/Tree.cpp b/Tree.cpp index f64fdf3..eaf7ffd 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -1198,28 +1198,37 @@ Tree::GetPolygons( std::vector& vPolygons) { // scorro sui poligoni delle celle non trimmate int nCells = (int)vPolygonsBasic.size() ; for ( int i = 0 ; i < nCells ; ++i ) { - // vettore dei poligoni ( loop) della cella nId - POLYLINEVECTOR vCellPolygons ; + // costruisco i poligoni partendo dal vettore delle intersezioni, come spiegato a pag15 di Cripps int nId = m_vnLeaves[i] ; - // vettore in cui salvo il chunk di appartenenza di ogni loop che attraversa la cella - INTVECTOR vnParentChunk ; - //int nEdgeIn = -1 ; - // vettore in cui salvo i loop che non appartengono al poligono che sto cotruendo nel ciclo attuale e da cui ripasserò dopo - INTVECTOR vToCheck( (int) m_mTree[nId].m_vInters.size()) ; - std::generate_n( vToCheck.begin(), (int) m_mTree[nId].m_vInters.size(), generator()) ; - // numero di poligoni aggiunti - int nPoly = 0 ; - // scorro sui vettori intersezione della cella nId e sui suoi vertici - // in questo for analizzo solo i loop che tagliano la cella - while( nPoly == 0 || (int)vToCheck.size() != 0) { - int nPolyBefore = nPoly ; - CreateCellPolygons( i, vPolygons, vToCheck, nPoly, vnParentChunk, vPolygonsBasic[i]) ; - if ( nPolyBefore == nPoly) - break ; + if ( m_mTree[nId].m_nFlag == 4) { + // vettore dei poligoni ( loop) della cella nId + POLYLINEVECTOR vCellPolygons ; + vCellPolygons.push_back( vPolygonsBasic[i]) ; + vPolygons.push_back( vCellPolygons) ; + } + else if ( m_mTree[nId].m_nFlag == 0) + continue ; + else { + // vettore in cui salvo il chunk di appartenenza di ogni loop che attraversa la cella + INTVECTOR vnParentChunk ; + //int nEdgeIn = -1 ; + // vettore in cui salvo i loop che non appartengono al poligono che sto cotruendo nel ciclo attuale e da cui ripasserò dopo + INTVECTOR vToCheck( (int) m_mTree[nId].m_vInters.size()) ; + std::generate_n( vToCheck.begin(), (int) m_mTree[nId].m_vInters.size(), generator()) ; + // numero di poligoni aggiunti + int nPoly = 0 ; + // scorro sui vettori intersezione della cella nId e sui suoi vertici + // in questo for analizzo solo i loop che tagliano la cella + while( nPoly == 0 || (int)vToCheck.size() != 0) { + int nPolyBefore = nPoly ; + CreateCellPolygons( i, vPolygons, vToCheck, nPoly, vnParentChunk, vPolygonsBasic[i]) ; + if ( nPolyBefore == nPoly) + break ; + } + // ora analizzo anche i loop che sono contenuti nella cella + CreateIslandAndHoles( i, vPolygons, nPoly, vnParentChunk) ; } - // ora analizzo anche i loop che sono contenuti nella cella - CreateIslandAndHoles( i, vPolygons, nPoly, vnParentChunk) ; } return true; } @@ -1608,6 +1617,7 @@ Tree::TraceLoopLabelCell( void) Point3d ptLast = m_mTree[nId].m_vInters.back().vpt.back() ; Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + int nLastId ; if ( AreSamePointApprox( m_mTree[nId].GetTopRight(), ptLast) || AreSamePointApprox( ptTl, ptLast) || AreSamePointApprox( m_mTree[nId].GetBottomLeft(), ptLast) || @@ -1618,12 +1628,14 @@ Tree::TraceLoopLabelCell( void) CurveLine clTrim ; clTrim.Set( ptStart, ptEnd) ; vptInters.clear() ; + nLastId = nId ; FindInters( nId, clTrim, vptInters, bVertex) ; + m_mTree[nLastId].m_vInters.back().vpt.push_back( vptInters[0]) ; } int nOut = m_mTree[nId].m_vInters[nPass].nOut ; m_mTree[nId].m_vInters.back().vpt.insert( m_mTree[nId].m_vInters.back().vpt.end(), - m_mTree[nId].m_vInters[nPass].vpt.begin(), - m_mTree[nId].m_vInters[nPass].vpt.end()) ; + m_mTree[nId].m_vInters[nPass].vpt.begin(), + m_mTree[nId].m_vInters[nPass].vpt.end()) ; m_mTree[nId].m_vInters[nPass] = m_mTree[nId].m_vInters.back() ; m_mTree[nId].m_vInters.pop_back() ; // sistemo il lato d'uscita @@ -1668,6 +1680,7 @@ Tree::TraceLoopLabelCell( void) } else { //categorizzo la cella/////////////////////////////////////////////////////////// m_mTree[nCell].m_nFlag2 = 1 ; + CategorizeCell( nCell) ; } if ( ! m_mTree[nCell].IsProcessed()) { @@ -1702,6 +1715,7 @@ Tree::TraceLoopLabelCell( void) if ( nCell == nLastLeft && m_mTree[nCell].IsProcessed() ) { // categorizzo//////////////////////////////////////////////////////////////////////////// m_mTree[nCell].m_nFlag2 = 1 ; + CategorizeCell( nCell) ; bAllDone = true ; break ; } @@ -1757,6 +1771,8 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert 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 + bool bIntersFound = false ; + Point3d ptInters ; if ( ptEnd.y >= ptTR.y && ptEnd.x <= ptTR.x) { nEdge = 0 ; // lato sopra @@ -1766,6 +1782,11 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert //else //if ( ptEnd.x < ptBL.x) if ( ptEnd.x < ptBL.x) clEdge2.Set( ptTl, ptBL) ; + else if ( AreSamePointExact( ptEnd, ptTl)) { + nEdge = 4 ; + ptInters = ptTl ; + bIntersFound = true ; + } } else if ( ptEnd.x <= ptBL.x && ptEnd.y <= ptTR.y) { nEdge = 1 ; @@ -1777,6 +1798,11 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert //else //if ( ptEnd.y < ptBL.y) if ( ptEnd.y < ptBL.y) clEdge2.Set( ptBL, ptBr) ; + else if ( AreSamePointExact( ptEnd, ptBL)) { + nEdge = 5 ; + ptInters = ptBL ; + bIntersFound = true ; + } } else if ( ptEnd.y <= ptBL.y && ptEnd.x >= ptBL.x) { nEdge = 2 ; @@ -1788,6 +1814,11 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert //else //if ( ptEnd.x > ptTR.x) if ( ptEnd.x > ptTR.x) clEdge2.Set( ptBr, ptTR) ; + else if ( AreSamePointExact( ptEnd, ptBr)) { + nEdge = 6 ; + ptInters = ptBr ; + bIntersFound = true ; + } } else if ( ptEnd.x >= ptTR.x && ptEnd.y >= ptBL.y) { nEdge = 3 ; @@ -1799,50 +1830,56 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert //else //if ( ptEnd.y > ptTR.y) if ( ptEnd.y > ptTR.y) clEdge2.Set( ptTR, ptTl) ; + else if ( AreSamePointExact( ptEnd, ptTR)) { + nEdge = 7 ; + ptInters = ptTR ; + bIntersFound = true ; + } } else return false ; - // intersezione e controlli - IntersLineLine illExit( clTrim, clEdge, true) ; - IntCrvCrvInfo aInfo, aInfo2 ; - Point3d ptInters ; - //if ( ! illExit.GetIntCrvCrvInfo( aInfo) ) - // return false ; - illExit.GetIntCrvCrvInfo( aInfo) ; - if ( clEdge2.IsValid()){ - IntersLineLine illExit2( clTrim, clEdge2, true) ; - //if ( ! illExit2.GetIntCrvCrvInfo( aInfo2) ) + if ( ! bIntersFound) { + // intersezione e controlli + IntersLineLine illExit( clTrim, clEdge, true) ; + IntCrvCrvInfo aInfo, aInfo2 ; + //if ( ! illExit.GetIntCrvCrvInfo( aInfo) ) // return false ; - // verifico su quale dei due lati ho l'intersezione - if ( ! illExit2.GetIntCrvCrvInfo( aInfo2)) - ptInters = aInfo.IciA[0].ptI ; - else { - // solo intersezione sul lato 2 - if ( illExit.GetNumInters() == 0 ) { - ptInters = aInfo2.IciA[0].ptI ; - if ( nEdge > 3 && nEdge != 7) - nEdge = nEdge - 4 ; - else if ( nEdge < 3 ) - ++ nEdge ; - else - nEdge = 0 ; - } - // intersezione sul vertice della cella + illExit.GetIntCrvCrvInfo( aInfo) ; + if ( clEdge2.IsValid()){ + IntersLineLine illExit2( clTrim, clEdge2, true) ; + //if ( ! illExit2.GetIntCrvCrvInfo( aInfo2) ) + // return false ; + // verifico su quale dei due lati ho l'intersezione + if ( ! illExit2.GetIntCrvCrvInfo( aInfo2)) + ptInters = aInfo.IciA[0].ptI ; else { - ptInters = aInfo2.IciA[0].ptI ; - bVertex = true ; - // la cella adiacente in diagonale a quel vertice - nEdge = nEdge + 4 ; + // solo intersezione sul lato 2 + if ( illExit.GetNumInters() == 0 ) { + ptInters = aInfo2.IciA[0].ptI ; + if ( nEdge > 3 && nEdge != 7) + nEdge = nEdge - 4 ; + else if ( nEdge < 3 ) + ++ nEdge ; + else + nEdge = 0 ; + } + // intersezione sul vertice della cella + else { + ptInters = aInfo2.IciA[0].ptI ; + bVertex = true ; + // la cella adiacente in diagonale a quel vertice + nEdge = nEdge + 4 ; + } } } + else + ptInters = aInfo.IciA[0].ptI ; } - else - ptInters = aInfo.IciA[0].ptI ; 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 - m_mTree[nId].m_vInters.back().vpt = vptInters ; + m_mTree[nId].m_vInters.back().vpt = vptInters ; // al posto di .vpt = vptInters metto un push_back //////////////////////////////////////////////// vptInters.clear() ; // setto la categoria della cella if ( m_mTree[nId].m_nFlag == -1) @@ -2356,7 +2393,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I plTrimmedPoly.Close() ; double dArea ; plTrimmedPoly.GetAreaXY( dArea) ; - if ( dArea > EPS_SMALL ) { + if ( dArea > SQ_EPS_SMALL) { vCellPolygons.push_back( plTrimmedPoly) ; vPolygons.push_back( vCellPolygons) ; ++ nPoly ; @@ -2481,6 +2518,7 @@ Tree::CheckIfBefore( PolyLine& pl, int nEdge) const bool Tree::CheckIfBefore( Inters& inA) const { + // controllo se l'ingresso è prima dell'uscita int nEdge1 = inA.nIn ; int nEdge2 = inA.nOut ; PolyLine pl ; @@ -2804,11 +2842,12 @@ Tree::SetRightEdgeIn( int nId) } // se non ho inters sul lato destro devo verificare se è tutto dentro o tutto fuori if ( ! bDone) { - // ciclo sulle inters e cerco se ho dei passaggi con un'uscita più bassa di un'entrata e se eventualmente è la più a destra! + // ciclo sulle inters e cerco quella più a destra, se ha un'uscita più bassa di un'entrata allora il right edge è compreso! bool bFound = false ; bool bRightMost = false ; int nEdgeIn = 6, nEdgeOut = 7, nLoop ; Point3d ptIn, ptOut ; + ptIn = ptOut = m_mTree[nId].GetBottomLeft() ; for ( int k = 0 ; k < nPass ; ++ k) { // trovo il loop che ha l'ingresso o l'uscita più a destra if ( CheckIfBefore( m_mTree[nId].m_vInters[k].nIn, m_mTree[nId].m_vInters[k].vpt[0], nEdgeIn, ptIn) || @@ -2842,16 +2881,111 @@ Tree::SetRightEdgeIn( int nId) bool Tree::CategorizeCell( int& nId) { - //if ( m_mTree[nId].m_nFlag != -1) { - // return true ; - //} - //INTVECTOR vNeigh ; - //GetLeftNeigh( nId, vNeigh) ; - //// mi servono i vicini di sinistra per capire se sono dentro il loop o fuori - //// 0 right edge fuori, 1 right edge dentro, 2 metà e metà - //if ( ) { + if ( m_mTree[nId].m_nFlag != -1) { + return true ; + } + INTVECTOR vNeigh, vNeigh1 ; + GetLeftNeigh( nId, vNeigh) ; + // mi servono i vicini di sinistra per capire se sono dentro il loop o fuori + // nRightEdgeIn // 0 right edge fuori, 1 right edge dentro, 2 metà e metà + // nFlag // 0 fuori, 1 intersecata, 2 contiene loop, 3 = 1 & 2, 4 dentro + if ( (int)vNeigh.size() == 0 ) { + m_mTree[nId].m_nFlag = 0 ; + } + else if ( (int)vNeigh.size() == 1) { + 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 ; + // 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 ) { + // guardo le intersezioni a mano + // + //int nPass = (int) m_mTree[vNeigh[0]].m_vInters.size() ; + //for ( int p = 0 ; p < nPass ; ++p ) { + // // se ho almeno un ingresso o un'uscita + // if ( ) { + + // } + // else { + // m_mTree[nId].m_nFlag == 0 ; + // } + //} + GetBottomNeigh( nId, vNeigh1) ; + int nNeigh = vNeigh1[0] ; + if ( m_mTree[nNeigh].m_nFlag == 0 || m_mTree[nNeigh].m_nFlag == 2) { + m_mTree[nId].m_nFlag = 0 ; + } + else if ( m_mTree[nNeigh].m_nFlag == 4) { + m_mTree[nId].m_nFlag = 4 ; + } + else if ( m_mTree[nNeigh].m_nFlag == 1 || m_mTree[nNeigh].m_nFlag == 3) { + if ( m_mTree[nNeigh].m_nRightEdgeIn == 0) + m_mTree[nId].m_nFlag = 0 ; + else if ( m_mTree[nNeigh].m_nRightEdgeIn == 1) + m_mTree[nId].m_nFlag = 4 ; + else if ( m_mTree[nNeigh].m_nRightEdgeIn == 2 ) { + // in questo caso devo verificare le intersezioni sul lato destro del vicino bottom + // scorro e cerco l'intersezione più alta, se è out la cella è dentro, se è in devo verificare l'out se è più a sinistra o a destra. + int nPass = (int) m_mTree[nNeigh].m_vInters.size() ; + bool bTopMost = false ; + bool bFound = false; + Point3d ptInters, ptBr( m_mTree[nNeigh].GetTopRight().x, m_mTree[nNeigh].GetBottomLeft().y) ; + ptInters = ptBr ; // inizializzato a vertice bottom right + int nEdgeIn = 3, nEdgeOut = 3, nLoop ; + 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))) { + 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)) { + nLoop = r ; + ptInters = m_mTree[nNeigh].m_vInters[r].vpt.back() ; + bFound = true ; + } + } + if ( bFound && CheckIfBefore( m_mTree[nNeigh].m_vInters[nLoop])) { + bTopMost = true ; + } + if ( bFound && bTopMost) { + if ( AreSameEdge(m_mTree[nNeigh].m_vInters[nLoop].nIn, 3) && AreSameEdge(m_mTree[nNeigh].m_vInters[nLoop].nOut, 3) ) { + if ( CheckIfBefore( m_mTree[nNeigh].m_vInters[nLoop])) + m_mTree[nId].m_nFlag = 4 ; + else + m_mTree[nId].m_nFlag = 0 ; + } + else if ( AreSameEdge(m_mTree[nId].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 + Point3d ptOut = m_mTree[nNeigh].m_vInters[nLoop].vpt.back() ; + Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + if ( ptOut.x >= ptBr.x) + m_mTree[nId].m_nFlag = 4 ; + else + m_mTree[nId].m_nFlag = 0 ; + } + } + } + } + } + } + else { + for ( int r = 0 ; r < (int)vNeigh.size() ; ++ r) { + if ( m_mTree[vNeigh[r]].m_nRightEdgeIn == 1) { + m_mTree[nId].m_nFlag = 4 ; + break ; + } + else if ( m_mTree[vNeigh[r]].m_nRightEdgeIn == 0) { + m_mTree[nId].m_nFlag = 0 ; + break ; + } + } + } - //} - // m_mTree[nId].m_nFlag2 = 1 ; return true ; } diff --git a/Tree.h b/Tree.h index d3ab143..369acba 100644 --- a/Tree.h +++ b/Tree.h @@ -75,8 +75,8 @@ class Cell int m_nChild1 ; // prima cella figlio int m_nChild2 ; // seconda cella figlio int m_nFlag ; // falg che indica la caratterizzazione della cella rispetto ai loop di trim - int m_nFlag2 ; // falg che indica se la cella è stata attraversata durante l'ultima fase del labelling // 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à INTVECTOR m_vnLoop ; // indice dei loop contenuti nella cella std::vector m_vInters ; // vettore delle intersezioni della cella con i loop di trim From 579bc5492c8f057417153e5c929a7932f46abbd3 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 6 Jun 2023 10:40:03 +0200 Subject: [PATCH 11/44] EgtGeomKernel : - sistemati vari bug nella creazione della superficie trimesh trimmata si una superficie di bezier Problemi noti : - sui casi con un tree reale genero dei poligoni sbagliati per le celle --- SurfBezier.cpp | 1 + Tree.cpp | 1065 +++++++++++++++++++++++++----------------------- Tree.h | 4 +- 3 files changed, 553 insertions(+), 517 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index b0fb6c6..cca23c6 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -1500,6 +1500,7 @@ SurfBezier::GetAuxSurf( void) const // costruttore della superficie Tree Tree( this, true) ; + //Tree.BuildTree_test() ; Tree.BuildTree() ; vector vvPL ; Tree.GetPolygons( vvPL) ; diff --git a/Tree.cpp b/Tree.cpp index eaf7ffd..131e469 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -373,7 +373,7 @@ Tree::Split( int nId) //---------------------------------------------------------------------------- bool -Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) +Tree::BuildTree_test( double dLinTol_, double dSideMin, double dSideMax) { //int nCToSplit = -1 ; //celle 0,1 @@ -409,336 +409,337 @@ Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) return true ; } -////---------------------------------------------------------------------------- -//bool -//Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) -//{ -// // suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri -// int nCToSplit = -1 ; -// double dLinTol = 0.2 ; -// //double dSideMin = 1 ; -// if ( ! m_bTrimmed) { -// if ( ! m_bBilinear) { -// while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { -// // controllo che la cella non sia già stata preliminarmente splittata -// if ( m_mTree[nCToSplit].IsLeaf()) { -// // calcolo in quale direzione ho più curvatura -// // ptP00P10 è un punto tra P00 e P10 -// double dCurvU = 0, dCurvV = 0 ; -// double dLenParU = m_mTree[nCToSplit].GetTopRight().x - m_mTree[nCToSplit].GetBottomLeft().x ; -// double dLenParV = m_mTree[nCToSplit].GetTopRight().y - m_mTree[nCToSplit].GetBottomLeft().y ; -// if ( dLenParU <= 1. / m_nDegV || dLenParV <= 1. / m_nDegU) { -// double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; -// double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; -// double dULoc = 0.5, dVLoc = 0.5 ; -// Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00 ; -// m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; -// m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; -// m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; -// m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; -// m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; -// Point3d ptV = ( 1 - dULoc) * ptP00P10 + dULoc * ptP11P01 ; -// Point3d ptU = ( 1 - dVLoc) * ptP10P11 + dVLoc * ptP01P00 ; -// dCurvV = Dist( ptV, ptPSrf) ; -// dCurvU = Dist( ptU, ptPSrf) ; -// } -// // faccio un'analisi più fine della curvatura se almeno il grado di una curva di uno dei due parametri è alto e -// // se sto ancora guardando una cella abbastanza grande -// else{ -// Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00, ptPSrfMid; -// double dStep = 1. / m_nDegU ; -// for ( double k = dStep ; k < 1 ; k = k + dStep) { -// double dU = k * m_mTree[nCToSplit].GetTopRight().x + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().x ; -// double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; -// m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; -// if ( k == 0.5) -// ptPSrfMid = ptPSrf ; -// m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; -// m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; -// CurveLine clV ; -// clV.Set( ptP00P10, ptP11P01) ; -// DistPointCurve dpc( ptPSrf, clV) ; -// double dDist ; -// dpc.GetDist( dDist) ; -// dCurvV = max( dCurvV, dDist) ; -// } -// dStep = 1. / m_nDegV ; -// for ( double k = dStep ; k < 1 ; k = k + dStep) { -// double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; -// double dV = k * m_mTree[nCToSplit].GetTopRight().y + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().y ; -// if ( k == 0.5) -// ptPSrf = ptPSrfMid ; -// else -// m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; -// m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; -// m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; -// CurveLine clU ; -// clU.Set( ptP01P00, ptP10P11) ; -// DistPointCurve dpc( ptPSrf, clU) ; -// double dDist ; -// dpc.GetDist( dDist) ; -// dCurvU = max( dCurvU, dDist) ; -// } -// } -// -// // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza -// // misura approssimativa della curvatura in una direzione -// bool bVert ; -// if ( dCurvV > dCurvU) { -// // lungo la direzione V ho una curvatura maggiore -// bVert = false ; -// } -// else { -// // lungo la direzione U ho una curvatura maggiore -// bVert = true ; -// } -// m_mTree[nCToSplit].SetSplitDirVert( bVert) ; -// Point3d ptP00, ptP10, ptP11, ptP01 ; -// // distanza reale tra i vertici della cella -// ptP00 = m_mVert[nCToSplit][0] ; -// ptP10 = m_mVert[nCToSplit][1] ; -// ptP11 = m_mVert[nCToSplit][2] ; -// ptP01 = m_mVert[nCToSplit][3] ; -// double dLen0 = Dist( ptP00, ptP10) ; -// double dLen1 = Dist( ptP10, ptP11) ; -// double dLen2 = Dist( ptP01, ptP11) ; -// double dLen3 = Dist( ptP00, ptP01) ; -// // 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 = min( dLen0, dLen2) ; -// else -// dSideMinVal = max( dLen0, dLen2) ; -// } -// else { -// if ( dLen1 != 0 && dLen3 != 0) -// dSideMinVal = min( dLen1, dLen3) ; -// else -// dSideMinVal = max( dLen1, dLen3) ; -// } -// // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella -// dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; -// -// // 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)) { -// CurveLine cl0010, cl0001, cl1011, cl0111 ; -// // U=0 -// cl0010.Set( ptP00, ptP10) ; -// // U=1 -// cl0111.Set( ptP01, ptP11) ; -// Point3d pt0010, pt0111, ptBz0, ptBz1, ptBzV ; -// int nFlag ; -// CurveLine clV ; -// // determino quanti Step fare per ogni direzione parametrica -// double dDimU = ( dLen0 >= dLen2 ? dLen0 / m_vDim[0] : dLen2 / m_vDim[2]) ; -// dDimU = ( dDimU > 1 ? 1 : dDimU) ; -// double dDimV = ( dLen1 >= dLen3 ? dLen1 / m_vDim[1] : dLen3 / m_vDim[3]) ; -// dDimV = ( dDimV > 1 ? 1 : dDimV) ; -// // numero di Step per campionare la superficie nelle due direzioni parametriche -// int nStepsU = int( 51 * dDimU + 5 * ( 1 - dDimU)) ; -// int nStepsV = int( 51 * dDimV + 5 * ( 1 - dDimV)) ; -// for ( int u = 0 ; u < nStepsU && ! bSplit ; ++ u) { -// double dU = double ( u) / double ( nStepsU - 1) ; -// double dULoc = ( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x ; -// if ( ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz0) || -// ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetTopRight().y, 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) ; -// clV.Set( pt0010, pt0111) ; -// for ( int v = 0 ; v < nStepsV ; ++ v) { -// double dV = double ( v) / double ( nStepsV - 1) ; -// double dVLoc = ( 1 - dV) * m_mTree[nCToSplit].GetBottomLeft().y + dV * m_mTree[nCToSplit].GetTopRight().y ; -// if ( ! m_pSrfBz->GetPointD1D2( dULoc, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBzV)) -// return false ; -// DistPointCurve dpc( ptBzV, clV) ; -// // distanza di approssimazione locale -// double dDist ; -// dpc.GetDist( dDist) ; -// if ( dDist > dLinTol) { -// bSplit = true ; -// break ; -// } -// } -// } -// } -// -// if ( bSplit || dSideMaxVal > dSideMax) { -// m_mTree[nCToSplit].SetSplitDirVert( bVert) ; -// // effettuo lo split -// Split( nCToSplit) ; -// -// // procedo con lo split del Child1 -// nCToSplit = m_mTree[nCToSplit].m_nChild1 ; -// } -// else { -// // sono arrivato ad una cella Leaf, quindi salvo la cella -// m_vnLeaves.push_back( nCToSplit) ; -// m_mTree[nCToSplit].SetProcessed() ; -// // risalgo i parent finché non trovo il primo Child2 da processare -// nCToSplit = m_mTree[nCToSplit].m_nParent ; -// if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) -// m_mTree[nCToSplit].SetProcessed() ; -// while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { -// if ( m_mTree[nCToSplit].m_nParent != -2) -// nCToSplit = m_mTree[nCToSplit].m_nParent ; -// if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) -// m_mTree[nCToSplit].SetProcessed() ; -// if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) -// break ; -// } -// nCToSplit = m_mTree[nCToSplit].m_nChild2 ; -// } -// } -// else { -// nCToSplit = m_mTree[nCToSplit].m_nChild1 ; -// } -// } -// Balance() ; // da implementare quando dividerò ad un parametro a scelta e non a metà -// } -// // bilineare -// else { -// while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { -// if ( m_mTree[nCToSplit].IsLeaf()) { -// // vertici della cella -// Point3d ptP00, ptP10, ptP11, ptP01 ; -// ptP00 = m_mVert[nCToSplit][0] ; -// ptP10 = m_mVert[nCToSplit][1] ; -// ptP11 = m_mVert[nCToSplit][2] ; -// ptP01 = m_mVert[nCToSplit][3] ; -// // distanza reale tra i vertici della cella -// double dLen0 = Dist( ptP00, ptP10) ; -// double dLen1 = Dist( ptP10, ptP11) ; -// double dLen2 = Dist( ptP01, ptP11) ; -// double dLen3 = Dist( ptP00, ptP01) ; -// -// bool bVert = false ; -// // calcolo in quale direzione è meglio dividere in base allo stretch -// Point3d ptPSrfU, ptPSrfV ; -// double dU = 0, dV = 0 ; -// double dDistU = 0, dDistV = 0 ; -// PNTVECTOR vPtU, vPtV ; -// if ( ! m_bMulti) { -// if ( max(dLen0, dLen2) > max(dLen1, dLen3)) { -// bVert = true ; -// } -// else { -// bVert = false ; -// } -// } -// else { -// for ( double i = 0.25 ; i < 1 ; i = i + 0.25 ) { -// dU = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().x + i * m_mTree[nCToSplit].GetTopRight().x ; -// dV = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().y + i * m_mTree[nCToSplit].GetTopRight().y ; -// double dVLoc = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 ; -// double dULoc = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 ; -// m_pSrfBz->GetPointD1D2( dU, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfU) ; -// m_pSrfBz->GetPointD1D2( dULoc, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfV) ; -// vPtU.push_back( ptPSrfU) ; -// vPtV.push_back( ptPSrfV) ; -// } -// // devo guardare se i tre punti in vPtU e vPtV sono allineati -// CurveLine clU, clV; -// clU.Set(vPtU[0], vPtU[1]) ; -// clV.Set(vPtV[0], vPtV[1]) ; -// DistPointCurve dpcU( vPtU[2], clU, false) ; -// DistPointCurve dpcV( vPtV[2], clV, false) ; -// dpcU.GetDist( dDistU) ; -// dpcV.GetDist( dDistV) ; -// if ( dDistU > dDistV) { -// bVert = true ; -// } -// else { -// bVert = false ; -// } -// } -// -// // verifico che la cella sia abbastanza grande da poter essere splittata -// double dSideMinVal = 0, dSideMaxVal = 0 ; -// if ( bVert) { -// if ( dLen0 != 0 && dLen2 != 0) -// dSideMinVal = min( dLen0, dLen2) ; -// else -// dSideMinVal = max( dLen0, dLen2) ; -// } -// else { -// if ( dLen1 != 0 && dLen3 != 0) -// dSideMinVal = min( dLen1, dLen3) ; -// else -// dSideMinVal = max( dLen1, dLen3) ; -// } -// // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella -// dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; -// -// -// double dErr = 0 ; -// if ( m_bMulti) { -// Point3d ptPSrf ; -// Plane3d plAppr ; -// if ( ! AreSamePointApprox( ptP00, ptP10) && ! AreSamePointApprox( ptP00, ptP01)) -// plAppr.Set( ptP00, ( ptP00 - ptP01) ^ ( ptP00 - ptP10)) ; -// else if ( AreSamePointApprox( ptP00, ptP10)) { -// plAppr.Set( ptP01, ( ptP00 - ptP01) ^ ( ptP01 - ptP11)) ; -// } -// else if ( AreSamePointApprox( ptP00, ptP01)) { -// plAppr.Set( ptP10, ( ptP10 - ptP11) ^ ( ptP00 - ptP10)) ; -// } -// for ( double i = 0.25 ; i < 1 ; i = i + 0.25) { -// for ( double j = 0.25 ; j < 1 ; j = j + 0.25) { -// double dU = ( 1 - i) * m_mTree[nCToSplit].GetTopRight().x + i * m_mTree[nCToSplit].GetBottomLeft().x ; -// double dV = ( 1 - j) * m_mTree[nCToSplit].GetTopRight().y + j * m_mTree[nCToSplit].GetBottomLeft().y ; -// m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; -// dErr = max( abs( DistPointPlane( ptPSrf, plAppr)), dErr) ; -// } -// } -// } -// else { -// dErr = 1. / 4. * ( (ptP00 - ptP01) + (ptP11 - ptP10)).Len() ; -// } -// // se la cella è abbastanza grande da poter essere divisa ancora e devo approssimare meglio, la divido -// if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && dErr > dLinTol) { -// m_mTree[nCToSplit].SetSplitDirVert( bVert) ; -// // effettuo lo split -// Split( nCToSplit) ; -// -// // procedo con lo split del Child1 -// nCToSplit = m_mTree[nCToSplit].m_nChild1 ; -// } -// else { -// // sono arrivato ad una cella Leaf, quindi salvo la cella -// m_vnLeaves.push_back( nCToSplit) ; -// m_mTree[nCToSplit].SetProcessed() ; -// // risalgo i parent finché non trovo il primo Child2 da processare -// nCToSplit = m_mTree[nCToSplit].m_nParent ; -// if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) -// m_mTree[nCToSplit].SetProcessed() ; -// while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { -// if ( m_mTree[nCToSplit].m_nParent != -2) -// nCToSplit = m_mTree[nCToSplit].m_nParent ; -// if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) -// m_mTree[nCToSplit].SetProcessed() ; -// if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) -// break ; -// } -// nCToSplit = m_mTree[nCToSplit].m_nChild2 ; -// } -// } -// else { -// nCToSplit = m_mTree[nCToSplit].m_nChild1 ; -// } -// } -// } -// } -// // se la superficie è trimmata -// else { -// SurfFlatRegion sfrTrimReg ; -// } -// return true ; -//} +//---------------------------------------------------------------------------- +bool +Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) +{ + // suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri + int nCToSplit = -1 ; + double dLinTol = 0.2 ; + //double dSideMin = 1 ; + if ( ! m_bTrimmed || m_bTrimmed) { + if ( ! m_bBilinear) { + while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { + // controllo che la cella non sia già stata preliminarmente splittata + if ( m_mTree[nCToSplit].IsLeaf()) { + // calcolo in quale direzione ho più curvatura + // ptP00P10 è un punto tra P00 e P10 + double dCurvU = 0, dCurvV = 0 ; + double dLenParU = m_mTree[nCToSplit].GetTopRight().x - m_mTree[nCToSplit].GetBottomLeft().x ; + double dLenParV = m_mTree[nCToSplit].GetTopRight().y - m_mTree[nCToSplit].GetBottomLeft().y ; + if ( dLenParU <= 1. / m_nDegV || dLenParV <= 1. / m_nDegU) { + double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; + double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; + double dULoc = 0.5, dVLoc = 0.5 ; + Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00 ; + m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; + Point3d ptV = ( 1 - dULoc) * ptP00P10 + dULoc * ptP11P01 ; + Point3d ptU = ( 1 - dVLoc) * ptP10P11 + dVLoc * ptP01P00 ; + dCurvV = Dist( ptV, ptPSrf) ; + dCurvU = Dist( ptU, ptPSrf) ; + } + // faccio un'analisi più fine della curvatura se almeno il grado di una curva di uno dei due parametri è alto e + // se sto ancora guardando una cella abbastanza grande + else{ + Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00, ptPSrfMid; + double dStep = 1. / m_nDegU ; + for ( double k = dStep ; k < 1 ; k = k + dStep) { + double dU = k * m_mTree[nCToSplit].GetTopRight().x + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().x ; + double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; + m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + if ( k == 0.5) + ptPSrfMid = ptPSrf ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; + CurveLine clV ; + clV.Set( ptP00P10, ptP11P01) ; + DistPointCurve dpc( ptPSrf, clV) ; + double dDist ; + dpc.GetDist( dDist) ; + dCurvV = std::max( dCurvV, dDist) ; + } + dStep = 1. / m_nDegV ; + for ( double k = dStep ; k < 1 ; k = k + dStep) { + double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; + double dV = k * m_mTree[nCToSplit].GetTopRight().y + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().y ; + if ( k == 0.5) + ptPSrf = ptPSrfMid ; + else + m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; + CurveLine clU ; + clU.Set( ptP01P00, ptP10P11) ; + DistPointCurve dpc( ptPSrf, clU) ; + double dDist ; + dpc.GetDist( dDist) ; + dCurvU = std::max( dCurvU, dDist) ; + } + } + + // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza + // misura approssimativa della curvatura in una direzione + bool bVert ; + if ( dCurvV > dCurvU) { + // lungo la direzione V ho una curvatura maggiore + bVert = false ; + } + else { + // lungo la direzione U ho una curvatura maggiore + bVert = true ; + } + m_mTree[nCToSplit].SetSplitDirVert( bVert) ; + Point3d ptP00, ptP10, ptP11, ptP01 ; + // distanza reale tra i vertici della cella + ptP00 = m_mVert[nCToSplit][0] ; + ptP10 = m_mVert[nCToSplit][1] ; + ptP11 = m_mVert[nCToSplit][2] ; + ptP01 = m_mVert[nCToSplit][3] ; + double dLen0 = Dist( ptP00, ptP10) ; + double dLen1 = Dist( ptP10, ptP11) ; + double dLen2 = Dist( ptP01, ptP11) ; + double dLen3 = Dist( ptP00, ptP01) ; + // 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) ; + else + dSideMinVal = std::max( dLen0, dLen2) ; + } + else { + if ( dLen1 != 0 && dLen3 != 0) + dSideMinVal = std::max( dLen1, dLen3) ; + else + dSideMinVal = std::max( dLen1, dLen3) ; + } + // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella + dSideMaxVal = std::max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; + + // 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)) { + CurveLine cl0010, cl0001, cl1011, cl0111 ; + // U=0 + cl0010.Set( ptP00, ptP10) ; + // U=1 + cl0111.Set( ptP01, ptP11) ; + Point3d pt0010, pt0111, ptBz0, ptBz1, ptBzV ; + int nFlag ; + CurveLine clV ; + // determino quanti Step fare per ogni direzione parametrica + double dDimU = ( dLen0 >= dLen2 ? dLen0 / m_vDim[0] : dLen2 / m_vDim[2]) ; + dDimU = ( dDimU > 1 ? 1 : dDimU) ; + double dDimV = ( dLen1 >= dLen3 ? dLen1 / m_vDim[1] : dLen3 / m_vDim[3]) ; + dDimV = ( dDimV > 1 ? 1 : dDimV) ; + // numero di Step per campionare la superficie nelle due direzioni parametriche + int nStepsU = int( 51 * dDimU + 5 * ( 1 - dDimU)) ; + int nStepsV = int( 51 * dDimV + 5 * ( 1 - dDimV)) ; + for ( int u = 0 ; u < nStepsU && ! bSplit ; ++ u) { + double dU = double ( u) / double ( nStepsU - 1) ; + double dULoc = ( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x ; + if ( ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz0) || + ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetTopRight().y, 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) ; + clV.Set( pt0010, pt0111) ; + for ( int v = 0 ; v < nStepsV ; ++ v) { + double dV = double ( v) / double ( nStepsV - 1) ; + double dVLoc = ( 1 - dV) * m_mTree[nCToSplit].GetBottomLeft().y + dV * m_mTree[nCToSplit].GetTopRight().y ; + if ( ! m_pSrfBz->GetPointD1D2( dULoc, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBzV)) + return false ; + DistPointCurve dpc( ptBzV, clV) ; + // distanza di approssimazione locale + double dDist ; + dpc.GetDist( dDist) ; + if ( dDist > dLinTol) { + bSplit = true ; + break ; + } + } + } + } + + if ( bSplit || dSideMaxVal > dSideMax) { + m_mTree[nCToSplit].SetSplitDirVert( bVert) ; + // effettuo lo split + Split( nCToSplit) ; + + // procedo con lo split del Child1 + nCToSplit = m_mTree[nCToSplit].m_nChild1 ; + } + else { + // sono arrivato ad una cella Leaf, quindi salvo la cella + m_vnLeaves.push_back( nCToSplit) ; + m_mTree[nCToSplit].SetProcessed() ; + // risalgo i parent finché non trovo il primo Child2 da processare + nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + m_mTree[nCToSplit].SetProcessed() ; + while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { + if ( m_mTree[nCToSplit].m_nParent != -2) + nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + m_mTree[nCToSplit].SetProcessed() ; + if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + break ; + } + nCToSplit = m_mTree[nCToSplit].m_nChild2 ; + } + } + else { + nCToSplit = m_mTree[nCToSplit].m_nChild1 ; + } + } + Balance() ; // da implementare quando dividerò ad un parametro a scelta e non a metà + } + // bilineare + else { + while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { + if ( m_mTree[nCToSplit].IsLeaf()) { + // vertici della cella + Point3d ptP00, ptP10, ptP11, ptP01 ; + ptP00 = m_mVert[nCToSplit][0] ; + ptP10 = m_mVert[nCToSplit][1] ; + ptP11 = m_mVert[nCToSplit][2] ; + ptP01 = m_mVert[nCToSplit][3] ; + // distanza reale tra i vertici della cella + double dLen0 = Dist( ptP00, ptP10) ; + double dLen1 = Dist( ptP10, ptP11) ; + double dLen2 = Dist( ptP01, ptP11) ; + double dLen3 = Dist( ptP00, ptP01) ; + + bool bVert = false ; + // calcolo in quale direzione è meglio dividere in base allo stretch + Point3d ptPSrfU, ptPSrfV ; + double dU = 0, dV = 0 ; + double dDistU = 0, dDistV = 0 ; + PNTVECTOR vPtU, vPtV ; + if ( ! m_bMulti) { + if ( std::max(dLen0, dLen2) > std::max(dLen1, dLen3)) { + bVert = true ; + } + else { + bVert = false ; + } + } + else { + for ( double i = 0.25 ; i < 1 ; i = i + 0.25 ) { + dU = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().x + i * m_mTree[nCToSplit].GetTopRight().x ; + dV = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().y + i * m_mTree[nCToSplit].GetTopRight().y ; + double dVLoc = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 ; + double dULoc = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 ; + m_pSrfBz->GetPointD1D2( dU, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfU) ; + m_pSrfBz->GetPointD1D2( dULoc, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfV) ; + vPtU.push_back( ptPSrfU) ; + vPtV.push_back( ptPSrfV) ; + } + // devo guardare se i tre punti in vPtU e vPtV sono allineati + CurveLine clU, clV; + clU.Set(vPtU[0], vPtU[1]) ; + clV.Set(vPtV[0], vPtV[1]) ; + DistPointCurve dpcU( vPtU[2], clU, false) ; + DistPointCurve dpcV( vPtV[2], clV, false) ; + dpcU.GetDist( dDistU) ; + dpcV.GetDist( dDistV) ; + if ( dDistU > dDistV) { + bVert = true ; + } + else { + bVert = false ; + } + } + + // verifico che la cella sia abbastanza grande da poter essere splittata + double dSideMinVal = 0, dSideMaxVal = 0 ; + if ( bVert) { + if ( dLen0 != 0 && dLen2 != 0) + dSideMinVal = std::max( dLen0, dLen2) ; + else + dSideMinVal = std::max( dLen0, dLen2) ; + } + else { + if ( dLen1 != 0 && dLen3 != 0) + dSideMinVal = std::max( dLen1, dLen3) ; + else + dSideMinVal = std::max( dLen1, dLen3) ; + } + // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella + dSideMaxVal = std::max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; + + + double dErr = 0 ; + if ( m_bMulti) { + Point3d ptPSrf ; + Plane3d plAppr ; + if ( ! AreSamePointApprox( ptP00, ptP10) && ! AreSamePointApprox( ptP00, ptP01)) + plAppr.Set( ptP00, ( ptP00 - ptP01) ^ ( ptP00 - ptP10)) ; + else if ( AreSamePointApprox( ptP00, ptP10)) { + plAppr.Set( ptP01, ( ptP00 - ptP01) ^ ( ptP01 - ptP11)) ; + } + else if ( AreSamePointApprox( ptP00, ptP01)) { + plAppr.Set( ptP10, ( ptP10 - ptP11) ^ ( ptP00 - ptP10)) ; + } + for ( double i = 0.25 ; i < 1 ; i = i + 0.25) { + for ( double j = 0.25 ; j < 1 ; j = j + 0.25) { + double dU = ( 1 - i) * m_mTree[nCToSplit].GetTopRight().x + i * m_mTree[nCToSplit].GetBottomLeft().x ; + double dV = ( 1 - j) * m_mTree[nCToSplit].GetTopRight().y + j * m_mTree[nCToSplit].GetBottomLeft().y ; + m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + dErr = std::max( abs( DistPointPlane( ptPSrf, plAppr)), dErr) ; + } + } + } + else { + dErr = 1. / 4. * ( (ptP00 - ptP01) + (ptP11 - ptP10)).Len() ; + } + // se la cella è abbastanza grande da poter essere divisa ancora e devo approssimare meglio, la divido + if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && dErr > dLinTol) { + m_mTree[nCToSplit].SetSplitDirVert( bVert) ; + // effettuo lo split + Split( nCToSplit) ; + + // procedo con lo split del Child1 + nCToSplit = m_mTree[nCToSplit].m_nChild1 ; + } + else { + // sono arrivato ad una cella Leaf, quindi salvo la cella + m_vnLeaves.push_back( nCToSplit) ; + m_mTree[nCToSplit].SetProcessed() ; + // risalgo i parent finché non trovo il primo Child2 da processare + nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + m_mTree[nCToSplit].SetProcessed() ; + while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { + if ( m_mTree[nCToSplit].m_nParent != -2) + nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + m_mTree[nCToSplit].SetProcessed() ; + if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + break ; + } + nCToSplit = m_mTree[nCToSplit].m_nChild2 ; + } + } + else { + nCToSplit = m_mTree[nCToSplit].m_nChild1 ; + } + } + } + } + // NON IMPLEMENTATO + // se la superficie è trimmata creo l'albero solo all'interno dei bbox delle curve di trim ( se ho solo trim CW allora tengo il bordo) + else { + SurfFlatRegion sfrTrimReg ; + } + return true ; +} //---------------------------------------------------------------------------- void @@ -1522,7 +1523,7 @@ Tree::TraceLoopLabelCell( void) } // ora le curve di trim hanno lo stesso indice delle loro corrispondenti spezzate nel vettore vPlApprox - double dLinTol = - 0.01 ; // questo è riferito allo spazio parametrico, quando è già stato riporatato al range 0..1 !!!!!! + 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 POLYLINEVECTOR vplPolygons ; GetPolygonsBasic( vplPolygons) ; @@ -1879,7 +1880,10 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert 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 - m_mTree[nId].m_vInters.back().vpt = vptInters ; // al posto di .vpt = vptInters metto un push_back //////////////////////////////////////////////// + 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 //////////////////////////////////////////////// + else + m_mTree[nId].m_vInters.back().vpt = vptInters ; vptInters.clear() ; // setto la categoria della cella if ( m_mTree[nId].m_nFlag == -1) @@ -1899,12 +1903,14 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert } m_mTree[nId].m_vInters.emplace_back() ; Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; - if ( ptInters.x > m_mTree[nId].GetBottomLeft().x && ptInters.x < m_mTree[nId].GetTopRight().x ) + if ( ptInters.x > m_mTree[nId].GetBottomLeft().x + EPS_SMALL && ptInters.x < m_mTree[nId].GetTopRight().x - EPS_SMALL) m_mTree[nId].m_vInters.back().nIn = 2 ; else if ( AreSamePointApprox( ptInters, m_mTree[nId].GetBottomLeft())) m_mTree[nId].m_vInters.back().nIn = 5 ; else if ( AreSamePointApprox( ptInters, ptBr)) m_mTree[nId].m_vInters.back().nIn = 6 ; + else + m_mTree[nId].m_vInters.back().nIn = 2 ; } else if ( nEdge == 1) { GetLeftNeigh( nId, vNeigh) ; @@ -1917,12 +1923,14 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert } m_mTree[nId].m_vInters.emplace_back() ; Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; - if ( ptInters.y > m_mTree[nId].GetBottomLeft().y && ptInters.y < m_mTree[nId].GetTopRight().y ) + if ( ptInters.y > m_mTree[nId].GetBottomLeft().y + EPS_SMALL && ptInters.y < m_mTree[nId].GetTopRight().y - EPS_SMALL) m_mTree[nId].m_vInters.back().nIn = 3 ; else if ( AreSamePointApprox( ptInters, ptBr)) m_mTree[nId].m_vInters.back().nIn = 6 ; else if ( AreSamePointApprox( ptInters, m_mTree[nId].GetTopRight())) m_mTree[nId].m_vInters.back().nIn = 7 ; + else + m_mTree[nId].m_vInters.back().nIn = 3 ; } else if ( nEdge == 2) { GetBottomNeigh( nId, vNeigh) ; @@ -1934,12 +1942,14 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert } m_mTree[nId].m_vInters.emplace_back() ; Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; - if ( ptInters.x > m_mTree[nId].GetBottomLeft().x && ptInters.x < m_mTree[nId].GetTopRight().x ) + if ( ptInters.x > m_mTree[nId].GetBottomLeft().x + EPS_SMALL && ptInters.x < m_mTree[nId].GetTopRight().x - EPS_SMALL) m_mTree[nId].m_vInters.back().nIn = 0 ; else if ( AreSamePointApprox( ptInters, ptTl)) m_mTree[nId].m_vInters.back().nIn = 4 ; else if ( AreSamePointApprox( ptInters, m_mTree[nId].GetTopRight())) m_mTree[nId].m_vInters.back().nIn = 7 ; + else + m_mTree[nId].m_vInters.back().nIn = 0 ; } else if ( nEdge == 3) { GetRightNeigh( nId, vNeigh) ; @@ -1951,12 +1961,14 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert } m_mTree[nId].m_vInters.emplace_back() ; Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; - if ( ptInters.y > m_mTree[nId].GetBottomLeft().y && ptInters.y < m_mTree[nId].GetTopRight().y ) + if ( ptInters.y > m_mTree[nId].GetBottomLeft().y + EPS_SMALL && ptInters.y < m_mTree[nId].GetTopRight().y - EPS_SMALL) m_mTree[nId].m_vInters.back().nIn = 1 ; else if ( AreSamePointApprox( ptInters, m_mTree[nId].GetBottomLeft())) m_mTree[nId].m_vInters.back().nIn = 5 ; else if ( AreSamePointApprox( ptInters, ptTl)) m_mTree[nId].m_vInters.back().nIn = 4 ; + else + m_mTree[nId].m_vInters.back().nIn = 1 ; } // esco da uno dei vertici else if ( nEdge == 4) { @@ -2153,6 +2165,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I int nEdgeIn = -1 ; int nFirstLoopInPoly = -1 ; for ( int w = 0 ; w < (int)vToCheckNow.size() ; ++ w) { + // primo loop di questo poligono int j = vToCheckNow[w] ; Inters inA = m_mTree[nId].m_vInters[j] ; if ( inA.nIn != -1 ) { @@ -2167,50 +2180,50 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I } nEdge = inA.nOut ; // se la curva è CW devo verifica di non essere uscito in un vertice, con un tratto sovrapposto al lato che ripercorrerò tra poco - if ( !inA.bCCW ) { - Point3d ptLast, ptSecondToLast; - plTrimmedPoly.GetLastPoint(ptLast) ; - plTrimmedPoly.GetPrevPoint(ptSecondToLast) ; - Vector3d vLast = ptLast - ptSecondToLast ; - vLast.Normalize(); - Vector3d vEdge ; - if ( AreSameEdge( nEdge, 0)) { - if ( AreSamePointApprox(ptLast, ptTl) ) { - vEdge = m_mTree[nId].GetBottomLeft() - ptTl ; - vEdge.Normalize() ; - if ( AreOppositeVectorApprox(vLast, vEdge) ) { - plTrimmedPoly.EraseLastUPoint() ; - nEdge = 1 ; - } - } - } - else if ( AreSameEdge( nEdge, 1) && AreSamePointApprox(ptLast, m_mTree[nId].GetBottomLeft()) ) { - vEdge = ptBr - m_mTree[nId].GetBottomLeft() ; + // qui ho tolto l'if e esteso anche ai casi CCW perché anche lì devo controllare!!!!!//////////////////////////////////////////////////////////// + Point3d ptLast, ptSecondToLast; + plTrimmedPoly.GetLastPoint(ptLast) ; + plTrimmedPoly.GetPrevPoint(ptSecondToLast) ; + Vector3d vLast = ptLast - ptSecondToLast ; + vLast.Normalize(); + Vector3d vEdge ; + if ( AreSameEdge( nEdge, 0)) { + if ( AreSamePointApprox(ptLast, ptTl) ) { + vEdge = m_mTree[nId].GetBottomLeft() - ptTl ; vEdge.Normalize() ; if ( AreOppositeVectorApprox(vLast, vEdge) ) { plTrimmedPoly.EraseLastUPoint() ; - nEdge = 2 ; - } - } - else if ( AreSameEdge( nEdge, 2) ) { - if ( AreSamePointApprox(ptLast, ptBr) ) { - vEdge = m_mTree[nId].GetTopRight() - ptBr ; - vEdge.Normalize() ; - if ( AreOppositeVectorApprox(vLast, vEdge) ) { - plTrimmedPoly.EraseLastUPoint() ; - nEdge = 3 ; - } - } - } - else if ( AreSameEdge( nEdge, 3) && AreSamePointApprox(ptLast, m_mTree[nId].GetTopRight()) ) { - vEdge = ptTl - m_mTree[nId].GetTopRight() ; - vEdge.Normalize() ; - if ( AreOppositeVectorApprox(vLast, vEdge) ) { - plTrimmedPoly.EraseLastUPoint() ; - nEdge = 0 ; + nEdge = 1 ; } } } + else if ( AreSameEdge( nEdge, 1) && AreSamePointApprox(ptLast, m_mTree[nId].GetBottomLeft()) ) { + vEdge = ptBr - m_mTree[nId].GetBottomLeft() ; + vEdge.Normalize() ; + if ( AreOppositeVectorApprox(vLast, vEdge) ) { + plTrimmedPoly.EraseLastUPoint() ; + nEdge = 2 ; + } + } + else if ( AreSameEdge( nEdge, 2) ) { + if ( AreSamePointApprox(ptLast, ptBr) ) { + vEdge = m_mTree[nId].GetTopRight() - ptBr ; + vEdge.Normalize() ; + if ( AreOppositeVectorApprox(vLast, vEdge) ) { + plTrimmedPoly.EraseLastUPoint() ; + nEdge = 3 ; + } + } + } + else if ( AreSameEdge( nEdge, 3) && AreSamePointApprox(ptLast, m_mTree[nId].GetTopRight()) ) { + vEdge = ptTl - m_mTree[nId].GetTopRight() ; + vEdge.Normalize() ; + if ( AreOppositeVectorApprox(vLast, vEdge) ) { + plTrimmedPoly.EraseLastUPoint() ; + nEdge = 0 ; + } + } + // se mi è rimasto solo un punto sulla polyline vuol dire che avevo solo un tratto parallelo ad lato // quindi salto al prossimo loop if ( plTrimmedPoly.GetPointNbr() == 1 ) { @@ -2226,63 +2239,63 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I // se ho altri Pass vado avanti ad aggiungere vertici finché trovo il prossimo o finché non sono tornato sul lato di partenza bool bNotCameBack = true ; bool bValidNextStart = false ; + bool bAtNextStart = false ; if ( j < nPassToCheck - 1) { int nSecondCheck = 0 ; - - // ciclo sui loop successivi per vedere se ne ho uno su questo lato con un valid start - for ( int t = w ; t < nPassToCheck -1 ; ++ t) { - if ( AreSameEdge( nEdge, m_mTree[nId].m_vInters[j].nIn) ) { - if ( m_mTree[nId].m_vInters[j].bCCW) { - bValidNextStart = ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge)) && // loop successivo inizia su questo lato - ! CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; // in posizione giusta da essere concatenato - } - else { - // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline - bValidNextStart = ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge)) && - CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; - } - } - else - bValidNextStart = CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; - if ( ! AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge) || bValidNextStart) + int nNext ; + // ciclo sui loop successivi per vedere se ne ho uno con un valid start + for ( int t = w + 1 ; t < nPassToCheck ; ++ t) { + bValidNextStart = CheckIfBetween( m_mTree[nId].m_vInters[j], m_mTree[nId].m_vInters[vToCheckNow[t]]) ; + if ( bValidNextStart) { + nNext = t ; + bAtNextStart = AreSameEdge( m_mTree[nId].m_vInters[j].nOut, m_mTree[nId].m_vInters[vToCheckNow[t]].nIn) ; break ; - // se ho trovato un loop successivo che devo saltare, lo salvo e considero i loop più avanti. - if ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge) && ! bValidNextStart){ - ++ nSecondCheck ; - vToCheck.push_back( t + 1) ; } - } - if ( m_mTree[nId].m_vInters[j].bCCW) { - //bNotCameBack = ! AreSameEdge( m_mTree[nId].m_vInters[j].nIn, nEdge) && // sono tornato al lato di ingresso di questo loop - // ! AreSameEdge( nEdge, nEdgeIn) ; // sono tornato sul lato di ingresso di questo poligono ( solo se la curva è CCW) - bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ; - } - else { - // il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline - if ( AreSameEdge( nEdge, nEdgeIn)) { - bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; - bNotCameBack = bNotCameBack && !bBefore ; + else { + ++ nSecondCheck ; + vToCheck.push_back( t) ; } } - while ( ! bValidNextStart && bNotCameBack) { + //// ciclo sui loop successivi per vedere se ne ho uno su questo lato con un valid start + //for ( int t = w ; t < nPassToCheck -1 ; ++ t) { + // if ( AreSameEdge( nEdge, m_mTree[nId].m_vInters[j].nIn) ) { + // if ( m_mTree[nId].m_vInters[j].bCCW) { + // bValidNextStart = ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge)) && // loop successivo inizia su questo lato + // ! CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; // in posizione giusta da essere concatenato + // } + // else { + // // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline + // bValidNextStart = ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge)) && + // CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; + // } + // } + // else + // bValidNextStart = CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; + // if ( ! AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge) || bValidNextStart) + // //if ( bValidNextStart) + // break ; + // // se ho trovato un loop successivo che devo saltare, lo salvo e considero i loop più avanti. + // if ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge) && ! bValidNextStart){ + // //else { + // ++ nSecondCheck ; + // vToCheck.push_back( t + 1) ; + // } + //} + + bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ; + + //while ( ! bValidNextStart && bNotCameBack) { + while ( ! ( bValidNextStart && bAtNextStart) && bNotCameBack) { Point3d ptVert ; - if ( nEdge == 0) { - //ptVert.x = m_mTree[nId].GetBottomLeft().x ; - //ptVert.y = m_mTree[nId].GetTopRight().y ; + if ( nEdge == 0) ptVert = ptTl ; - } - else if ( nEdge == 1) { + else if ( nEdge == 1) ptVert = m_mTree[nId].GetBottomLeft() ; - } - else if ( nEdge == 2) { - //ptVert.x = m_mTree[nId].GetTopRight().x ; - //ptVert.y = m_mTree[nId].GetBottomLeft().y ; + else if ( nEdge == 2) ptVert = ptBr ; - } - else if ( nEdge == 3) { + else if ( nEdge == 3) ptVert = m_mTree[nId].GetTopRight() ; - } AddVertex( nId, vEdgeVertex, plTrimmedPoly, c, ptVert) ; //plTrimmedPoly.AddUPoint( c, ptVert) ; //++c ; @@ -2294,42 +2307,48 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I nEdge = 0 ; // aggiorno le condizioni per il while - // ciclo sui loop successivi per vedere se ne ho uno su questo lato con un valid start - for ( int t = w ; t < nPassToCheck -1 ; ++ t) { - if ( AreSameEdge( nEdge, m_mTree[nId].m_vInters[j].nIn) ) { - if ( m_mTree[nId].m_vInters[j].bCCW) { - bValidNextStart = ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge)) && // loop successivo inizia su questo lato - ! CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; // in posizione giusta da essere concatenato - } - else { - // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline - bValidNextStart = ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge)) && - CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; - } - } - else - bValidNextStart = CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; - if ( ! AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge) || bValidNextStart) - break ; - // se ho trovato un loop successivo che devo saltare, lo salvo e considero i loop più avanti. - if ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge) && ! bValidNextStart){ - ++ nSecondCheck ; - vToCheck.push_back( t + 1) ; - } - } - if ( m_mTree[nId].m_vInters[j].bCCW) { - //bNotCameBack = ! AreSameEdge( m_mTree[nId].m_vInters[j].nIn, nEdge) && // sono tornato al lato di ingresso di questo loop - // ! AreSameEdge( nEdge, nEdgeIn) ; // sono tornato sul lato di ingresso di questo poligono ( solo se la curva è CCW) - bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ; - } - else { - // il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline - if ( AreSameEdge( nEdge, nEdgeIn)) { - bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; - bNotCameBack = bNotCameBack && !bBefore ; - } - } + if ( bValidNextStart) + bAtNextStart = AreSameEdge( nEdge, m_mTree[nId].m_vInters[vToCheckNow[nNext]].nIn) ; + bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ; + + /*for ( int t = w + 1 ; t < nPassToCheck -1 ; ++ t) { + bValidNextStart = CheckIfBetween( m_mTree[nId].m_vInters[j], m_mTree[nId].m_vInters[vToCheckNow[t]]) ; + if ( bValidNextStart) { + bAtNextStart = AreSameEdge( m_mTree[nId].m_vInters[j].nOut, m_mTree[nId].m_vInters[vToCheckNow[t]].nIn) ; + break ; + } + else { + ++ nSecondCheck ; + vToCheck.push_back( t) ; + } + }*/ + + // ciclo sui loop successivi per vedere se ne ho uno su questo lato con un valid start + //for ( int t = w ; t < nPassToCheck -1 ; ++ t) { + // if ( AreSameEdge( nEdge, m_mTree[nId].m_vInters[j].nIn) ) { + // if ( m_mTree[nId].m_vInters[j].bCCW) { + // bValidNextStart = ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge)) && // loop successivo inizia su questo lato + // ! CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; // in posizione giusta da essere concatenato + // } + // else { + // // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline + // bValidNextStart = ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge)) && + // CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; + // } + // } + // else + // bValidNextStart = CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; + // if ( ! AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge) || bValidNextStart) + // //if ( bValidNextStart) + // break ; + // // se ho trovato un loop successivo che devo saltare, lo salvo e considero i loop più avanti. + // if ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge) && ! bValidNextStart){ + // //else { + // ++ nSecondCheck ; + // vToCheck.push_back( t + 1) ; + // } + //} } // se ho trovato un altro loop salto all'inizio del for // @@ -2341,31 +2360,16 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I } // non ho altri loop quindi aggiungo vertici finché torno al punto di partenza else { - if ( m_mTree[nId].m_vInters[j].bCCW ) { - bNotCameBack = ! AreSameEdge( m_mTree[nId].m_vInters[j].nIn, nEdge) && // sono tornato al lato di ingresso di questo loop - ! AreSameEdge( nEdge, nEdgeIn) ; // sono tornato sul lato di ingresso di questo poligono ( solo se la curva è CCW) - } - else { - // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline - if ( AreSameEdge( nEdge, nEdgeIn) ) { - bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; - bNotCameBack = bNotCameBack && ! bBefore ; - } - } + bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ; + while ( bNotCameBack) { Point3d ptVert ; - if ( nEdge == 0) { - //ptVert.x = m_mTree[nId].GetBottomLeft().x ; - //ptVert.y = m_mTree[nId].GetTopRight().y ; + if ( nEdge == 0) ptVert = ptTl ; - } else if ( nEdge == 1) ptVert = m_mTree[nId].GetBottomLeft() ; - else if ( nEdge == 2) { - //ptVert.x = m_mTree[nId].GetTopRight().x ; - //ptVert.y = m_mTree[nId].GetBottomLeft().y ; + else if ( nEdge == 2) ptVert = ptBr ; - } else if ( nEdge == 3) ptVert = m_mTree[nId].GetTopRight() ; AddVertex( nId, vEdgeVertex, plTrimmedPoly, c, ptVert) ; @@ -2378,16 +2382,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I else nEdge = 0 ; // aggiorno le condizioni per il while - if ( m_mTree[nId].m_vInters[j].bCCW ) { - bNotCameBack = ! AreSameEdge( m_mTree[nId].m_vInters[j].nIn, nEdge) && - ! AreSameEdge( nEdge, nEdgeIn) ; - } - else { - if ( AreSameEdge( nEdge, nEdgeIn)) { - bool bBefore = CheckIfBefore( plTrimmedPoly, nEdge) ; - bNotCameBack = bNotCameBack && ! bBefore ; - } - } + bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ; } } plTrimmedPoly.Close() ; @@ -2528,8 +2523,8 @@ Tree::CheckIfBefore( Inters& inA) const // pl.AddUPoint( c, ptToAdd) ; // ++ c ; //} - pl.AddUPoint( 0, inA.vpt[0]) ; - pl.AddUPoint( 1, inA.vpt.back()) ; + pl.AddUPoint( 0, inA.vpt.back()) ; + pl.AddUPoint( 1, inA.vpt[0]) ; INTVECTOR vEdges = { 7, 0, 4, 1, 5, 2, 6} ; // controllo se nEdge1 viene prima di nEdge2. la partenza è da ptTR e l'arrivo è ptBr @@ -2579,36 +2574,53 @@ Tree::CheckIfBefore( int& nEdge1, Point3d& ptP1, int& nEdge2, Point3d& ptP2) con //---------------------------------------------------------------------------- bool -Tree::CheckIfAfter( PolyLine& pl, Point3d& ptNextStart, int nEdge) const +Tree::CheckIfAfter( PolyLine& pl, Point3d& ptNextStart, int nEdge, bool bSameEdge) const { // controllo se ptNextStart è più avanti rispetto a ptEnd in senso antiorario + // ATTENZIONE i due punti devono essere sullo stesso lato! - // se i punti non sono sullo stesso lato ritorno false + // se i punti non sono sullo stesso lato ritorno false ( con bSameEdge == true) Point3d ptEnd ; pl.GetLastPoint( ptEnd) ; if ( nEdge == 0 ) { - if ( ptNextStart.y > ptEnd.y - EPS_SMALL && ptNextStart.y < ptEnd.y + EPS_SMALL) - return ptEnd.x > ptNextStart.x ; + if ( bSameEdge) { + if ( ptNextStart.y > ptEnd.y - EPS_SMALL && ptNextStart.y < ptEnd.y + EPS_SMALL) + return ptEnd.x > ptNextStart.x ; + else + return false ; + } else - return false ; + return ptEnd.x > ptNextStart.x ; } else if ( nEdge == 1 ) { - if ( ptNextStart.x > ptEnd.x - EPS_SMALL && ptNextStart.x < ptEnd.x + EPS_SMALL) + if ( bSameEdge) { + if ( ptNextStart.x > ptEnd.x - EPS_SMALL && ptNextStart.x < ptEnd.x + EPS_SMALL) + return ptEnd.y > ptNextStart.y ; + else + return false ; + } + else return ptEnd.y > ptNextStart.y ; - else - return false ; } else if ( nEdge == 2 ) { - if ( ptNextStart.y > ptEnd.y - EPS_SMALL && ptNextStart.y < ptEnd.y + EPS_SMALL) - return ptEnd.x < ptNextStart.x ; + if ( bSameEdge) { + if ( ptNextStart.y > ptEnd.y - EPS_SMALL && ptNextStart.y < ptEnd.y + EPS_SMALL) + return ptEnd.x < ptNextStart.x ; + else + return false ; + } else - return false ; + return ptEnd.x < ptNextStart.x ; } else if ( nEdge == 3 ) { - if ( ptNextStart.x > ptEnd.x - EPS_SMALL && ptNextStart.x < ptEnd.x + EPS_SMALL) - return ptEnd.y < ptNextStart.y ; + if ( bSameEdge) { + if ( ptNextStart.x > ptEnd.x - EPS_SMALL && ptNextStart.x < ptEnd.x + EPS_SMALL) + return ptEnd.y < ptNextStart.y ; + else + return false ; + } else - return false ; + return ptEnd.y < ptNextStart.y ; } return false ; } @@ -2688,7 +2700,7 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm if ( ptToAdd.x >= ptBL.x && ptToAdd.x <= ptTR.x && ptToAdd.y == ptTR.y && abs(vDir.x) > 1 - EPS_SMALL) { for ( int t = 0 ; t < (int)vEdgeVertex[0].size() ; ++ t) { Point3d ptIntermed = vEdgeVertex[0][t] ; - if ( ptIntermed.x > ptToAdd.x ) { + if ( ptIntermed.x > ptToAdd.x && ptIntermed.x < ptLast.x) { plTrimmedPoly.AddUPoint( c, ptIntermed) ; ++ c ; } @@ -2702,7 +2714,7 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm else if ( ptToAdd.y >= ptBL.y && ptToAdd.y <= ptTR.y && ptToAdd.x == ptBL.x && abs(vDir.y) > 1 - EPS_SMALL) { for ( int t = 0 ; t < (int)vEdgeVertex[1].size() ; ++ t) { Point3d ptIntermed = vEdgeVertex[1][t] ; - if ( ptIntermed.y > ptToAdd.y ) { + if ( ptIntermed.y > ptToAdd.y && ptIntermed.y < ptLast.y) { plTrimmedPoly.AddUPoint( c, ptIntermed) ; ++ c ; } @@ -2716,7 +2728,7 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm else if ( ptToAdd.x >= ptBL.x && ptToAdd.x <= ptTR.x && ptToAdd.y == ptBL.y && abs(vDir.x) > 1 - EPS_SMALL) { for ( int t = 0 ; t < (int)vEdgeVertex[2].size() ; ++ t) { Point3d ptIntermed = vEdgeVertex[2][t] ; - if ( ptIntermed.x < ptToAdd.x ) { + if ( ptIntermed.x < ptToAdd.x && ptIntermed.x > ptLast.x) { plTrimmedPoly.AddUPoint( c, ptIntermed) ; ++ c ; } @@ -2730,7 +2742,7 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm else if ( ptToAdd.y >= ptBL.y && ptToAdd.y <= ptTR.y && ptToAdd.x == ptTR.x && abs(vDir.y) > 1 - EPS_SMALL) { for ( int t = 0 ; t < (int)vEdgeVertex[3].size() ; ++ t) { Point3d ptIntermed = vEdgeVertex[3][t] ; - if ( ptIntermed.y < ptToAdd.y ) { + if ( ptIntermed.y < ptToAdd.y && ptIntermed.y > ptLast.y) { plTrimmedPoly.AddUPoint( c, ptIntermed) ; ++ c ; } @@ -2900,18 +2912,6 @@ Tree::CategorizeCell( int& nId) // 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 ) { - // guardo le intersezioni a mano - // - //int nPass = (int) m_mTree[vNeigh[0]].m_vInters.size() ; - //for ( int p = 0 ; p < nPass ; ++p ) { - // // se ho almeno un ingresso o un'uscita - // if ( ) { - - // } - // else { - // m_mTree[nId].m_nFlag == 0 ; - // } - //} GetBottomNeigh( nId, vNeigh1) ; int nNeigh = vNeigh1[0] ; if ( m_mTree[nNeigh].m_nFlag == 0 || m_mTree[nNeigh].m_nFlag == 2) { @@ -2989,3 +2989,36 @@ Tree::CategorizeCell( int& nId) return true ; } + +//---------------------------------------------------------------------------- +bool +Tree::CheckIfBetween( Inters& intA, Inters& intB) const +{ + // controllo se intB è compreso tra l'end e lo start di intA + // ( 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 = intA.nOut ; + vEdges.push_back( nEdge) ; + if ( nEdge == 3) + nEdge = 0 ; + else + ++ nEdge ; + while ( nEdge != intA.nIn ) { + vEdges.push_back( nEdge) ; + if ( nEdge == 3) + nEdge = 0 ; + else + ++ nEdge ; + } + bool bFound = false ; + for ( int i : vEdges) { + if ( intB.nIn == i) { + PolyLine pl ; + pl.AddUPoint( 0, intA.vpt[0]) ; + pl.AddUPoint( 1, intA.vpt.back()) ; + if ( CheckIfAfter( pl, intB.vpt[0], i, false)) + bFound = true ; + } + } + return bFound ; +} diff --git a/Tree.h b/Tree.h index 369acba..fb3663e 100644 --- a/Tree.h +++ b/Tree.h @@ -99,6 +99,7 @@ public : void SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches = true) ; bool BuildTree( double dLinTol = LIN_TOL_STD, double dSideMin = 5, 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( double dLinTol = LIN_TOL_STD, double dSideMin = 5, 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 @@ -126,12 +127,13 @@ private : bool CheckIfBefore( PolyLine& pl, int nEdge) const ; bool CheckIfBefore( Inters& inA) const ; bool CheckIfBefore( int& nEdge1, Point3d& ptP1, int& nEdge2, Point3d& ptP2) const ; - bool CheckIfAfter( PolyLine& pl, Point3d& ptNextStart, int nEdge) const ; + bool CheckIfAfter( PolyLine& pl, Point3d& ptNextStart, int nEdge, bool bSameEdge = true) const ; bool AreSameEdge( int nEdge1, int nEdge2) const ; bool AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimmedPoly, int& c, Point3d& ptToAdd) const ; //bool SetRightEdgeIn( int nId, std::vector& vEdgeVertex, PolyLine& plTrimmedPoly) ; bool SetRightEdgeIn( int nId) ; bool CategorizeCell( int& nId) ; + bool CheckIfBetween( Inters& intA, Inters& intB) const ; private : const SurfBezier* m_pSrfBz ; // superficie di bezier From f3346fd1f19e7269b8ba456328722121bb7dca57 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 6 Jun 2023 16:36:09 +0200 Subject: [PATCH 12/44] EgtGeomKernel : - sistemati vari bug nella creazione della superficie trimesh trimmata si una superficie di bezier Problemi noti : - sui casi con un tree reale entro in un loop infinito o seleziono oppure seleziono un elemento inesistente di un vettore --- Tree.cpp | 240 ++++++++++++++++++++++++++----------------------------- Tree.h | 5 +- 2 files changed, 118 insertions(+), 127 deletions(-) diff --git a/Tree.cpp b/Tree.cpp index 131e469..ec0d431 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -1393,6 +1393,12 @@ Tree::FindCell( const Point3d& ptToAssign, CurveLine& clTrim) const //nCells.push_back( - 2) ; return nCells ; } + + // se lo spazio parametrico non è stato suddiviso ( ho un piano), restituisco la cella root + if ( m_mTree.at(nId).IsLeaf() ) { + nCells.push_back( nId) ; + return nCells ; + } while ( ! m_mTree.at(nId).IsLeaf()) { if ( m_mTree.at(nId).IsSplitVert()) { @@ -2164,23 +2170,24 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I // in questo for analizzo solo i loop che tagliano la cella int nEdgeIn = -1 ; int nFirstLoopInPoly = -1 ; + INTVECTOR vAddedLoops ; for ( int w = 0 ; w < (int)vToCheckNow.size() ; ++ w) { - // primo loop di questo poligono + // indice del loop in m_vInters int j = vToCheckNow[w] ; Inters inA = m_mTree[nId].m_vInters[j] ; if ( inA.nIn != -1 ) { int nEdge ; - if ( nEdgeIn == -1 ) + if ( nEdgeIn == -1 ) { // salvo il lato di ingresso del primo lato del poligono che sto costruendo nEdgeIn = inA.nIn ; + nFirstLoopInPoly = j ; + } for ( Point3d ptInt : inA.vpt ) { AddVertex( nId, vEdgeVertex, plTrimmedPoly, c, ptInt) ; - //plTrimmedPoly.AddUPoint(c, ptInt) ; - //++c ; } + vAddedLoops.push_back( j) ; nEdge = inA.nOut ; - // se la curva è CW devo verifica di non essere uscito in un vertice, con un tratto sovrapposto al lato che ripercorrerò tra poco - // qui ho tolto l'if e esteso anche ai casi CCW perché anche lì devo controllare!!!!!//////////////////////////////////////////////////////////// + // devo verificare di non essere uscito in un vertice, con un tratto sovrapposto al lato che ripercorrerò tra poco Point3d ptLast, ptSecondToLast; plTrimmedPoly.GetLastPoint(ptLast) ; plTrimmedPoly.GetPrevPoint(ptSecondToLast) ; @@ -2240,7 +2247,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I bool bNotCameBack = true ; bool bValidNextStart = false ; bool bAtNextStart = false ; - if ( j < nPassToCheck - 1) { + if ( w < nPassToCheck - 1) { // ho messo w al posto di j //////////////////////////////////////////////////////////////////////////////////////// int nSecondCheck = 0 ; int nNext ; // ciclo sui loop successivi per vedere se ne ho uno con un valid start @@ -2253,39 +2260,12 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I } else { ++ nSecondCheck ; - vToCheck.push_back( t) ; + vToCheck.push_back( vToCheckNow[t]) ; } } - //// ciclo sui loop successivi per vedere se ne ho uno su questo lato con un valid start - //for ( int t = w ; t < nPassToCheck -1 ; ++ t) { - // if ( AreSameEdge( nEdge, m_mTree[nId].m_vInters[j].nIn) ) { - // if ( m_mTree[nId].m_vInters[j].bCCW) { - // bValidNextStart = ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge)) && // loop successivo inizia su questo lato - // ! CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; // in posizione giusta da essere concatenato - // } - // else { - // // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline - // bValidNextStart = ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge)) && - // CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; - // } - // } - // else - // bValidNextStart = CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; - // if ( ! AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge) || bValidNextStart) - // //if ( bValidNextStart) - // break ; - // // se ho trovato un loop successivo che devo saltare, lo salvo e considero i loop più avanti. - // if ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge) && ! bValidNextStart){ - // //else { - // ++ nSecondCheck ; - // vToCheck.push_back( t + 1) ; - // } - //} - bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ; - //while ( ! bValidNextStart && bNotCameBack) { while ( ! ( bValidNextStart && bAtNextStart) && bNotCameBack) { Point3d ptVert ; if ( nEdge == 0) @@ -2297,8 +2277,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 ) @@ -2311,50 +2289,10 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I bAtNextStart = AreSameEdge( nEdge, m_mTree[nId].m_vInters[vToCheckNow[nNext]].nIn) ; bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ; - - /*for ( int t = w + 1 ; t < nPassToCheck -1 ; ++ t) { - bValidNextStart = CheckIfBetween( m_mTree[nId].m_vInters[j], m_mTree[nId].m_vInters[vToCheckNow[t]]) ; - if ( bValidNextStart) { - bAtNextStart = AreSameEdge( m_mTree[nId].m_vInters[j].nOut, m_mTree[nId].m_vInters[vToCheckNow[t]].nIn) ; - break ; - } - else { - ++ nSecondCheck ; - vToCheck.push_back( t) ; - } - }*/ - - // ciclo sui loop successivi per vedere se ne ho uno su questo lato con un valid start - //for ( int t = w ; t < nPassToCheck -1 ; ++ t) { - // if ( AreSameEdge( nEdge, m_mTree[nId].m_vInters[j].nIn) ) { - // if ( m_mTree[nId].m_vInters[j].bCCW) { - // bValidNextStart = ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge)) && // loop successivo inizia su questo lato - // ! CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; // in posizione giusta da essere concatenato - // } - // else { - // // se il loop è CW e sono tornato sul lato di partenza allora controllo se sono prima del primo punto della polyline - // bValidNextStart = ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge)) && - // CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; - // } - // } - // else - // bValidNextStart = CheckIfAfter( plTrimmedPoly, m_mTree[nId].m_vInters[vToCheckNow[t + 1]].vpt[0], nEdge) ; - // if ( ! AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge) || bValidNextStart) - // //if ( bValidNextStart) - // break ; - // // se ho trovato un loop successivo che devo saltare, lo salvo e considero i loop più avanti. - // if ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[t + 1]].nIn, nEdge) && ! bValidNextStart){ - // //else { - // ++ nSecondCheck ; - // vToCheck.push_back( t + 1) ; - // } - //} } // se ho trovato un altro loop salto all'inizio del for - // - //if ( AreSameEdge( m_mTree[nId].m_vInters[vToCheckNow[w + 1 + nSecondCheck]].nIn, nEdge) && bValidNextStart) { // qui ho aggiunto bValidNextStart///////////////////////// - if ( bValidNextStart) { /////////////////////////////// - w = w + nSecondCheck ; + if ( bValidNextStart) { + w = w + nSecondCheck ; continue ; } } @@ -2398,6 +2336,14 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I 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///////////////////////////////////// + for ( int k = 0 ; k < (int)vToCheck.size() ; ++ k) { + for ( int i = 0 ; i < (int)vAddedLoops.size() ; ++ i) { + if ( vToCheck[k] == vAddedLoops[i] ) { + vToCheck.erase(vToCheck.begin() + k) ; + } + } + } } else continue ; @@ -2551,7 +2497,7 @@ bool Tree::CheckIfBefore( int& nEdge1, Point3d& ptP1, int& nEdge2, Point3d& ptP2) const { INTVECTOR vEdges = { 7, 0, 4, 1, 5, 2, 6} ; - // controllo se nEdge1 viene prima di nEdge2. la partenza è da ptTR e l'arrivo è ptBr + // controllo se ptP1, che è su nEdge1, viene prima di ptP2, che è su nEdge2. la partenza è da ptTR e l'arrivo è ptBr INTVECTOR :: iterator iter1 = find( vEdges.begin(), vEdges.end(), nEdge1) ; int nPos1 = std::distance( vEdges.begin(), iter1) ; INTVECTOR :: iterator iter2 = find( vEdges.begin(), vEdges.end(), nEdge2) ; @@ -2574,53 +2520,58 @@ Tree::CheckIfBefore( int& nEdge1, Point3d& ptP1, int& nEdge2, Point3d& ptP2) con //---------------------------------------------------------------------------- bool -Tree::CheckIfAfter( PolyLine& pl, Point3d& ptNextStart, int nEdge, bool bSameEdge) const +Tree::CheckIfBefore( int& nEdge, Point3d& ptP1, Point3d& ptP2) const +{ + // sul lato nEdge controllo se ptP1 viene prima di ptP2. + // i lati vengono percorsi in senso antiorario + if ( nEdge == 0 ) { + return ptP1.x > ptP2.x ; + } + else if ( nEdge == 1 ) { + return ptP1.y > ptP2.y ; + } + else if ( nEdge == 2 ) { + return ptP1.x < ptP2.x ; + } + else if ( nEdge == 3 ) { + return ptP1.y < ptP2.y ; + } + return false ; +} + +//---------------------------------------------------------------------------- +bool +Tree::CheckIfAfter( PolyLine& pl, Point3d& ptNextStart, int nEdge) const { // controllo se ptNextStart è più avanti rispetto a ptEnd in senso antiorario // ATTENZIONE i due punti devono essere sullo stesso lato! - // se i punti non sono sullo stesso lato ritorno false ( con bSameEdge == true) + // se i punti non sono sullo stesso lato ritorno false Point3d ptEnd ; pl.GetLastPoint( ptEnd) ; if ( nEdge == 0 ) { - if ( bSameEdge) { - if ( ptNextStart.y > ptEnd.y - EPS_SMALL && ptNextStart.y < ptEnd.y + EPS_SMALL) - return ptEnd.x > ptNextStart.x ; - else - return false ; - } - else + if ( ptNextStart.y > ptEnd.y - EPS_SMALL && ptNextStart.y < ptEnd.y + EPS_SMALL) return ptEnd.x > ptNextStart.x ; + else + return false ; } else if ( nEdge == 1 ) { - if ( bSameEdge) { - if ( ptNextStart.x > ptEnd.x - EPS_SMALL && ptNextStart.x < ptEnd.x + EPS_SMALL) - return ptEnd.y > ptNextStart.y ; - else - return false ; - } - else + if ( ptNextStart.x > ptEnd.x - EPS_SMALL && ptNextStart.x < ptEnd.x + EPS_SMALL) return ptEnd.y > ptNextStart.y ; + else + return false ; } else if ( nEdge == 2 ) { - if ( bSameEdge) { - if ( ptNextStart.y > ptEnd.y - EPS_SMALL && ptNextStart.y < ptEnd.y + EPS_SMALL) - return ptEnd.x < ptNextStart.x ; - else - return false ; - } - else + if ( ptNextStart.y > ptEnd.y - EPS_SMALL && ptNextStart.y < ptEnd.y + EPS_SMALL) return ptEnd.x < ptNextStart.x ; + else + return false ; } else if ( nEdge == 3 ) { - if ( bSameEdge) { - if ( ptNextStart.x > ptEnd.x - EPS_SMALL && ptNextStart.x < ptEnd.x + EPS_SMALL) - return ptEnd.y < ptNextStart.y ; - else - return false ; - } - else + if ( ptNextStart.x > ptEnd.x - EPS_SMALL && ptNextStart.x < ptEnd.x + EPS_SMALL) return ptEnd.y < ptNextStart.y ; + else + return false ; } return false ; } @@ -2992,33 +2943,72 @@ Tree::CategorizeCell( int& nId) //---------------------------------------------------------------------------- bool -Tree::CheckIfBetween( Inters& intA, Inters& intB) const +Tree::CheckIfBetween( Inters& inA, Inters& inB) const { - // controllo se intB è compreso tra l'end e lo start di intA + // controllo se inB è compreso tra l'end e lo start di inA // ( 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 = intA.nOut ; - vEdges.push_back( nEdge) ; - if ( nEdge == 3) - nEdge = 0 ; - else - ++ nEdge ; - while ( nEdge != intA.nIn ) { + 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) nEdge = 0 ; else ++ nEdge ; } + if ( inA.nIn != inA.nOut) + vEdges.push_back( nEdge) ; bool bFound = false ; for ( int i : vEdges) { - if ( intB.nIn == i) { - PolyLine pl ; - pl.AddUPoint( 0, intA.vpt[0]) ; - pl.AddUPoint( 1, intA.vpt.back()) ; - if ( CheckIfAfter( pl, intB.vpt[0], i, false)) - bFound = true ; + if ( inB.nIn == i) { + if ( inB.nIn == inA.nIn && 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()) ) { + if ( CheckIfBefore( nEdge, inA.vpt.back(), inB.vpt[0]) || CheckIfBefore( nEdge, inB.vpt[0], inA.vpt[0])) + 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])) + 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) { + 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 ) { + //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())) { + bFound = true ; + } + else if ( inB.nOut != inB.nIn) + bFound = true ; } + if ( inB.nOut == i && ! bFound) + break ; } return bFound ; } diff --git a/Tree.h b/Tree.h index fb3663e..55b76f0 100644 --- a/Tree.h +++ b/Tree.h @@ -127,13 +127,14 @@ private : bool CheckIfBefore( PolyLine& pl, int nEdge) const ; bool CheckIfBefore( Inters& inA) const ; bool CheckIfBefore( int& nEdge1, Point3d& ptP1, int& nEdge2, Point3d& ptP2) const ; - bool CheckIfAfter( PolyLine& pl, Point3d& ptNextStart, int nEdge, bool bSameEdge = true) const ; + bool CheckIfBefore( int& nEdge, Point3d& ptP1, Point3d& ptP2) const ; + bool CheckIfAfter( PolyLine& pl, Point3d& ptNextStart, int nEdge) const ; bool AreSameEdge( int nEdge1, int nEdge2) const ; bool AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimmedPoly, int& c, Point3d& ptToAdd) const ; //bool SetRightEdgeIn( int nId, std::vector& vEdgeVertex, PolyLine& plTrimmedPoly) ; bool SetRightEdgeIn( int nId) ; bool CategorizeCell( int& nId) ; - bool CheckIfBetween( Inters& intA, Inters& intB) const ; + bool CheckIfBetween( Inters& inA, Inters& inB) const ; private : const SurfBezier* m_pSrfBz ; // superficie di bezier From 7cf933ec482d380538b899ffcba206ee126d0c20 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Wed, 7 Jun 2023 17:43:23 +0200 Subject: [PATCH 13/44] 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 ; From 1aeb2809fa44f15b0e250279ce06854b89f6aeb7 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Fri, 9 Jun 2023 17:51:47 +0200 Subject: [PATCH 14/44] EgtGeomKernel : - risolti i bug noti Da migliorare: - in caso di curve di trim sul bordo di celle, considero intersecate quelle esterne - possibili problemi numerici al bordo delle celle in FindInters --- SurfBezier.cpp | 25 +- SurfBezier.h | 1 + Tree.cpp | 638 ++++++++++++++++++++++++++++++++----------------- Tree.h | 12 +- 4 files changed, 450 insertions(+), 226 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index fe54cf4..36bacaa 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -1500,8 +1500,9 @@ SurfBezier::GetAuxSurf( void) const // costruttore della superficie Tree Tree( this, true) ; - //Tree.BuildTree_test() ; - Tree.BuildTree( 0.2, 25) ; + Tree.BuildTree_test() ; + //Tree.BuildTree( 0.2, 5) ; + //Tree.BuildTree( 1, 25) ; vector vvPL ; Tree.GetPolygons( vvPL) ; PtrOwner pSrfTm( CreateBasicSurfTriMesh()) ; @@ -1521,7 +1522,7 @@ SurfBezier::GetAuxSurf( void) const PNTVECTOR vPnt3d ; for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) { Point3d pt3d ; - if ( ! GetPointD1D2( vPnt[i].x, vPnt[i].y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d)) + if ( ! GetPointD1D2( vPnt[i].x / SBZ_TREG_COEFF, vPnt[i].y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d)) return nullptr ; vPnt3d.push_back( pt3d) ; } @@ -1540,6 +1541,24 @@ SurfBezier::GetAuxSurf( void) const return m_pSTM ; } +//---------------------------------------------------------------------------- +bool +SurfBezier::GetLeaves( std::vector>& vLeaves) const +{ + Tree Tree( this, true) ; + Tree.BuildTree_test() ; + //Tree.BuildTree( 0.2, 5) ; + //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) ; + } + return true ; +} + //---------------------------------------------------------------------------- void SurfBezier::ResetAuxSurf( void) const diff --git a/SurfBezier.h b/SurfBezier.h index 6cfc9e2..cec073c 100644 --- a/SurfBezier.h +++ b/SurfBezier.h @@ -106,6 +106,7 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW bool GetControlCurveOnU( int nIndV, PolyLine& plCtrlU) const override ; bool GetControlCurveOnV( int nIndU, PolyLine& plCtrlV) const override ; const SurfTriMesh* GetAuxSurf( void) const override ; + bool GetLeaves( std::vector>& vLeaves) const override ; public : // IGeoObjRW int GetNgeId( void) const override ; diff --git a/Tree.cpp b/Tree.cpp index bbbe40c..d5f3f04 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -30,7 +30,7 @@ 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) { - Point3d ptTr ( 1, 1) ; + Point3d ptTr ( 1 * SBZ_TREG_COEFF, 1 * SBZ_TREG_COEFF) ; m_ptPtr = ptTr ; } @@ -71,7 +71,7 @@ Cell::IsLeaf ( void) const Tree::Tree( void) : m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosed( false) { - Point3d ptBl( 0, 0), ptTr ( 1, 1) ; + Point3d ptBl( 0, 0), ptTr ( 1 * SBZ_TREG_COEFF, 1 * SBZ_TREG_COEFF) ; Cell cRoot( ptBl, ptTr) ; m_mTree.insert( std::pair< int, Cell>( -1, cRoot)) ; } @@ -141,7 +141,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) PtrOwner pTrimReg( m_pSrfBz->GetTrimRegion()->Clone()) ; for ( int i = 0 ; i < pTrimReg->GetChunkCount() ; ++ i) { PtrOwner pChunk( pTrimReg->CloneChunk( i)) ; - pChunk->Scale( frSurf, 1./ SBZ_TREG_COEFF, 1./ SBZ_TREG_COEFF, 1) ; + //pChunk->Scale( frSurf, 1./ SBZ_TREG_COEFF, 1./ SBZ_TREG_COEFF, 1) ; for ( int j = 0 ; j < pChunk->GetLoopCount( 0) ; ++ j) { vChunk.push_back( nLoop) ; // i chunk della superficie orignale non possono avere dei sub chunk @@ -156,7 +156,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) } // salvo i vertici 3d della cella root Point3d ptBottom ( 0, 0) ; - Point3d ptTop( nSpanU, nSpanV) ; + Point3d ptTop( nSpanU * SBZ_TREG_COEFF, nSpanV * SBZ_TREG_COEFF) ; Cell cRoot( ptBottom, ptTop) ; m_mTree.insert( std::pair< int, Cell>( -1, cRoot)) ; Point3d ptP00, ptP10, ptP11, ptP01 ; @@ -314,8 +314,8 @@ Tree::Split( int nId, double dSplitValue) m_mTree[m_mTree[nId].m_nChild2].m_nRight = m_mTree[nId].m_nRight ; // metto i corrispondenti 3d dei punti dello split nella mappa m_mVert // per ogni cella i punti devono essere nell'ordine ptP00, ptP10, ptP11, ptP01 - m_pSrfBz->GetPointD1D2( m_mTree[nId].GetBottomLeft().x, dSplitValue, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert1) ; - m_pSrfBz->GetPointD1D2( m_mTree[nId].GetTopRight().x, dSplitValue, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert2) ; + m_pSrfBz->GetPointD1D2( m_mTree[nId].GetBottomLeft().x / SBZ_TREG_COEFF, dSplitValue / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert1) ; + m_pSrfBz->GetPointD1D2( m_mTree[nId].GetTopRight().x / SBZ_TREG_COEFF, dSplitValue / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert2) ; m_mVert[nNodes - 1].push_back( ptVert1) ; m_mVert[nNodes - 1].push_back( ptVert2) ; m_mVert[nNodes - 1].push_back( m_mVert[nId][2]) ; @@ -343,8 +343,8 @@ Tree::Split( int nId, double dSplitValue) m_mTree[m_mTree[nId].m_nChild2].m_nRight = m_mTree[nId].m_nRight ; // metto i corrispondenti 3d dei punti dello split nella mappa m_mVert // per ogni cella i punti devono essere nell'ordine ptP00, ptP10, ptP11, ptP01 - m_pSrfBz->GetPointD1D2( dSplitValue, m_mTree[nId].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert2) ; - m_pSrfBz->GetPointD1D2( dSplitValue, m_mTree[nId].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert1) ; + m_pSrfBz->GetPointD1D2( dSplitValue / SBZ_TREG_COEFF, m_mTree[nId].GetBottomLeft().y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert2) ; + m_pSrfBz->GetPointD1D2( dSplitValue / SBZ_TREG_COEFF, m_mTree[nId].GetTopRight().y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert1) ; m_mVert[nNodes - 1].push_back( m_mVert[nId][0]) ; m_mVert[nNodes - 1].push_back( ptVert2) ; m_mVert[nNodes - 1].push_back( ptVert1) ; @@ -398,24 +398,46 @@ Tree::BuildTree_test( double dLinTol_, double dSideMin, double dSideMax) m_mTree[9].SetSplitDirVert( false) ; Split( 9) ; m_vnLeaves.push_back( 4) ; - m_vnLeaves.push_back( 5) ; + //m_vnLeaves.push_back( 5) ; m_vnLeaves.push_back( 6) ; - m_vnLeaves.push_back( 7) ; - m_vnLeaves.push_back( 10) ; + //m_vnLeaves.push_back( 7) ; + //m_vnLeaves.push_back( 10) ; m_vnLeaves.push_back( 11) ; - m_vnLeaves.push_back( 12) ; + //m_vnLeaves.push_back( 12) ; m_vnLeaves.push_back( 13) ; + // aggiunta di split + //celle 14,15 + m_mTree[5].SetSplitDirVert( true) ; + Split( 5) ; + m_vnLeaves.push_back( 14) ; + m_vnLeaves.push_back( 15) ; + //celle 16,17 + m_mTree[7].SetSplitDirVert( false) ; + Split( 7) ; + m_vnLeaves.push_back( 16) ; + m_vnLeaves.push_back( 17) ; + //celle 18,19 + m_mTree[12].SetSplitDirVert( true) ; + Split( 12) ; + m_vnLeaves.push_back( 18) ; + m_vnLeaves.push_back( 19) ; + //celle 20,21 + m_mTree[10].SetSplitDirVert( false) ; + Split( 10) ; + m_vnLeaves.push_back( 20) ; + m_vnLeaves.push_back( 21) ; + return true ; } //---------------------------------------------------------------------------- bool -Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) +Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) { // suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri int nCToSplit = -1 ; - double dLinTol = 0.2 ; + //double dLinTol = 0.2 ; //double dSideMin = 1 ; if ( ! m_bTrimmed || m_bTrimmed) { if ( ! m_bBilinear) { @@ -425,18 +447,18 @@ Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) // calcolo in quale direzione ho più curvatura // ptP00P10 è un punto tra P00 e P10 double dCurvU = 0, dCurvV = 0 ; - double dLenParU = m_mTree[nCToSplit].GetTopRight().x - m_mTree[nCToSplit].GetBottomLeft().x ; - double dLenParV = m_mTree[nCToSplit].GetTopRight().y - m_mTree[nCToSplit].GetBottomLeft().y ; + double dLenParU = ( m_mTree[nCToSplit].GetTopRight().x - m_mTree[nCToSplit].GetBottomLeft().x) / SBZ_TREG_COEFF ; + double dLenParV = ( m_mTree[nCToSplit].GetTopRight().y - m_mTree[nCToSplit].GetBottomLeft().y) / SBZ_TREG_COEFF; if ( dLenParU <= 1. / m_nDegV || dLenParV <= 1. / m_nDegU) { - double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; - double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; + double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 / SBZ_TREG_COEFF ; + double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 / SBZ_TREG_COEFF ; double dULoc = 0.5, dVLoc = 0.5 ; Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00 ; m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; - m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x / SBZ_TREG_COEFF, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x / SBZ_TREG_COEFF, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; Point3d ptV = ( 1 - dULoc) * ptP00P10 + dULoc * ptP11P01 ; Point3d ptU = ( 1 - dVLoc) * ptP10P11 + dVLoc * ptP01P00 ; dCurvV = Dist( ptV, ptPSrf) ; @@ -448,13 +470,13 @@ Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00, ptPSrfMid; double dStep = 1. / m_nDegU ; for ( double k = dStep ; k < 1 ; k = k + dStep) { - double dU = k * m_mTree[nCToSplit].GetTopRight().x + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().x ; - double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; + double dU = ( k * m_mTree[nCToSplit].GetTopRight().x + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().x) / SBZ_TREG_COEFF ; + double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 / SBZ_TREG_COEFF; m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; if ( k == 0.5) ptPSrfMid = ptPSrf ; - m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; - m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; CurveLine clV ; clV.Set( ptP00P10, ptP11P01) ; DistPointCurve dpc( ptPSrf, clV) ; @@ -464,14 +486,14 @@ Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) } dStep = 1. / m_nDegV ; for ( double k = dStep ; k < 1 ; k = k + dStep) { - double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; - double dV = k * m_mTree[nCToSplit].GetTopRight().y + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().y ; + double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 / SBZ_TREG_COEFF ; + double dV = ( k * m_mTree[nCToSplit].GetTopRight().y + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().y) / SBZ_TREG_COEFF ; if ( k == 0.5) ptPSrf = ptPSrfMid ; else m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x / SBZ_TREG_COEFF, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x / SBZ_TREG_COEFF, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; CurveLine clU ; clU.Set( ptP01P00, ptP10P11) ; DistPointCurve dpc( ptPSrf, clU) ; @@ -541,9 +563,9 @@ Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) int nStepsV = int( 51 * dDimV + 5 * ( 1 - dDimV)) ; for ( int u = 0 ; u < nStepsU && ! bSplit ; ++ u) { double dU = double ( u) / double ( nStepsU - 1) ; - double dULoc = ( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x ; - if ( ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz0) || - ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz1)) + double dULoc = (( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x) / SBZ_TREG_COEFF ; + 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) ; @@ -552,7 +574,7 @@ Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) clV.Set( pt0010, pt0111) ; for ( int v = 0 ; v < nStepsV ; ++ v) { double dV = double ( v) / double ( nStepsV - 1) ; - double dVLoc = ( 1 - dV) * m_mTree[nCToSplit].GetBottomLeft().y + dV * m_mTree[nCToSplit].GetTopRight().y ; + double dVLoc = ( ( 1 - dV) * m_mTree[nCToSplit].GetBottomLeft().y + dV * m_mTree[nCToSplit].GetTopRight().y) / SBZ_TREG_COEFF ; if ( ! m_pSrfBz->GetPointD1D2( dULoc, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBzV)) return false ; DistPointCurve dpc( ptBzV, clV) ; @@ -632,10 +654,10 @@ Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) } else { for ( double i = 0.25 ; i < 1 ; i = i + 0.25 ) { - dU = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().x + i * m_mTree[nCToSplit].GetTopRight().x ; - dV = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().y + i * m_mTree[nCToSplit].GetTopRight().y ; - double dVLoc = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 ; - double dULoc = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 ; + dU = (( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().x + i * m_mTree[nCToSplit].GetTopRight().x) / SBZ_TREG_COEFF ; + dV = (( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().y + i * m_mTree[nCToSplit].GetTopRight().y) / SBZ_TREG_COEFF ; + double dVLoc = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 / SBZ_TREG_COEFF ; + double dULoc = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 / SBZ_TREG_COEFF ; m_pSrfBz->GetPointD1D2( dU, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfU) ; m_pSrfBz->GetPointD1D2( dULoc, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfV) ; vPtU.push_back( ptPSrfU) ; @@ -689,8 +711,8 @@ Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) } for ( double i = 0.25 ; i < 1 ; i = i + 0.25) { for ( double j = 0.25 ; j < 1 ; j = j + 0.25) { - double dU = ( 1 - i) * m_mTree[nCToSplit].GetTopRight().x + i * m_mTree[nCToSplit].GetBottomLeft().x ; - double dV = ( 1 - j) * m_mTree[nCToSplit].GetTopRight().y + j * m_mTree[nCToSplit].GetBottomLeft().y ; + double dU = ( ( 1 - i) * m_mTree[nCToSplit].GetTopRight().x + i * m_mTree[nCToSplit].GetBottomLeft().x) / SBZ_TREG_COEFF ; + double dV = ( ( 1 - j) * m_mTree[nCToSplit].GetTopRight().y + j * m_mTree[nCToSplit].GetBottomLeft().y) / SBZ_TREG_COEFF ; m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; dErr = std::max( abs( DistPointPlane( ptPSrf, plAppr)), dErr) ; } @@ -1307,8 +1329,8 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons) if ( vVertices.size() == 5) { Point3d ptPSrf, ptP00, ptP10, ptP11, ptP01; double dU, dV ; - dU = ( m_mTree.at(nId).GetBottomLeft().x + m_mTree.at(nId).GetTopRight().x) / 2 ; - dV = ( m_mTree.at(nId).GetBottomLeft().y + m_mTree.at(nId).GetTopRight().y) / 2 ; + dU = ( m_mTree.at(nId).GetBottomLeft().x + m_mTree.at(nId).GetTopRight().x) / 2 / SBZ_TREG_COEFF; + dV = ( m_mTree.at(nId).GetBottomLeft().y + m_mTree.at(nId).GetTopRight().y) / 2 / SBZ_TREG_COEFF; m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; ptP00 = m_mVert.at(nId).at(0) ; ptP10 = m_mVert.at(nId).at(1) ; @@ -1555,13 +1577,14 @@ Tree::TraceLoopLabelCell( void) CurveLine clFirst ; clFirst.Set( ptFirst->first, ptSecond->first) ; INTVECTOR nCells = FindCell( ptStart, clFirst) ; - int nId ; + int nId, nFirstCell ; if ( (int)nCells.size() == 1) { nId = nCells[0] ; } else { nId = nCells.back() ; } + nFirstCell = nId ; // trovo quali punti della polyline sono nella cella e l'intersezione PNTVECTOR vptInters ; vptInters.push_back( ptStart) ; @@ -1581,11 +1604,11 @@ Tree::TraceLoopLabelCell( void) bool bVertex = false ; while ( plLoop.GetNextPoint( ptCurr)) { // sto uscendo dalla cella, quindi cerco l'intersezione - Point3d ptStart, ptEnd ; - plLoop.GetPrevPoint( ptStart) ; - plLoop.GetNextPoint( ptEnd) ; + Point3d ptTStart, ptTEnd ; + plLoop.GetPrevPoint( ptTStart) ; + plLoop.GetNextPoint( ptTEnd) ; CurveLine clTrim ; - clTrim.Set( ptStart, ptEnd) ; + 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 bLoopInside = false ; // trovo l'intersezione e passo alla cella successiva. nId viene aggiornato dalla funzione FindInters @@ -1602,10 +1625,11 @@ Tree::TraceLoopLabelCell( void) // aggiungo la fine del segmento nel vettore delle intersezioni vptInters.push_back( ptCurr) ; } - vptInters.pop_back() ; + if ( AreSamePointExact( ptCurr, ptStart)) + vptInters.pop_back() ; m_mTree[nId].m_vInters.back().vpt = vptInters ; if ( bLoopInside) { - m_mTree[nId].m_vnLoop.push_back( i) ; + //m_mTree[nId].m_vnLoop.push_back( i) ; // setto la categoria della cella if ( m_mTree[nId].m_nFlag == -1) m_mTree[nId].m_nFlag = 2 ; @@ -1618,24 +1642,27 @@ Tree::TraceLoopLabelCell( void) // sono tornato alla cella di partenza, quindi devo fare il merge dei due vettori di intersezione che ho creato per questa cella // per lo stesso loop else { + // verifico se sono effettivamente nella cella di partenza o nella penultima cella // devo verificare se il loop finisce in un vertice! in questo caso sono nella penultima cella! e devo fare un FindInters di nuovo per sistemare Point3d ptLast = m_mTree[nId].m_vInters.back().vpt.back() ; - Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; - Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; - int nLastId ; - if ( AreSamePointApprox( m_mTree[nId].GetTopRight(), ptLast) || - AreSamePointApprox( ptTl, ptLast) || - AreSamePointApprox( m_mTree[nId].GetBottomLeft(), ptLast) || - AreSamePointApprox( ptBr, ptLast)) { - Point3d ptStart, ptEnd ; - plLoop.GetPrevPoint( ptEnd) ; - plLoop.GetPrevPoint( ptStart) ; - CurveLine clTrim ; - clTrim.Set( ptStart, ptEnd) ; - vptInters.clear() ; - nLastId = nId ; - FindInters( nId, clTrim, vptInters, bVertex) ; - m_mTree[nLastId].m_vInters.back().vpt.push_back( vptInters[0]) ; + if ( nId != nFirstCell) { + Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + int nLastId ; + if ( AreSamePointApprox( m_mTree[nId].GetTopRight(), ptLast) || + AreSamePointApprox( ptTl, ptLast) || + AreSamePointApprox( m_mTree[nId].GetBottomLeft(), ptLast) || + AreSamePointApprox( ptBr, ptLast)) { + Point3d ptTStart, ptTEnd ; + plLoop.GetPrevPoint( ptTEnd) ; + plLoop.GetPrevPoint( ptTStart) ; + CurveLine clTrim ; + clTrim.Set( ptTStart, ptTEnd) ; + vptInters.clear() ; + nLastId = nId ; + FindInters( nId, clTrim, vptInters, bVertex) ; + m_mTree[nLastId].m_vInters.back().vpt.push_back( vptInters[0]) ; + } } int nOut = m_mTree[nId].m_vInters[nPass].nOut ; m_mTree[nId].m_vInters.back().vpt.insert( m_mTree[nId].m_vInters.back().vpt.end(), @@ -2256,6 +2283,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I while ( plCell.GetNextPoint( ptToAdd) && ! AreSamePointExact( ptToAdd, vEdgeVertex[next][0])) { vEdgeVertex[j].push_back( ptToAdd) ; } + //vEdgeVertex[next].push_back( ptToAdd) ; } // comincio a costruire il poligono @@ -2298,7 +2326,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I vLast.Normalize(); Vector3d vEdge ; if ( AreSameEdge( nEdge, 0)) { - if ( AreSamePointApprox(ptLast, ptTl) ) { + if ( AreSamePointExact(ptLast, ptTl) ) { vEdge = m_mTree[nId].GetBottomLeft() - ptTl ; vEdge.Normalize() ; if ( AreOppositeVectorApprox(vLast, vEdge) ) { @@ -2307,7 +2335,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I } } } - else if ( AreSameEdge( nEdge, 1) && AreSamePointApprox(ptLast, m_mTree[nId].GetBottomLeft()) ) { + else if ( AreSameEdge( nEdge, 1) && AreSamePointExact(ptLast, m_mTree[nId].GetBottomLeft()) ) { vEdge = ptBr - m_mTree[nId].GetBottomLeft() ; vEdge.Normalize() ; if ( AreOppositeVectorApprox(vLast, vEdge) ) { @@ -2316,7 +2344,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I } } else if ( AreSameEdge( nEdge, 2) ) { - if ( AreSamePointApprox(ptLast, ptBr) ) { + if ( AreSamePointExact(ptLast, ptBr) ) { vEdge = m_mTree[nId].GetTopRight() - ptBr ; vEdge.Normalize() ; if ( AreOppositeVectorApprox(vLast, vEdge) ) { @@ -2325,7 +2353,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I } } } - else if ( AreSameEdge( nEdge, 3) && AreSamePointApprox(ptLast, m_mTree[nId].GetTopRight()) ) { + else if ( AreSameEdge( nEdge, 3) && AreSamePointExact(ptLast, m_mTree[nId].GetTopRight()) ) { vEdge = ptTl - m_mTree[nId].GetTopRight() ; vEdge.Normalize() ; if ( AreOppositeVectorApprox(vLast, vEdge) ) { @@ -2393,16 +2421,36 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ; } - // se ho trovato un altro loop salto all'inizio del for + + // se ho trovato un altro loop salto all'inizio del for, dopo aver aggiunto eventuali punti intermedi if ( bValidNextStart) { + for ( int p = 1 ; p < (int) vEdgeVertex[nEdge].size() ; ++ p) { + if ( CheckIfBefore( nEdge, vEdgeVertex[nEdge][p], m_mTree[nId].m_vInters[vToCheckNow[nNext]].vpt[0]) ) { + plTrimmedPoly.AddUPoint( c, vEdgeVertex[nEdge][p]) ; + ++ c ; + } + } w = w + nSecondCheck ; continue ; } + // sono tornato indietro + else if ( ! bNotCameBack){ + Point3d ptStart ; + plTrimmedPoly.GetFirstPoint( ptStart) ; + for ( int p = 1 ; p < (int) vEdgeVertex[nEdge].size() ; ++ p) { + if ( CheckIfBefore( nEdge, vEdgeVertex[nEdge][p], ptStart) ) { + plTrimmedPoly.AddUPoint( c, vEdgeVertex[nEdge][p]) ; + ++ c ; + } + } + } } // non ho altri loop quindi aggiungo vertici finché torno al punto di partenza else { bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ; + Point3d ptStart ; + plTrimmedPoly.GetFirstPoint( ptStart) ; while ( bNotCameBack) { Point3d ptVert ; if ( nEdge == 0) @@ -2421,19 +2469,29 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I else nEdge = 0 ; // aggiorno le condizioni per il while - bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ; + bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ; } + for ( int p = 1 ; p < (int) vEdgeVertex[nEdge].size() ; ++ p) { + if ( CheckIfBefore( nEdge, vEdgeVertex[nEdge][p], ptStart)) { + plTrimmedPoly.AddUPoint( c, vEdgeVertex[nEdge][p]) ; + ++ c ; + } + } + } plTrimmedPoly.Close() ; + // controllo sull'area del poligono, se è 0 ( quindi un segmento), non lo aggiungo double dArea ; plTrimmedPoly.GetAreaXY( dArea) ; - if ( dArea > SQ_EPS_SMALL) { + //if ( dArea > SQ_EPS_SMALL) { + if ( dArea > 0) { vCellPolygons.push_back( plTrimmedPoly) ; vPolygons.push_back( vCellPolygons) ; ++ nPoly ; vnParentChunk.push_back( inA.nChunk) ; vCellPolygons.clear() ; } + c = 0 ; plTrimmedPoly.Clear() ; nEdgeIn = -1 ; @@ -2470,20 +2528,38 @@ Tree::CreateIslandAndHoles( int nLeafId, std::vector& vPolygons, if ( m_mTree[nId].m_nFlag == 3 || m_mTree[nId].m_nFlag == 2) { PolyLine plInLoop ; // 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 ; + Inters inA ; + // se ho almeno un loop CW che non è contenuto in un altro poligono o in un loop interno CCW devo aggiungere il bordo + bool bEdgeToAdd = true ; + bool bAllContained = true ; + bool bContained = false ; + int nInters = (int) m_mTree[nId].m_vInters.size() ; + for ( int n = 0 ; n < nInters ; ++ n) { + inA = m_mTree[nId].m_vInters[n] ; + 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) { + bContained = false ; + Inters inB = m_mTree[nId].m_vInters[0] ; + for( int c = 0 ; c < nInters ; ++ c){ + inB = m_mTree[nId].m_vInters[c] ; + if ( inB.nIn == -1) { + if ( inB != inA && inB.nChunk == inA.nChunk) { + bContained = true ; + break ; + } + } + else + break ; + } + bAllContained = bAllContained && bContained ; } } + else + break ; } - // la seconda condizione è da cambiareeeeeeeeeeeeeeeeeeeee//////////////////////////////////////////////////////////////////////////////////////////// - if ( m_mTree[nId].m_nFlag == 2 && ! inA.bCCW) { + + if ( m_mTree[nId].m_nFlag == 2 && ( bEdgeToAdd || ! bAllContained)) { // i loop esterni sono CW, quindi prima dei loop di trim aggiungo il bordo cella Point3d ptVert = m_mTree[nId].GetTopRight() ; plInLoop.AddUPoint( 0, ptVert) ; @@ -2503,42 +2579,44 @@ Tree::CreateIslandAndHoles( int nLeafId, std::vector& vPolygons, vCellPolygons.clear() ; plInLoop.Clear() ; } - while ( inA.nIn == -1) { - // numero di vertici aggiunti al nuovo poligono - int k = 0 ; - for ( Point3d ptInt : inA.vpt) { - plInLoop.AddUPoint( k, ptInt) ; - ++ k ; - } - plInLoop.Close(); - bool bAdded = false ; - // se il loop è CW devo controllare in quale altro dei poligoni che ho già aggiunto è contenuto - if ( ! inA.bCCW) { - Point3d ptStart ; - plInLoop.GetFirstPoint( ptStart) ; - int nOtherPoly = (int)vPolygons.size() ; - for ( int r = 0 ; r < nPoly ; ++r ) { - if ( IsPointInsidePolyLine( ptStart, vPolygons[nOtherPoly - r - 1][0], -0.01) && vnParentChunk[nPoly - r - 1] == inA.nChunk ) { - vPolygons[nOtherPoly - r - 1].push_back( plInLoop) ; - plInLoop.Clear() ; - vnParentChunk.push_back( inA.nChunk) ; - bAdded = true ; - break ; + for ( int i = 0 ; i < nInters ; ++ i) { + inA = m_mTree[nId].m_vInters[i] ; + if ( inA.nIn == -1) { + // numero di vertici aggiunti al nuovo poligono + int k = 0 ; + for ( Point3d ptInt : inA.vpt) { + plInLoop.AddUPoint( k, ptInt) ; + ++ k ; + } + plInLoop.Close(); + bool bAdded = false ; + // se il loop è CW devo controllare in quale altro dei poligoni che ho già aggiunto è contenuto + if ( ! inA.bCCW) { + Point3d ptStart ; + plInLoop.GetFirstPoint( ptStart) ; + int nOtherPoly = (int)vPolygons.size() ; + for ( int r = 0 ; r < nPoly ; ++r ) { + if ( IsPointInsidePolyLine( ptStart, vPolygons[nOtherPoly - r - 1][0], -0.01) && vnParentChunk[nPoly - r - 1] == inA.nChunk ) { + vPolygons[nOtherPoly - r - 1].push_back( plInLoop) ; + plInLoop.Clear() ; + vnParentChunk.push_back( inA.nChunk) ; + bAdded = true ; + break ; + } } } - } - if ( ! bAdded ) { - vCellPolygons.push_back( plInLoop) ; - vPolygons.push_back( vCellPolygons) ; - ++ nPoly ; - vnParentChunk.push_back( inA.nChunk) ; + if ( ! bAdded) { + vCellPolygons.push_back( plInLoop) ; + vPolygons.push_back( vCellPolygons) ; + ++ nPoly ; + vnParentChunk.push_back( inA.nChunk) ; + plInLoop.Clear() ; + vCellPolygons.clear() ; + } plInLoop.Clear() ; - vCellPolygons.clear() ; } - - plInLoop.Clear() ; - ++ n ; - inA = m_mTree[nId].m_vInters[n] ; + else + break ; } } return true ; @@ -2552,16 +2630,16 @@ Tree::CheckIfBefore( PolyLine& pl, int nEdge) const Point3d ptStart, ptEnd ; pl.GetFirstPoint( ptStart) ; pl.GetLastPoint( ptEnd) ; - if ( nEdge == 0 ) { + if ( AreSameEdge( nEdge, 0)) { return ptEnd.x > ptStart.x ; } - else if ( nEdge == 1 ) { + else if ( AreSameEdge( nEdge, 1) ) { return ptEnd.y > ptStart.y ; } - else if ( nEdge == 2 ) { + else if ( AreSameEdge( nEdge, 2) ) { return ptEnd.x < ptStart.x ; } - else if ( nEdge == 3 ) { + else if ( AreSameEdge( nEdge, 3) ) { return ptEnd.y < ptStart.y ; } return false ; @@ -2571,9 +2649,12 @@ Tree::CheckIfBefore( PolyLine& pl, int nEdge) const bool Tree::CheckIfBefore( Inters& inA) const { + // questa funzione è pensata in riferimento al lato 3, quindi nessuno dei due punti può stare su Edge = 3 // controllo se l'ingresso è prima dell'uscita int nEdge1 = inA.nIn ; int nEdge2 = inA.nOut ; + if ( nEdge1 == -1) + return false ; PolyLine pl ; pl.AddUPoint( 0, inA.vpt.back()) ; pl.AddUPoint( 1, inA.vpt[0]) ; @@ -2602,6 +2683,9 @@ Tree::CheckIfBefore( Inters& inA) const bool Tree::CheckIfBefore( int& nEdge1, Point3d& ptP1, int& nEdge2, Point3d& ptP2) const { + if ( nEdge1 == -1 || nEdge2 == -1) + return false ; + // questa funzione è pensata in riferimento al lato 3, quindi nessuno dei due punti può stare su Edge = 3 INTVECTOR vEdges = { 7, 0, 4, 1, 5, 2, 6} ; // controllo se ptP1, che è su nEdge1, viene prima di ptP2, che è su nEdge2. la partenza è da ptTR e l'arrivo è ptBr INTVECTOR :: iterator iter1 = find( vEdges.begin(), vEdges.end(), nEdge1) ; @@ -2630,16 +2714,16 @@ Tree::CheckIfBefore( int& nEdge, Point3d& ptP1, Point3d& ptP2) const { // sul lato nEdge controllo se ptP1 viene prima di ptP2. // i lati vengono percorsi in senso antiorario - if ( nEdge == 0 ) { + if ( AreSameEdge(nEdge, 0) ) { return ptP1.x > ptP2.x ; } - else if ( nEdge == 1 ) { + else if ( AreSameEdge(nEdge, 1) ) { return ptP1.y > ptP2.y ; } - else if ( nEdge == 2 ) { + else if ( AreSameEdge(nEdge, 2) ) { return ptP1.x < ptP2.x ; } - else if ( nEdge == 3 ) { + else if ( AreSameEdge(nEdge, 3) ) { return ptP1.y < ptP2.y ; } return false ; @@ -2655,25 +2739,25 @@ Tree::CheckIfAfter( PolyLine& pl, Point3d& ptNextStart, int nEdge) const // se i punti non sono sullo stesso lato ritorno false Point3d ptEnd ; pl.GetLastPoint( ptEnd) ; - if ( nEdge == 0 ) { + if ( AreSameEdge(nEdge, 0) ) { if ( ptNextStart.y > ptEnd.y - EPS_SMALL && ptNextStart.y < ptEnd.y + EPS_SMALL) return ptEnd.x > ptNextStart.x ; else return false ; } - else if ( nEdge == 1 ) { + else if ( AreSameEdge(nEdge, 1) ) { if ( ptNextStart.x > ptEnd.x - EPS_SMALL && ptNextStart.x < ptEnd.x + EPS_SMALL) return ptEnd.y > ptNextStart.y ; else return false ; } - else if ( nEdge == 2 ) { + else if ( AreSameEdge(nEdge, 2) ) { if ( ptNextStart.y > ptEnd.y - EPS_SMALL && ptNextStart.y < ptEnd.y + EPS_SMALL) return ptEnd.x < ptNextStart.x ; else return false ; } - else if ( nEdge == 3 ) { + else if ( AreSameEdge(nEdge, 3) ) { if ( ptNextStart.x > ptEnd.x - EPS_SMALL && ptNextStart.x < ptEnd.x + EPS_SMALL) return ptEnd.y < ptNextStart.y ; else @@ -2742,15 +2826,32 @@ Tree::AreSameEdge( int nEdge1, int nEdge2) const bool Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimmedPoly, int& c, Point3d& ptToAdd) const { - 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) ; - Point3d ptBL = m_mTree.at(nId).GetBottomLeft() ; - Point3d ptTR = m_mTree.at(nId).GetTopRight() ; + //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) ; + //Point3d ptBL = m_mTree.at(nId).GetBottomLeft() ; + //Point3d ptTR = m_mTree.at(nId).GetTopRight() ; + Point3d ptBr = vEdgeVertex[3][0] ; + Point3d ptTR = vEdgeVertex[0][0] ; + Point3d ptTl = vEdgeVertex[1][0] ; + Point3d ptBL = vEdgeVertex[2][0] ; Point3d ptLast ; plTrimmedPoly.GetLastPoint( ptLast) ; // verifico di essere allineato con un lato, sennò aggiungo e basta Vector3d vDir = ptToAdd - ptLast ; - vDir.Normalize() ; + // se non riesco a normalizzare perché sono troppo vicino ad un vertice allora aggiungo direttamente il vertice + if ( ! vDir.Normalize()) { + plTrimmedPoly.EraseLastUPoint() ; + if ( AreSamePointApprox( ptToAdd, ptBr)) + plTrimmedPoly.AddUPoint( c, ptBr) ; + else if ( AreSamePointApprox( ptToAdd, ptTR)) + plTrimmedPoly.AddUPoint( c, ptTR) ; + else if ( AreSamePointApprox( ptToAdd, ptTl)) + plTrimmedPoly.AddUPoint( c, ptTl) ; + else if ( AreSamePointApprox( ptToAdd, ptBL)) + plTrimmedPoly.AddUPoint( c, ptBL) ; + ++ c ; + return true ; + } if ( abs( vDir.x) > 1 - EPS_SMALL || abs( vDir.y) > 1 - EPS_SMALL) { // se su un edge devo fare dei controlli // edge 0 @@ -2761,8 +2862,6 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm plTrimmedPoly.AddUPoint( c, ptIntermed) ; ++ c ; } - else - break ; } plTrimmedPoly.AddUPoint( c, ptToAdd) ; ++ c ; @@ -2775,8 +2874,6 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm plTrimmedPoly.AddUPoint( c, ptIntermed) ; ++ c ; } - else - break ; } plTrimmedPoly.AddUPoint( c, ptToAdd) ; ++ c ; @@ -2789,8 +2886,6 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm plTrimmedPoly.AddUPoint( c, ptIntermed) ; ++ c ; } - else - break ; } plTrimmedPoly.AddUPoint( c, ptToAdd) ; ++ c ; @@ -2803,8 +2898,6 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm plTrimmedPoly.AddUPoint( c, ptIntermed) ; ++ c ; } - else - break ; } plTrimmedPoly.AddUPoint( c, ptToAdd) ; ++ c ; @@ -2891,11 +2984,50 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm bool Tree::SetRightEdgeIn( 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 Point3d ptBr( m_mTree.at(nId).GetTopRight().x , m_mTree.at(nId).GetBottomLeft().y) ; Point3d ptTR = m_mTree.at(nId).GetTopRight() ; - // se ho inters sul lato destro allora in parte è dentro int nPass = (int) m_mTree[nId].m_vInters.size() ; 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 ) { + bool bAllContained = true ; + bool bContained = false ; + Inters inA ; + int nInters = (int) m_mTree[nId].m_vInters.size() ; + for ( int n = 0 ; n < nInters ; ++ n) { + inA = m_mTree[nId].m_vInters[n] ; + if ( inA.nIn == -1) { + if ( ! inA.bCCW) { + bContained = false ; + Inters inB = m_mTree[nId].m_vInters[0] ; + for( int c = 0 ; c < nInters ; ++ c){ + inB = m_mTree[nId].m_vInters[c] ; + if ( inB.nIn == -1) { + if ( inB != inA && inB.nChunk == inA.nChunk) { + bContained = true ; + break ; + } + } + else + break ; + } + bAllContained = bAllContained && bContained ; + } + } + else + break ; + } + // se i loop CW interni sono tutti contenuti in un loop CW allora il right edge è esterno + bool bRightEdgeIn = ! bAllContained ; + if ( bRightEdgeIn) + m_mTree[nId].m_nRightEdgeIn = 1 ; + else + m_mTree[nId].m_nRightEdgeIn = 0 ; + return true ; + } + // se ho inters sul lato destro allora in parte è dentro for ( int k = 0 ; k < nPass ; ++ k) { if ( m_mTree[nId].m_vInters[k].nIn == 3 || m_mTree[nId].m_vInters[k].nOut == 3) { m_mTree[nId].m_nRightEdgeIn = 2 ; @@ -2925,20 +3057,34 @@ Tree::SetRightEdgeIn( int nId) // ciclo sulle inters e cerco quella più a destra, se ha un'uscita più bassa di un'entrata allora il right edge è compreso! bool bFound = false ; bool bRightMost = false ; - int nEdgeIn = 6, nEdgeOut = 7, nLoop ; - Point3d ptIn, ptOut ; - ptIn = ptOut = m_mTree[nId].GetBottomLeft() ; + int nEdgeUp = 6, nEdgeDown = 7, nLoop ; + Point3d ptDown( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + Point3d ptUp = m_mTree[nId].GetTopRight() ; for ( int k = 0 ; k < nPass ; ++ k) { - // trovo il loop che ha l'ingresso o l'uscita più a destra - if ( CheckIfBefore( m_mTree[nId].m_vInters[k].nIn, m_mTree[nId].m_vInters[k].vpt[0], nEdgeIn, ptIn) || - CheckIfBefore( nEdgeOut, ptOut, m_mTree[nId].m_vInters[k].nOut, m_mTree[nId].m_vInters[k].vpt.back())) { - nLoop = k ; - nEdgeIn = m_mTree[nId].m_vInters[k].nIn ; - ptIn = m_mTree[nId].m_vInters[k].vpt[0] ; - nEdgeOut = m_mTree[nId].m_vInters[k].nOut ; - ptOut = m_mTree[nId].m_vInters[k].vpt.back() ; - bFound = true ; + if ( m_mTree[nId].m_vInters[k].nIn != -1) { + // trovo il loop che ha l'ingresso o l'uscita più a destra + if ( CheckIfBefore( m_mTree[nId].m_vInters[k].nIn, m_mTree[nId].m_vInters[k].vpt[0], nEdgeUp, ptUp) || + CheckIfBefore( m_mTree[nId].m_vInters[k].nOut, m_mTree[nId].m_vInters[k].vpt.back(), nEdgeUp, ptUp) || + CheckIfBefore( nEdgeDown, ptDown, m_mTree[nId].m_vInters[k].nIn, m_mTree[nId].m_vInters[k].vpt[0]) || + CheckIfBefore( nEdgeDown, ptDown, m_mTree[nId].m_vInters[k].nOut, m_mTree[nId].m_vInters[k].vpt.back())) { + nLoop = k ; + if ( CheckIfBefore( m_mTree[nId].m_vInters[k])) { + ptUp = m_mTree[nId].m_vInters[k].vpt[0] ; + nEdgeUp = m_mTree[nId].m_vInters[k].nIn ; + ptDown = m_mTree[nId].m_vInters[k].vpt.back() ; + nEdgeDown = m_mTree[nId].m_vInters[k].nOut ; + } + else { + ptUp = m_mTree[nId].m_vInters[k].vpt.back() ; + nEdgeUp = m_mTree[nId].m_vInters[k].nOut ; + ptDown = m_mTree[nId].m_vInters[k].vpt[0] ; + nEdgeDown = m_mTree[nId].m_vInters[k].nIn ; + } + bFound = true ; + } } + else + continue ; } if ( bFound && CheckIfBefore( m_mTree[nId].m_vInters[nLoop])) { bRightMost = true ; @@ -2948,7 +3094,6 @@ Tree::SetRightEdgeIn( int nId) m_mTree[nId].m_nRightEdgeIn = 1 ; else m_mTree[nId].m_nRightEdgeIn = 0 ; - } if ( m_mTree[nId].m_nRightEdgeIn != -1) @@ -2991,77 +3136,106 @@ Tree::CategorizeCell( int& nId) // guardando nFlag del vicino bottom, che è già categorizzato! else if ( m_mTree[vNeigh[0]].m_nRightEdgeIn == 2 ) { GetBottomNeigh( nId, vNeigh1) ; - int nNeigh = vNeigh1[0] ; - if ( m_mTree[nNeigh].m_nFlag == 0 || m_mTree[nNeigh].m_nFlag == 2) { - m_mTree[nId].m_nFlag = 0 ; - } - else if ( m_mTree[nNeigh].m_nFlag == 4) { - m_mTree[nId].m_nFlag = 4 ; - } - else if ( m_mTree[nNeigh].m_nFlag == 1 || m_mTree[nNeigh].m_nFlag == 3) { - if ( m_mTree[nNeigh].m_nRightEdgeIn == 0) + if ( (int) vNeigh1.size() > 0) { + int nNeigh = vNeigh1[0] ; + if ( m_mTree[nNeigh].m_nFlag == 0 || m_mTree[nNeigh].m_nFlag == 2) { m_mTree[nId].m_nFlag = 0 ; - else if ( m_mTree[nNeigh].m_nRightEdgeIn == 1) + } + else if ( m_mTree[nNeigh].m_nFlag == 4) { m_mTree[nId].m_nFlag = 4 ; - else if ( m_mTree[nNeigh].m_nRightEdgeIn == 2 ) { - // in questo caso devo verificare le intersezioni sul lato destro del vicino bottom - // scorro e cerco l'intersezione più alta, se è out la cella è dentro, se è in devo verificare l'out se è più a sinistra o a destra. - int nPass = (int) m_mTree[nNeigh].m_vInters.size() ; - bool bTopMost = false ; - bool bFound = false; - Point3d ptInters, ptBr( m_mTree[nNeigh].GetTopRight().x, m_mTree[nNeigh].GetBottomLeft().y) ; - ptInters = ptBr ; // inizializzato a vertice bottom right - int nEdgeIn = 3, nEdgeOut = 3, nLoop ; - 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 ( 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 ; + } + else if ( m_mTree[nNeigh].m_nFlag == 1 || m_mTree[nNeigh].m_nFlag == 3) { + if ( m_mTree[nNeigh].m_nRightEdgeIn == 0) + m_mTree[nId].m_nFlag = 0 ; + else if ( m_mTree[nNeigh].m_nRightEdgeIn == 1) + m_mTree[nId].m_nFlag = 4 ; + else if ( m_mTree[nNeigh].m_nRightEdgeIn == 2 ) { + // in questo caso devo verificare le intersezioni sul lato destro del vicino bottom + // scorro e cerco l'intersezione più alta, se è out la cella è dentro, se è in devo verificare l'out se è più a sinistra o a destra. + int nPass = (int) m_mTree[nNeigh].m_vInters.size() ; + bool bTopMost = false ; + bool bFound = false; + Point3d ptInters, ptBr( m_mTree[nNeigh].GetTopRight().x, m_mTree[nNeigh].GetBottomLeft().y) ; + ptInters = ptBr ; // inizializzato a vertice bottom right + int nEdgeIn = 3, nEdgeOut = 3, nLoop ; + 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 ( 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 ( 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 ( 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 ; + if ( bFound && CheckIfBefore( m_mTree[nNeigh].m_vInters[nLoop])) { + bTopMost = 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 ; - } - if ( bFound && bTopMost) { - if ( AreSameEdge(m_mTree[nNeigh].m_vInters[nLoop].nIn, 3) && AreSameEdge(m_mTree[nNeigh].m_vInters[nLoop].nOut, 3) ) { - if ( CheckIfBefore( m_mTree[nNeigh].m_vInters[nLoop])) + if ( bFound && bTopMost) { + if ( AreSameEdge(m_mTree[nNeigh].m_vInters[nLoop].nIn, 3) && AreSameEdge(m_mTree[nNeigh].m_vInters[nLoop].nOut, 3) ) { + if ( CheckIfBefore( m_mTree[nNeigh].m_vInters[nLoop])) + m_mTree[nId].m_nFlag = 4 ; + else + m_mTree[nId].m_nFlag = 0 ; + } + else if ( AreSameEdge(m_mTree[nNeigh].m_vInters[nLoop].nOut, 3)) m_mTree[nId].m_nFlag = 4 ; - else - m_mTree[nId].m_nFlag = 0 ; - } - 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 - Point3d ptOut = m_mTree[nNeigh].m_vInters[nLoop].vpt.back() ; - Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; - if ( ptOut.x >= ptBr.x) - m_mTree[nId].m_nFlag = 4 ; - else - m_mTree[nId].m_nFlag = 0 ; + else if ( AreSameEdge(m_mTree[nNeigh].m_vInters[nLoop].nIn, 3) ) { + // devo verificare se l'uscita è più a sinistra o più a destra della cella + Point3d ptOut = m_mTree[nNeigh].m_vInters[nLoop].vpt.back() ; + Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + if ( ptOut.x >= ptBr.x) + m_mTree[nId].m_nFlag = 4 ; + else + m_mTree[nId].m_nFlag = 0 ; + } } } } } + // se non ho vicini bottom devo per forza guardare il vicino a sinistra + else { + Point3d ptInters = m_mTree[vNeigh[0]].GetTopRight() ; + int nLoop ; + int nEdge = 3 ; + 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)) { + ptInters = m_mTree[vNeigh[0]].m_vInters[k].vpt[0] ; + nLoop = k ; + 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) ) { + ptInters = m_mTree[vNeigh[0]].m_vInters[k].vpt.back() ; + nLoop = k ; + bIntersIn = false ; + } + } + } + if ( bIntersIn) + m_mTree[nId].m_nFlag = 4 ; + else + m_mTree[nId].m_nFlag = 0 ; + } } } else { @@ -3071,8 +3245,14 @@ Tree::CategorizeCell( int& nId) break ; } else if ( m_mTree[vNeigh[r]].m_nRightEdgeIn == 0) { - m_mTree[nId].m_nFlag = 0 ; - break ; + if ( m_mTree[vNeigh[r]].m_nFlag == 4) { + m_mTree[nId].m_nFlag = 4 ; + break ; + } + else if ( m_mTree[vNeigh[r]].m_nFlag == 0) { + m_mTree[nId].m_nFlag = 0 ; + break ; + } } } } @@ -3088,14 +3268,19 @@ 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 ; - while ( nEdge != inA.nIn || (int) vEdges.size() == 0) { + if ( nEdge > 3 && nEdge != 7) { + nEdge = nEdge - 4 ; + } + else if ( nEdge == 7) + nEdge = 0 ; + while ( ! AreSameEdge( nEdge, inA.nIn) || (int) vEdges.size() == 0) { vEdges.push_back( nEdge) ; if ( nEdge == 3) nEdge = 0 ; else ++ nEdge ; } - if ( inA.nIn != inA.nOut) + if ( ! AreSameEdge( inA.nIn, inA.nOut)) vEdges.push_back( nEdge) ; bool bFound = false ; for ( int i : vEdges) { @@ -3138,3 +3323,16 @@ Tree::CheckIfBetween( Inters& inA, Inters& inB) const } return bFound ; } + +//---------------------------------------------------------------------------- +bool +Tree::GetLeaves( std::vector& vLeaves) const +{ + vLeaves.clear() ; + for ( int k : m_vnLeaves) { + Cell cToAdd = m_mTree.at( k) ; + vLeaves.push_back( cToAdd) ; + } + + return true ; +} diff --git a/Tree.h b/Tree.h index 55b76f0..c1e71ba 100644 --- a/Tree.h +++ b/Tree.h @@ -36,6 +36,12 @@ struct Inters { ( bEqIn && nIn == 2 && vpt[0].x < b.vpt[0].x) || ( bEqIn && nIn == 3 && vpt[0].y < b.vpt[0].y) ; } + bool operator == ( Inters& b) { + return AreSamePointExact( vpt[0], b.vpt[0]) ; + } + bool operator != ( Inters& b){ + return ! AreSamePointExact( vpt[0], b.vpt[0]) ; + } } ; // nIn e nOut sono flag che indicano da quale lato ho l'ingresso e l'uscita 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 @@ -78,7 +84,7 @@ 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à - INTVECTOR m_vnLoop ; // indice dei loop contenuti nella cella + //INTVECTOR m_vnLoop ; // indice dei loop contenuti nella cella 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 @@ -95,7 +101,7 @@ class Tree public : ~Tree( void) ; Tree( void) ; - Tree ( const SurfBezier* pSrfBz, bool bSplitPatches = false) ; + Tree ( const SurfBezier* pSrfBz, bool bSplitPatches = true) ; void SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches = true) ; bool BuildTree( double dLinTol = LIN_TOL_STD, double dSideMin = 5, 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 @@ -103,7 +109,7 @@ public : 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 - + bool GetLeaves ( std::vector& vLeaves) const ; private : void Split( int nId, double dSplitValue) ; // funzione di split di una cella al parametro indicato nella direzione data da bVert From d3d7f94c3aa63a65761f0bde885e70b11db0eb16 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 13 Jun 2023 11:55:33 +0200 Subject: [PATCH 15/44] =?UTF-8?q?EgtGeomKernel=20:=20-=20risolti=20i=20bug?= =?UTF-8?q?=20noti=20-=20gestiti=20problemi=20numerici=20al=20bordo=20dell?= =?UTF-8?q?e=20celle=20Manca=20-=20test=20in=20casi=20pi=C3=B9=20complicat?= =?UTF-8?q?i?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SurfBezier.cpp | 10 ++-- Tree.cpp | 156 +++++++++++++++++++++++++++++++++++++------------ Tree.h | 21 ++++++- 3 files changed, 144 insertions(+), 43 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 36bacaa..c072092 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -1500,8 +1500,9 @@ SurfBezier::GetAuxSurf( void) const // costruttore della superficie Tree Tree( this, true) ; - Tree.BuildTree_test() ; - //Tree.BuildTree( 0.2, 5) ; + //Tree.BuildTree_test() ; + //Tree.BuildTree( 0.05, 1) ; + Tree.BuildTree( 0.5, 10) ; //Tree.BuildTree( 1, 25) ; vector vvPL ; Tree.GetPolygons( vvPL) ; @@ -1546,8 +1547,9 @@ bool SurfBezier::GetLeaves( std::vector>& vLeaves) const { Tree Tree( this, true) ; - Tree.BuildTree_test() ; - //Tree.BuildTree( 0.2, 5) ; + //Tree.BuildTree_test() ; + //Tree.BuildTree( 0.05, 1) ; + Tree.BuildTree( 0.5, 10) ; //Tree.BuildTree( 1, 25) ; std::vector vCells ; Tree.GetLeaves( vCells) ; diff --git a/Tree.cpp b/Tree.cpp index d5f3f04..23c5e5d 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -69,7 +69,7 @@ Cell::IsLeaf ( void) const //---------------------------------------------------------------------------- Tree::Tree( void) - : m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosed( false) + : m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosed( false), m_bSplitPatches( true) { Point3d ptBl( 0, 0), ptTr ( 1 * SBZ_TREG_COEFF, 1 * SBZ_TREG_COEFF) ; Cell cRoot( ptBl, ptTr) ; @@ -78,9 +78,9 @@ Tree::Tree( void) //---------------------------------------------------------------------------- Tree::Tree( const SurfBezier* pSrfBz, bool bSplitPatches) - : m_bBilinear( false), m_bMulti( false), m_bClosed( false) + : m_bBilinear( false), m_bMulti( false), m_bClosed( false), m_bSplitPatches( bSplitPatches) { - SetSurf( pSrfBz, bSplitPatches) ; + SetSurf( pSrfBz, m_bSplitPatches) ; } //---------------------------------------------------------------------------- @@ -93,6 +93,7 @@ void Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) { m_pSrfBz = pSrfBz ; + m_bSplitPatches = bSplitPatches ; // le coordinate delle celle sono nello spazio parametrico int nDegU, nDegV, nSpanU, nSpanV ; bool bIsRat, bTrimmed ; @@ -100,6 +101,8 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) m_bTrimmed = bTrimmed ; m_nDegU = nDegU ; m_nDegV = nDegV ; + m_nSpanU = nSpanU ; + m_nSpanV = nSpanV ; if ( nDegU == 1 && nDegV == 1) m_bBilinear = true ; if ( nSpanU * nSpanV != 1) @@ -176,7 +179,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) int nId = -1 ; for ( int i = 1 ; i < nSpanU ; ++i) { m_mTree[nId].SetSplitDirVert( true) ; - Split( nId, i) ; + Split( nId, i * SBZ_TREG_COEFF) ; ++ nId ; ++ nId ; } @@ -185,11 +188,13 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) for ( int nId : vLeaves) { for ( int j = nSpanV - 1 ; j > 0 ; --j ) { m_mTree[nId].SetSplitDirVert( false) ; - Split( nId, j) ; + Split( nId, j * SBZ_TREG_COEFF) ; nId = m_mTree[nId].m_nChild2 ; } } - // split preliminari per dividere le patch in modo da triangolarle indipendentemente//////////////////////////////////////////////////////// + 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 { @@ -603,6 +608,8 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) m_mTree[nCToSplit].SetProcessed() ; // risalgo i parent finché non trovo il primo Child2 da processare nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( nCToSplit == -2) + return true ; if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) m_mTree[nCToSplit].SetProcessed() ; while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { @@ -736,6 +743,8 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) m_mTree[nCToSplit].SetProcessed() ; // risalgo i parent finché non trovo il primo Child2 da processare nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( nCToSplit == -2) + return true ; if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) m_mTree[nCToSplit].SetProcessed() ; while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { @@ -1215,7 +1224,8 @@ Tree::GetPolygons( std::vector& vPolygons) { } // trimmata else { - TraceLoopLabelCell() ; + if ( ! TraceLoopLabelCell()) + return false ; POLYLINEVECTOR vPolygonsBasic ; GetPolygonsBasic( vPolygonsBasic) ; // scorro sui poligoni delle celle non trimmate @@ -1416,12 +1426,19 @@ Tree::FindCell( const Point3d& ptToAssign, CurveLine& clTrim) const return nCells ; } - // se lo spazio parametrico non è stato suddiviso ( ho un piano), restituisco la cella root - if ( m_mTree.at(nId).IsLeaf() ) { - nCells.push_back( nId) ; - return nCells ; - } + //// se lo spazio parametrico non è stato suddiviso ( ho un piano), restituisco la cella root + //if ( m_mTree.at(nId).IsLeaf() ) { + // nCells.push_back( nId) ; + // return nCells ; + //} + // se ho diviso preliminarmente le patches e in uno dei due parametri ho un numero dispari di patches devo individuare a mano la cella parent + // in cui individuare la foglia giusta + if ( m_bSplitPatches && ( (m_nSpanU % 2 != 0 && m_nSpanU > 1) || (m_nSpanV % 2 != 0 && m_nSpanV > 1))) { + INTVECTOR nParents = FindCell( ptToAssign, clTrim, m_vnParents) ; + nId = nParents.back() ; + } + // individuo la foglia in cui ho lo start del loop while ( ! m_mTree.at(nId).IsLeaf()) { if ( m_mTree.at(nId).IsSplitVert()) { double dMid = ( m_mTree.at(nId).GetBottomLeft().x + m_mTree.at(nId).GetTopRight().x) / 2 ; @@ -1442,11 +1459,14 @@ Tree::FindCell( const Point3d& ptToAssign, CurveLine& clTrim) const } } } - if ( nId != -1) - nCells.push_back( nId) ; + //if ( nId != -1) + // nCells.push_back( nId) ; + //if ( nId == -1) // nId = -2 ; + nCells.push_back( nId) ; + //// devo verificare se sono sul bordo di una cella: in questo caso dovrei restituire anche il vicino con cui condivido quel lato!! ///////////////////// Point3d ptBr( m_mTree.at(nId).GetTopRight().x , m_mTree.at(nId).GetBottomLeft().y) ; @@ -1482,7 +1502,7 @@ Tree::FindCell( const Point3d& ptToAssign, CurveLine& clTrim) const if ( AreSamePointApprox(ptToAssign, ptTl) || AreSamePointApprox( ptToAssign, m_mTree.at(nId).GetBottomLeft()) || AreSamePointApprox(ptToAssign, ptBr) || - AreSamePointApprox( ptToAssign, ptTl)) + AreSamePointApprox( ptToAssign, m_mTree.at(nId).GetTopRight())) { Point3d ptToAssignPlus ; double dParam ; @@ -1602,6 +1622,7 @@ Tree::TraceLoopLabelCell( void) INTVECTOR :: iterator iter = find( m_vnLeaves.begin(), m_vnLeaves.end(), nId) ; int nIdPolygon = std::distance( m_vnLeaves.begin(), iter) ; bool bVertex = false ; + bool bEraseNextPoint = false ; while ( plLoop.GetNextPoint( ptCurr)) { // sto uscendo dalla cella, quindi cerco l'intersezione Point3d ptTStart, ptTEnd ; @@ -1610,10 +1631,28 @@ Tree::TraceLoopLabelCell( void) 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 + if ( bEraseNextPoint ) { + vptInters.pop_back() ; + bEraseNextPoint = false ; + } bLoopInside = false ; - // trovo l'intersezione e passo alla cella successiva. nId viene aggiornato dalla funzione FindInters + // trovo l'intersezione e passo alla cella successiva. nId viene aggiornato dalla funzione FindInters bVertex = false ; - FindInters( nId, clTrim, vptInters, bVertex) ; + // se non trovo l'intersezione vuol dire che non sono nella cella giusta! + // al precedente FindInters avrei dovuto passare di cella + if ( ! FindInters( nId, clTrim, vptInters, bVertex)) { + // scaterò il punto molto vicino al lato e tengo solo l'intersezione del trim col lato + m_mTree[nId].m_vInters.back().vpt.pop_back() ; + plLoop.GetPrevPoint( ptTEnd) ; + plLoop.GetPrevPoint( ptTStart) ; + plLoop.GetNextPoint( ptCurr) ; + clTrim.Set( ptTStart, ptTEnd) ; + //clTrim.ExtendEndByLen( EPS_SMALL * 2) ; + vptInters.clear() ; + if ( FindInters( nId, clTrim, vptInters, bVertex)) + return false ; + bEraseNextPoint = true ; + } // ricalcolo la posizione di nId nel vettore delle foglie iter = find( m_vnLeaves.begin(), m_vnLeaves.end(), nId) ; nIdPolygon = std::distance( m_vnLeaves.begin(), iter) ; @@ -1644,7 +1683,8 @@ Tree::TraceLoopLabelCell( void) else { // verifico se sono effettivamente nella cella di partenza o nella penultima cella // devo verificare se il loop finisce in un vertice! in questo caso sono nella penultima cella! e devo fare un FindInters di nuovo per sistemare - Point3d ptLast = m_mTree[nId].m_vInters.back().vpt.back() ; + //Point3d ptLast = m_mTree[nId].m_vInters.back().vpt.back() ; + Point3d ptLast = ptCurr ; if ( nId != nFirstCell) { Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; @@ -1661,21 +1701,43 @@ Tree::TraceLoopLabelCell( void) vptInters.clear() ; nLastId = nId ; FindInters( nId, clTrim, vptInters, bVertex) ; - m_mTree[nLastId].m_vInters.back().vpt.push_back( vptInters[0]) ; + if ( ! AreSamePointExact( vptInters[0], m_mTree[nLastId].m_vInters.back().vpt.back())) + m_mTree[nLastId].m_vInters.back().vpt.push_back( vptInters[0]) ; } } - int nOut = m_mTree[nId].m_vInters[nPass].nOut ; - m_mTree[nId].m_vInters.back().vpt.insert( m_mTree[nId].m_vInters.back().vpt.end(), - m_mTree[nId].m_vInters[nPass].vpt.begin(), - m_mTree[nId].m_vInters[nPass].vpt.end()) ; - m_mTree[nId].m_vInters[nPass] = m_mTree[nId].m_vInters.back() ; - m_mTree[nId].m_vInters.pop_back() ; - // sistemo il lato d'uscita - m_mTree[nId].m_vInters[nPass].nOut = nOut ; + // sono tornato nella cella iniziale, quindi giunto i due vettori intersezione + if ( nId == nFirstCell) { + int nOut = m_mTree[nId].m_vInters[nPass].nOut ; + m_mTree[nId].m_vInters.back().vpt.insert( m_mTree[nId].m_vInters.back().vpt.end(), + m_mTree[nId].m_vInters[nPass].vpt.begin(), + m_mTree[nId].m_vInters[nPass].vpt.end()) ; + m_mTree[nId].m_vInters[nPass] = m_mTree[nId].m_vInters.back() ; + m_mTree[nId].m_vInters.pop_back() ; + // sistemo il lato d'uscita + m_mTree[nId].m_vInters[nPass].nOut = nOut ; + } + // se non sono tornato alla cella di partenza + else { + m_mTree[nId].m_vInters.pop_back() ; + if ( (int)m_mTree[nId].m_vInters.size() == 0) + m_mTree[nId].m_nFlag = 0 ; + // aggiusto nIn della cella di partenza ( in questo caso dovrei aver avuto un ingresso direttamente in un vertice) + Point3d ptFirst = m_mTree[nFirstCell].m_vInters[nPass].vpt[0] ; + Point3d ptTl( m_mTree[nFirstCell].GetBottomLeft().x, m_mTree[nFirstCell].GetTopRight().y) ; + Point3d ptBr( m_mTree[nFirstCell].GetTopRight().x, m_mTree[nFirstCell].GetBottomLeft().y) ; + if ( AreSamePointApprox( m_mTree[nFirstCell].GetTopRight(), ptFirst)) + m_mTree[nFirstCell].m_vInters[nPass].nIn = 7 ; + else if (AreSamePointApprox( ptTl, ptFirst)) + m_mTree[nFirstCell].m_vInters[nPass].nIn = 4 ; + else if (AreSamePointApprox( m_mTree[nFirstCell].GetBottomLeft(), ptFirst)) + m_mTree[nFirstCell].m_vInters[nPass].nIn = 5 ; + else if (AreSamePointApprox( ptBr, ptFirst)) + m_mTree[nFirstCell].m_vInters[nPass].nIn = 6 ; + } } } - // riordino i vettori di intersezione per ogni cella e setto il flag RightEdgeIn + // riordino i vettori di intersezione per ogni cella e setto il flag RightEdgeIn for ( int nId : m_vnLeaves) { std::sort( m_mTree[nId].m_vInters.begin( ), m_mTree[nId].m_vInters.end()) ; SetRightEdgeIn( nId) ; @@ -1913,16 +1975,21 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert // intersezione e controlli IntersLineLine illExit( clTrim, clEdge, true) ; IntCrvCrvInfo aInfo, aInfo2 ; - //if ( ! illExit.GetIntCrvCrvInfo( aInfo) ) - // return false ; - illExit.GetIntCrvCrvInfo( aInfo) ; + bool bIntersOn1Found = true ; + if ( ! illExit.GetIntCrvCrvInfo( aInfo) && ! clEdge2.IsValid()) { + bIntersOn1Found = false ; + return false ; + } if ( clEdge2.IsValid()){ IntersLineLine illExit2( clTrim, clEdge2, true) ; //if ( ! illExit2.GetIntCrvCrvInfo( aInfo2) ) // return false ; // verifico su quale dei due lati ho l'intersezione if ( ! illExit2.GetIntCrvCrvInfo( aInfo2)) - ptInters = aInfo.IciA[0].ptI ; + if ( bIntersOn1Found) + ptInters = aInfo.IciA[0].ptI ; + else + return false ; else { // solo intersezione sul lato 2 if ( illExit.GetNumInters() == 0 ) { @@ -1958,7 +2025,10 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert nEdge = 7 ; } m_mTree[nId].m_vInters.back().nOut = nEdge ; - vptInters.push_back( ptInters) ; + if ( (int)vptInters.size() == 0) + vptInters.push_back( ptInters) ; + else if ( ! AreSamePointExact(ptInters , vptInters.back())) + 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]) ; @@ -2303,6 +2373,9 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I int nFirstLoopInPoly = -1 ; INTVECTOR vAddedLoops ; for ( int w = 0 ; w < (int)vToCheckNow.size() ; ++ w) { + if ( m_mTree[nId].m_vInters[w].vpt.size() < 2) { + continue ; + } // indice del loop in m_vInters int j = vToCheckNow[w] ; Inters inA = m_mTree[nId].m_vInters[j] ; @@ -2366,6 +2439,8 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I // quindi salto al prossimo loop if ( plTrimmedPoly.GetPointNbr() == 1 ) { plTrimmedPoly.Clear() ; + if ( j == nFirstLoopInPoly) + nEdgeIn = -1 ; continue ; } if ( nEdge > 3 && nEdge != 7 ) { @@ -2530,7 +2605,7 @@ Tree::CreateIslandAndHoles( int nLeafId, std::vector& vPolygons, // numero dei loop interni passati Inters inA ; // se ho almeno un loop CW che non è contenuto in un altro poligono o in un loop interno CCW devo aggiungere il bordo - bool bEdgeToAdd = true ; + //bool bEdgeToAdd = true ; bool bAllContained = true ; bool bContained = false ; int nInters = (int) m_mTree[nId].m_vInters.size() ; @@ -2559,7 +2634,8 @@ Tree::CreateIslandAndHoles( int nLeafId, std::vector& vPolygons, break ; } - if ( m_mTree[nId].m_nFlag == 2 && ( bEdgeToAdd || ! bAllContained)) { + //if ( m_mTree[nId].m_nFlag == 2 && ( bEdgeToAdd || ! bAllContained)) { + if ( m_mTree[nId].m_nFlag == 2 && ! bAllContained) { // i loop esterni sono CW, quindi prima dei loop di trim aggiungo il bordo cella Point3d ptVert = m_mTree[nId].GetTopRight() ; plInLoop.AddUPoint( 0, ptVert) ; @@ -2837,7 +2913,11 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm Point3d ptLast ; plTrimmedPoly.GetLastPoint( ptLast) ; // verifico di essere allineato con un lato, sennò aggiungo e basta - Vector3d vDir = ptToAdd - ptLast ; + Vector3d vDir; + if ( ! AreSamePointExact(ptToAdd, ptLast)) + vDir = ptToAdd - ptLast ; + else + return true ; // se non riesco a normalizzare perché sono troppo vicino ad un vertice allora aggiungo direttamente il vertice if ( ! vDir.Normalize()) { plTrimmedPoly.EraseLastUPoint() ; @@ -3027,7 +3107,7 @@ Tree::SetRightEdgeIn( int nId) m_mTree[nId].m_nRightEdgeIn = 0 ; return true ; } - // se ho inters sul lato destro allora in parte è dentro + // se ho inters sul lato destro ( nEdge == 3) allora in parte è dentro for ( int k = 0 ; k < nPass ; ++ k) { if ( m_mTree[nId].m_vInters[k].nIn == 3 || m_mTree[nId].m_vInters[k].nOut == 3) { m_mTree[nId].m_nRightEdgeIn = 2 ; @@ -3307,7 +3387,7 @@ Tree::CheckIfBetween( Inters& inA, 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.nIn, inA.vpt[0])) + if ( CheckIfBefore(inA.nIn, inB.vpt[0], inA.vpt[0])) bFound = true ; } else diff --git a/Tree.h b/Tree.h index c1e71ba..39e5333 100644 --- a/Tree.h +++ b/Tree.h @@ -18,6 +18,7 @@ #include "SurfBezier.h" #include "GeoConst.h" #include "CurveLine.h" +#include "/EgtDev/Include/EGkPolyLine.h" struct Inters { int nIn ; @@ -30,7 +31,21 @@ struct Inters { // 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 bEqIn = ( nIn == b.nIn) ; - return nIn < b.nIn || + double dAreaA = 0 , dAreaB = 0 ; + if ( bEqIn && nIn == -1) { + PolyLine pl ; + for ( int k = 0 ; k < (int)vpt.size(); ++ k) + pl.AddUPoint( k, vpt[k]) ; + pl.Close() ; + pl.GetAreaXY( dAreaA) ; + pl.Clear() ; + for ( int k = 0 ; k < (int)b.vpt.size(); ++ k) + pl.AddUPoint( k, b.vpt[k]) ; + pl.Close() ; + pl.GetAreaXY( dAreaB) ; + } + return nIn < b.nIn || + ( bEqIn && nIn == -1 && dAreaA > 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) || @@ -153,11 +168,15 @@ private : bool m_bBilinear ; // superficie bilineare bool m_bMulti ; // superficie multi-patch bool m_bClosed ; // superficie chiusa + bool m_bSplitPatches ; // flag che indica se le patches sono state divise prima della creazione dell'albero int m_nDegU ; // grado della superficie nel parametro U int m_nDegV ; // grado della superficie nel parametro V + int m_nSpanU ; + int m_nSpanV ; std::vector m_vPolygons ; // vettore dei poligoni del tree //std::map m_mPolygons ; // mappa dei poligoni std::map m_mTree ; // mappa che contiene tutti i nodi e le foglie dell'albero. -2 è puntatore Null e -1 è root std::map m_mVert ; // mappa che contiene tutti i vertici 3d delle celle del tree. L'Id è lo stesso che la cella ha in m_mTree INTVECTOR m_vnLeaves ; // vettore delle foglie + INTVECTOR m_vnParents ; // vettore delle celle ottenute dalla divisione preliminare in singole patch } ; \ No newline at end of file From cb1edcf20abcaebca36c1795399a17f1efb0e5e5 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 13 Jun 2023 16:40:45 +0200 Subject: [PATCH 16/44] EgtGeomKernel : - sistemati vari bug Manca - da testare superfici e trim complessi --- SurfBezier.cpp | 8 ++++---- Tree.cpp | 44 +++++++++++++++++++++++++++++++++++++------- Tree.h | 3 ++- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index c072092..b74b70c 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -1500,9 +1500,9 @@ SurfBezier::GetAuxSurf( void) const // costruttore della superficie Tree Tree( this, true) ; - //Tree.BuildTree_test() ; + Tree.BuildTree_test() ; //Tree.BuildTree( 0.05, 1) ; - Tree.BuildTree( 0.5, 10) ; + //Tree.BuildTree( 0.5, 10) ; //Tree.BuildTree( 1, 25) ; vector vvPL ; Tree.GetPolygons( vvPL) ; @@ -1547,9 +1547,9 @@ bool SurfBezier::GetLeaves( std::vector>& vLeaves) const { Tree Tree( this, true) ; - //Tree.BuildTree_test() ; + Tree.BuildTree_test() ; //Tree.BuildTree( 0.05, 1) ; - Tree.BuildTree( 0.5, 10) ; + //Tree.BuildTree( 0.5, 10) ; //Tree.BuildTree( 1, 25) ; std::vector vCells ; Tree.GetLeaves( vCells) ; diff --git a/Tree.cpp b/Tree.cpp index 23c5e5d..a357514 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -1434,7 +1434,7 @@ Tree::FindCell( const Point3d& ptToAssign, CurveLine& clTrim) const // se ho diviso preliminarmente le patches e in uno dei due parametri ho un numero dispari di patches devo individuare a mano la cella parent // in cui individuare la foglia giusta - if ( m_bSplitPatches && ( (m_nSpanU % 2 != 0 && m_nSpanU > 1) || (m_nSpanV % 2 != 0 && m_nSpanV > 1))) { + if ( m_bSplitPatches && ( m_nSpanU > 1 || m_nSpanV > 1)) { INTVECTOR nParents = FindCell( ptToAssign, clTrim, m_vnParents) ; nId = nParents.back() ; } @@ -1664,7 +1664,7 @@ Tree::TraceLoopLabelCell( void) // aggiungo la fine del segmento nel vettore delle intersezioni vptInters.push_back( ptCurr) ; } - if ( AreSamePointExact( ptCurr, ptStart)) + if ( nId == nFirstCell) vptInters.pop_back() ; m_mTree[nId].m_vInters.back().vpt = vptInters ; if ( bLoopInside) { @@ -1683,16 +1683,18 @@ Tree::TraceLoopLabelCell( void) else { // verifico se sono effettivamente nella cella di partenza o nella penultima cella // devo verificare se il loop finisce in un vertice! in questo caso sono nella penultima cella! e devo fare un FindInters di nuovo per sistemare - //Point3d ptLast = m_mTree[nId].m_vInters.back().vpt.back() ; - Point3d ptLast = ptCurr ; + Point3d ptLast = m_mTree[nId].m_vInters.back().vpt.back() ; // devo recuperare l'intersezione del trim con i bordi delle celle//////////////////// + //Point3d ptLast = ptCurr ; if ( nId != nFirstCell) { Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; - int nLastId ; + int nLastId, nEdge ; + // qui devo tener conto anche della possibilità che il trim termini parzialmente coincidente con un lato/////////////////////////////////// if ( AreSamePointApprox( m_mTree[nId].GetTopRight(), ptLast) || AreSamePointApprox( ptTl, ptLast) || AreSamePointApprox( m_mTree[nId].GetBottomLeft(), ptLast) || - AreSamePointApprox( ptBr, ptLast)) { + AreSamePointApprox( ptBr, ptLast) || + OnWhichEdge( nId, ptLast,nEdge)) { Point3d ptTStart, ptTEnd ; plLoop.GetPrevPoint( ptTEnd) ; plLoop.GetPrevPoint( ptTStart) ; @@ -1733,6 +1735,12 @@ Tree::TraceLoopLabelCell( void) m_mTree[nFirstCell].m_vInters[nPass].nIn = 5 ; else if (AreSamePointApprox( ptBr, ptFirst)) m_mTree[nFirstCell].m_vInters[nPass].nIn = 6 ; + // sono su un lato e non su un vertice + else { + int nEdge ; + OnWhichEdge( nFirstCell, ptFirst, nEdge) ; + m_mTree[nFirstCell].m_vInters[nPass].nIn = nEdge ; + } } } } @@ -2619,7 +2627,7 @@ Tree::CreateIslandAndHoles( int nLeafId, std::vector& vPolygons, for( int c = 0 ; c < nInters ; ++ c){ inB = m_mTree[nId].m_vInters[c] ; if ( inB.nIn == -1) { - if ( inB != inA && inB.nChunk == inA.nChunk) { + if ( inB != inA && inB.nChunk == inA.nChunk && inB.bCCW) { bContained = true ; break ; } @@ -3416,3 +3424,25 @@ Tree::GetLeaves( std::vector& vLeaves) const return true ; } + +//---------------------------------------------------------------------------- +bool +Tree::OnWhichEdge( int nId, Point3d& ptToAssign, int& nEdge) const +{ + Point3d ptTR = m_mTree.at(nId).GetTopRight() ; + Point3d ptBL = m_mTree.at(nId).GetBottomLeft() ; + Point3d ptTl ( ptBL.x, ptTR.y) ; + Point3d ptBr ( ptTR.x, ptBL.y) ; + + if ( ptToAssign.x >= ptBL.x && ptToAssign.x <= ptTR.x && abs( ptToAssign.y - ptTR.y) < EPS_SMALL) + nEdge = 0 ; + else if ( ptToAssign.y >= ptBL.y && ptToAssign.y <= ptTR.y && abs( ptToAssign.x - ptBL.x) < EPS_SMALL) + nEdge = 1 ; + else if ( ptToAssign.x >= ptBL.x && ptToAssign.x <= ptTR.x && abs( ptToAssign.y - ptBL.y) < EPS_SMALL) + nEdge = 2 ; + else if ( ptToAssign.y >= ptBL.y && ptToAssign.y <= ptTR.y && abs( ptToAssign.x - ptTR.x) < EPS_SMALL) + nEdge = 3 ; + else + return false ; + return true ; +} diff --git a/Tree.h b/Tree.h index 39e5333..62a3830 100644 --- a/Tree.h +++ b/Tree.h @@ -45,7 +45,7 @@ struct Inters { pl.GetAreaXY( dAreaB) ; } return nIn < b.nIn || - ( bEqIn && nIn == -1 && dAreaA > dAreaB) || + ( 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) || @@ -156,6 +156,7 @@ private : bool SetRightEdgeIn( int nId) ; bool CategorizeCell( int& nId) ; bool CheckIfBetween( Inters& inA, Inters& inB) const ; + bool OnWhichEdge( int nId, Point3d& ptToAssign, int& nEdge) const ; private : const SurfBezier* m_pSrfBz ; // superficie di bezier From 4daa62db978a542f6e823deb5075e83fd938fcd5 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Thu, 15 Jun 2023 10:47:53 +0200 Subject: [PATCH 17/44] EgtGeomKernel : - risolti i bug noti - fatti con successo test con superfici e curve complesse manca - pulizia del codice. --- SurfBezier.cpp | 10 +- Tree.cpp | 310 +++++++++++++------------------------------------ Tree.h | 2 +- 3 files changed, 90 insertions(+), 232 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index b74b70c..bbf3689 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -1500,8 +1500,9 @@ SurfBezier::GetAuxSurf( void) const // costruttore della superficie Tree Tree( this, true) ; - Tree.BuildTree_test() ; - //Tree.BuildTree( 0.05, 1) ; + //Tree.BuildTree_test() ; + Tree.BuildTree( 0.05, 1) ; + //Tree.BuildTree( 0.2, 5) ; //Tree.BuildTree( 0.5, 10) ; //Tree.BuildTree( 1, 25) ; vector vvPL ; @@ -1547,8 +1548,9 @@ bool SurfBezier::GetLeaves( std::vector>& vLeaves) const { Tree Tree( this, true) ; - Tree.BuildTree_test() ; - //Tree.BuildTree( 0.05, 1) ; + //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 ; diff --git a/Tree.cpp b/Tree.cpp index a357514..c8245c4 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -1245,7 +1245,6 @@ Tree::GetPolygons( std::vector& vPolygons) { else { // vettore in cui salvo il chunk di appartenenza di ogni loop che attraversa la cella INTVECTOR vnParentChunk ; - //int nEdgeIn = -1 ; // vettore in cui salvo i loop che non appartengono al poligono che sto cotruendo nel ciclo attuale e da cui ripasserò dopo INTVECTOR vToCheck( (int) m_mTree[nId].m_vInters.size()) ; std::generate_n( vToCheck.begin(), (int) m_mTree[nId].m_vInters.size(), generator()) ; @@ -1280,7 +1279,7 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons) PNTVECTOR vVertices ; INTVECTOR vNeigh ; bool bBottomRight , bTopLeft ; - // scorro lungo tutte le celle leaves ( dell'albero bilanciato) e oltre agli angoli della cella aggiungo alla polyline anche i vertici sui lati + // scorro lungo tutte le celle leaves e oltre agli angoli della cella aggiungo alla polyline anche i vertici sui lati for ( int nId : m_vnLeaves) { vVertices.clear() ; vNeigh.clear() ; @@ -1378,32 +1377,6 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons) void Tree::ResetTree( void) { - //// setto tutti i nodi (foglie comprese) a Processed = false - //int nCToReset = -1 ; - //while ( nCToReset != -2 && m_mTree[nCToReset].IsProcessed() == true) { - // if ( m_mTree[nCToReset].IsLeaf()) { - // m_mTree[nCToReset].SetProcessed( false) ; - // - // // risalgo i parent finché non trovo il primo Child2 da deprocessare - // nCToReset = m_mTree[nCToReset].m_nParent ; - // if ( ! m_mTree[m_mTree[nCToReset].m_nChild1].IsProcessed() && ! m_mTree[m_mTree[nCToReset].m_nChild2].IsProcessed()) - // m_mTree[nCToReset].SetProcessed( false) ; - // while ( ! m_mTree[m_mTree[nCToReset].m_nChild2].IsProcessed()) { - // if ( m_mTree[nCToReset].m_nParent != -2) - // nCToReset = m_mTree[nCToReset].m_nParent ; - // if ( ! m_mTree[m_mTree[nCToReset].m_nChild1].IsProcessed() && ! m_mTree[m_mTree[nCToReset].m_nChild2].IsProcessed()) - // m_mTree[nCToReset].SetProcessed( false) ; - // if ( nCToReset == -1 && ! m_mTree[m_mTree[nCToReset].m_nChild2].IsProcessed()) - // break ; - // } - // nCToReset = m_mTree[nCToReset].m_nChild2 ; - - // } - // else { - // nCToReset = m_mTree[nCToReset].m_nChild1 ; - // } - //} - // setto tutte le foglie a Processed = false for ( int nC : m_vnLeaves ) { m_mTree[nC].SetProcessed( false) ; @@ -1414,8 +1387,6 @@ Tree::ResetTree( void) INTVECTOR Tree::FindCell( const Point3d& ptToAssign, CurveLine& clTrim) const { - // riordino le celle da sinistra a destra ( rispetto al verso della cl) - // devo ancora aggiungerla questa feature!!!//////////////////////////////////////////////////////////////////////////////////////////////////////////// INTVECTOR nCells ; int nId = -1 ; // se fallisce ritorna un vettore vuoto @@ -1425,12 +1396,6 @@ Tree::FindCell( const Point3d& ptToAssign, CurveLine& clTrim) const //nCells.push_back( - 2) ; return nCells ; } - - //// se lo spazio parametrico non è stato suddiviso ( ho un piano), restituisco la cella root - //if ( m_mTree.at(nId).IsLeaf() ) { - // nCells.push_back( nId) ; - // return nCells ; - //} // se ho diviso preliminarmente le patches e in uno dei due parametri ho un numero dispari di patches devo individuare a mano la cella parent // in cui individuare la foglia giusta @@ -1459,46 +1424,11 @@ Tree::FindCell( const Point3d& ptToAssign, CurveLine& clTrim) const } } } - //if ( nId != -1) - // nCells.push_back( nId) ; - - //if ( nId == -1) - // nId = -2 ; nCells.push_back( nId) ; - //// devo verificare se sono sul bordo di una cella: in questo caso dovrei restituire anche il vicino con cui condivido quel lato!! ///////////////////// - 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) ; - //IntCrvCrvInfo aInfo, bInfo ; - //CurveLine clEdge, clEdge2 ; - //if ( AreSamePointApprox(ptToAssign, ptTl)){ - // // lato top - // clEdge.Set( m_mTree.at(nId).GetTopRight(), ptTl) ; - // IntersLineLine illTrimEdge( clTrim, clEdge, true) ; - // illTrimEdge.GetIntCrvCrvInfo( aInfo) ; - // // lato sinistro - // clEdge2.Set( ptTl, m_mTree.at(nId).GetBottomLeft()) ; - // IntersLineLine illTrimEdge2( clTrim, clEdge2, true) ; - // illTrimEdge2.GetIntCrvCrvInfo( bInfo) ; - // if ( aInfo.bOverlap) { - // if ( aInfo.bCBOverEq ) { - - // } - // } - //} - //else if ( AreSamePointApprox( ptToAssign, m_mTree.at(nId).GetBottomLeft())) { - - //} - //else if ( AreSamePointApprox(ptToAssign, ptBr)) { - - //} - //else if (AreSamePointApprox( ptToAssign, ptTl)) { - - //} - - if ( AreSamePointApprox(ptToAssign, ptTl) || AreSamePointApprox( ptToAssign, m_mTree.at(nId).GetBottomLeft()) || AreSamePointApprox(ptToAssign, ptBr) || @@ -1545,10 +1475,6 @@ Tree::FindCell( const Point3d& ptToAssign, CurveLine& cl, INTVECTOR vCells) cons nId = nCell ; nCells.push_back( nId) ; } - //if ( bFound) - // break ; - //if ( nCells.size() > 0) - // bFound = true ; } return nCells ; } @@ -1596,15 +1522,10 @@ Tree::TraceLoopLabelCell( void) std::advance( ptSecond, 1) ; CurveLine clFirst ; clFirst.Set( ptFirst->first, ptSecond->first) ; + // individuo la cella da cui parte il loop INTVECTOR nCells = FindCell( ptStart, clFirst) ; - int nId, nFirstCell ; - if ( (int)nCells.size() == 1) { - nId = nCells[0] ; - } - else { - nId = nCells.back() ; - } - nFirstCell = nId ; + int nId = nCells.back() ; + int nFirstCell = nId ; // trovo quali punti della polyline sono nella cella e l'intersezione PNTVECTOR vptInters ; vptInters.push_back( ptStart) ; @@ -1621,7 +1542,6 @@ Tree::TraceLoopLabelCell( void) Point3d ptCurr ; INTVECTOR :: iterator iter = find( m_vnLeaves.begin(), m_vnLeaves.end(), nId) ; int nIdPolygon = std::distance( m_vnLeaves.begin(), iter) ; - bool bVertex = false ; bool bEraseNextPoint = false ; while ( plLoop.GetNextPoint( ptCurr)) { // sto uscendo dalla cella, quindi cerco l'intersezione @@ -1637,11 +1557,10 @@ Tree::TraceLoopLabelCell( void) } bLoopInside = false ; // trovo l'intersezione e passo alla cella successiva. nId viene aggiornato dalla funzione FindInters - bVertex = false ; // se non trovo l'intersezione vuol dire che non sono nella cella giusta! // al precedente FindInters avrei dovuto passare di cella - if ( ! FindInters( nId, clTrim, vptInters, bVertex)) { - // scaterò il punto molto vicino al lato e tengo solo l'intersezione del trim col lato + if ( ! FindInters( nId, clTrim, vptInters, true)) { + // scarterò il punto molto vicino al lato e tengo solo l'intersezione del trim col lato m_mTree[nId].m_vInters.back().vpt.pop_back() ; plLoop.GetPrevPoint( ptTEnd) ; plLoop.GetPrevPoint( ptTStart) ; @@ -1649,7 +1568,7 @@ Tree::TraceLoopLabelCell( void) clTrim.Set( ptTStart, ptTEnd) ; //clTrim.ExtendEndByLen( EPS_SMALL * 2) ; vptInters.clear() ; - if ( FindInters( nId, clTrim, vptInters, bVertex)) + if ( FindInters( nId, clTrim, vptInters, true)) return false ; bEraseNextPoint = true ; } @@ -1681,34 +1600,25 @@ Tree::TraceLoopLabelCell( void) // sono tornato alla cella di partenza, quindi devo fare il merge dei due vettori di intersezione che ho creato per questa cella // per lo stesso loop else { - // verifico se sono effettivamente nella cella di partenza o nella penultima cella - // devo verificare se il loop finisce in un vertice! in questo caso sono nella penultima cella! e devo fare un FindInters di nuovo per sistemare - Point3d ptLast = m_mTree[nId].m_vInters.back().vpt.back() ; // devo recuperare l'intersezione del trim con i bordi delle celle//////////////////// - //Point3d ptLast = ptCurr ; + // verifico se sono effettivamente nella cella di partenza o in una cella adiacente if ( nId != nFirstCell) { - Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; - Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; - int nLastId, nEdge ; - // qui devo tener conto anche della possibilità che il trim termini parzialmente coincidente con un lato/////////////////////////////////// - if ( AreSamePointApprox( m_mTree[nId].GetTopRight(), ptLast) || - AreSamePointApprox( ptTl, ptLast) || - AreSamePointApprox( m_mTree[nId].GetBottomLeft(), ptLast) || - AreSamePointApprox( ptBr, ptLast) || - OnWhichEdge( nId, ptLast,nEdge)) { - Point3d ptTStart, ptTEnd ; - plLoop.GetPrevPoint( ptTEnd) ; - plLoop.GetPrevPoint( ptTStart) ; - CurveLine clTrim ; - clTrim.Set( ptTStart, ptTEnd) ; - vptInters.clear() ; - nLastId = nId ; - FindInters( nId, clTrim, vptInters, bVertex) ; - if ( ! AreSamePointExact( vptInters[0], m_mTree[nLastId].m_vInters.back().vpt.back())) - m_mTree[nLastId].m_vInters.back().vpt.push_back( vptInters[0]) ; - } + Point3d ptFirst = m_mTree[nFirstCell].m_vInters[nPass].vpt[0] ; + Point3d ptLast = m_mTree[nId].m_vInters.back().vpt.back() ; + //sistemo l'ingresso della prima cella + int nEdge ; + OnWhichEdge( nFirstCell, ptFirst, nEdge) ; + m_mTree[nFirstCell].m_vInters[nPass].nIn = nEdge ; + // sistemo l'uscita dell'ultima cella + OnWhichEdge( nId, ptLast, nEdge) ; + m_mTree[nId].m_vInters.back().nOut = nEdge ; + // sistemo il flag dell'ultima cella + if ( m_mTree[nId].m_nFlag == -1) + m_mTree[nId].m_nFlag = 1 ; + else if ( m_mTree[nId].m_nFlag == 2) + m_mTree[nId].m_nFlag = 3 ; } // sono tornato nella cella iniziale, quindi giunto i due vettori intersezione - if ( nId == nFirstCell) { + else if ( nId == nFirstCell) { int nOut = m_mTree[nId].m_vInters[nPass].nOut ; m_mTree[nId].m_vInters.back().vpt.insert( m_mTree[nId].m_vInters.back().vpt.end(), m_mTree[nId].m_vInters[nPass].vpt.begin(), @@ -1718,30 +1628,6 @@ Tree::TraceLoopLabelCell( void) // sistemo il lato d'uscita m_mTree[nId].m_vInters[nPass].nOut = nOut ; } - // se non sono tornato alla cella di partenza - else { - m_mTree[nId].m_vInters.pop_back() ; - if ( (int)m_mTree[nId].m_vInters.size() == 0) - m_mTree[nId].m_nFlag = 0 ; - // aggiusto nIn della cella di partenza ( in questo caso dovrei aver avuto un ingresso direttamente in un vertice) - Point3d ptFirst = m_mTree[nFirstCell].m_vInters[nPass].vpt[0] ; - Point3d ptTl( m_mTree[nFirstCell].GetBottomLeft().x, m_mTree[nFirstCell].GetTopRight().y) ; - Point3d ptBr( m_mTree[nFirstCell].GetTopRight().x, m_mTree[nFirstCell].GetBottomLeft().y) ; - if ( AreSamePointApprox( m_mTree[nFirstCell].GetTopRight(), ptFirst)) - m_mTree[nFirstCell].m_vInters[nPass].nIn = 7 ; - else if (AreSamePointApprox( ptTl, ptFirst)) - m_mTree[nFirstCell].m_vInters[nPass].nIn = 4 ; - else if (AreSamePointApprox( m_mTree[nFirstCell].GetBottomLeft(), ptFirst)) - m_mTree[nFirstCell].m_vInters[nPass].nIn = 5 ; - else if (AreSamePointApprox( ptBr, ptFirst)) - m_mTree[nFirstCell].m_vInters[nPass].nIn = 6 ; - // sono su un lato e non su un vertice - else { - int nEdge ; - OnWhichEdge( nFirstCell, ptFirst, nEdge) ; - m_mTree[nFirstCell].m_vInters[nPass].nIn = nEdge ; - } - } } } @@ -1791,7 +1677,7 @@ 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) ; } @@ -1845,7 +1731,7 @@ Tree::TraceLoopLabelCell( void) } } if ( nCell == nLastLeft && m_mTree[nCell].IsProcessed() ) { - // categorizzo//////////////////////////////////////////////////////////////////////////// + // categorizzo m_mTree[nCell].m_nFlag2 = 1 ; CategorizeCell( nCell) ; bAllDone = true ; @@ -1876,20 +1762,6 @@ Tree::TraceLoopLabelCell( void) } vNeigh.clear() ; GetRightNeigh( nCell, vNeigh) ; - - //// se sono all'ultimo elemento di vFirst controllo se ho processato tutti i suoi vicini di destra - //if ( nCell == nLastLeft){ - // vNeigh.clear() ; - // GetRightNeigh( nCell, vNeigh) ; - // bAllDone = true ; - // for( int j = 0 ; j < (int) vNeigh.size(); ++ j) { - // if ( ! m_mTree[vNeigh[j]].IsProcessed() ) { - // bAllDone = false ; - // break ; - // } - // } - //} - } return true ; @@ -1897,7 +1769,7 @@ Tree::TraceLoopLabelCell( void) //---------------------------------------------------------------------------- bool -Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVertex) +Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool bFirstInters) { CurveLine clEdge , clEdge2 ; Point3d ptStart , ptEnd ; @@ -1917,12 +1789,10 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert nEdge = 0 ; // lato sopra clEdge.Set( ptTR, ptTl) ; - //if ( ptEnd.x >= ptBL.x) - // ;// lato sinistro - //else //if ( ptEnd.x < ptBL.x) + // lato sinistro if ( ptEnd.x < ptBL.x) clEdge2.Set( ptTl, ptBL) ; - else if ( AreSamePointExact( ptEnd, ptTl)) { + else if ( AreSamePointExact( ptEnd, ptTl) && bFirstInters) { nEdge = 4 ; ptInters = ptTl ; bIntersFound = true ; @@ -1932,13 +1802,10 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert nEdge = 1 ; // lato sinistro clEdge.Set( ptTl, ptBL) ; - //if ( ptEnd.y >= ptBL.y) - // ; - //// lato sotto - //else //if ( ptEnd.y < ptBL.y) + // lato sotto if ( ptEnd.y < ptBL.y) clEdge2.Set( ptBL, ptBr) ; - else if ( AreSamePointExact( ptEnd, ptBL)) { + else if ( AreSamePointExact( ptEnd, ptBL) && bFirstInters) { nEdge = 5 ; ptInters = ptBL ; bIntersFound = true ; @@ -1948,13 +1815,10 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert nEdge = 2 ; // lato sotto clEdge.Set( ptBL, ptBr) ; - //if ( ptEnd.x <= ptTR.x) - // ; - //// lato destro - //else //if ( ptEnd.x > ptTR.x) + // lato destro if ( ptEnd.x > ptTR.x) clEdge2.Set( ptBr, ptTR) ; - else if ( AreSamePointExact( ptEnd, ptBr)) { + else if ( AreSamePointExact( ptEnd, ptBr) && bFirstInters) { nEdge = 6 ; ptInters = ptBr ; bIntersFound = true ; @@ -1964,13 +1828,10 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert nEdge = 3 ; // lato desto clEdge.Set( ptBr, ptTR) ; - //if ( ptEnd.y <= ptTR.y) - // ; - //// lato sopra - //else //if ( ptEnd.y > ptTR.y) + // lato sopra if ( ptEnd.y > ptTR.y) clEdge2.Set( ptTR, ptTl) ; - else if ( AreSamePointExact( ptEnd, ptTR)) { + else if ( AreSamePointExact( ptEnd, ptTR) && bFirstInters) { nEdge = 7 ; ptInters = ptTR ; bIntersFound = true ; @@ -1979,59 +1840,47 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert else return false ; + if ( ! bIntersFound) { // intersezione e controlli IntersLineLine illExit( clTrim, clEdge, true) ; IntCrvCrvInfo aInfo, aInfo2 ; bool bIntersOn1Found = true ; - if ( ! illExit.GetIntCrvCrvInfo( aInfo) && ! clEdge2.IsValid()) { + if ( ! illExit.GetIntCrvCrvInfo( aInfo)) { bIntersOn1Found = false ; - return false ; + if ( ! clEdge2.IsValid()) + return false ; } - if ( clEdge2.IsValid()){ + else if ( aInfo.bOverlap && ! bFirstInters) { + ptInters = aInfo.IciA[1].ptI ; + bIntersFound = true ; + } + if ( clEdge2.IsValid() && ! bIntersFound){ IntersLineLine illExit2( clTrim, clEdge2, true) ; - //if ( ! illExit2.GetIntCrvCrvInfo( aInfo2) ) - // return false ; // verifico su quale dei due lati ho l'intersezione - if ( ! illExit2.GetIntCrvCrvInfo( aInfo2)) - if ( bIntersOn1Found) - ptInters = aInfo.IciA[0].ptI ; + if ( ! illExit2.GetIntCrvCrvInfo( aInfo2)){ + if ( bIntersOn1Found) { + // se ho intersezione su Edge1 con sovrapposizione, seleziono o il primo punto o il secondo. + if ( aInfo.bOverlap && ! bFirstInters) + ptInters = aInfo.IciA[1].ptI ; + else + ptInters = aInfo.IciA[0].ptI ; + } else return false ; + } else { - // solo intersezione sul lato 2 - if ( illExit.GetNumInters() == 0 ) { + //// solo intersezione sul lato 2 + if ( aInfo2.bOverlap && ! bFirstInters) + ptInters = aInfo2.IciA[1].ptI ; + else ptInters = aInfo2.IciA[0].ptI ; - if ( nEdge > 3 && nEdge != 7) - nEdge = nEdge - 4 ; - else if ( nEdge < 3 ) - ++ nEdge ; - else - nEdge = 0 ; - } - // intersezione sul vertice della cella - else { - ptInters = aInfo2.IciA[0].ptI ; - bVertex = true ; - // la cella adiacente in diagonale a quel vertice - nEdge = nEdge + 4 ; - } } } 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 ; - } + OnWhichEdge( nId, ptInters, nEdge) ; m_mTree[nId].m_vInters.back().nOut = nEdge ; if ( (int)vptInters.size() == 0) vptInters.push_back( ptInters) ; @@ -2366,7 +2215,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I // comincio a costruire il poligono INTVECTOR vToCheckNow = vToCheck ; - vToCheck.clear() ; + //vToCheck.clear() ; // vettore dei poligoni ( loop) della cella nId POLYLINEVECTOR vCellPolygons ; // costruisco i poligoni partendo dal vettore delle intersezioni, come spiegato a pag15 di Cripps @@ -2461,7 +2310,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I bool bNotCameBack = true ; bool bValidNextStart = false ; bool bAtNextStart = false ; - if ( w < nPassToCheck - 1) { // ho messo w al posto di j //////////////////////////////////////////////////////////////////////////////////////// + if ( w < nPassToCheck - 1) { int nSecondCheck = 0 ; int nNext ; // ciclo sui loop successivi per vedere se ne ho uno con un valid start @@ -2474,7 +2323,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I } else { ++ nSecondCheck ; - vToCheck.push_back( vToCheckNow[t]) ; + //vToCheck.push_back( vToCheckNow[t]) ; } } @@ -2910,10 +2759,12 @@ Tree::AreSameEdge( int nEdge1, int nEdge2) const bool Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimmedPoly, int& c, Point3d& ptToAdd) const { - //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) ; - //Point3d ptBL = m_mTree.at(nId).GetBottomLeft() ; - //Point3d ptTR = m_mTree.at(nId).GetTopRight() ; + // se è il primo punto della PolyLine lo aggiungo + if ( plTrimmedPoly.GetPointNbr() == 0) { + plTrimmedPoly.AddUPoint( c, ptToAdd) ; + ++ c ; + return true ; + } Point3d ptBr = vEdgeVertex[3][0] ; Point3d ptTR = vEdgeVertex[0][0] ; Point3d ptTl = vEdgeVertex[1][0] ; @@ -3005,6 +2856,7 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm return true ; } +//usando i poligoni ////---------------------------------------------------------------------------- //bool //Tree::SetRightEdgeIn( int nId, std::vector& vEdgeVertex, PolyLine& plTrimmedPoly) @@ -3068,6 +2920,7 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm // return true ; //} +//usando le intersezioni con le celle //---------------------------------------------------------------------------- bool Tree::SetRightEdgeIn( int nId) @@ -3093,7 +2946,7 @@ Tree::SetRightEdgeIn( int nId) for( int c = 0 ; c < nInters ; ++ c){ inB = m_mTree[nId].m_vInters[c] ; if ( inB.nIn == -1) { - if ( inB != inA && inB.nChunk == inA.nChunk) { + if ( inB != inA && inB.nChunk == inA.nChunk && inB.bCCW) { bContained = true ; break ; } @@ -3124,21 +2977,16 @@ Tree::SetRightEdgeIn( int nId) } // considero anche ingressi/ uscite dai vertici 6 e 7 // controllo nei vertici - if ( m_mTree[nId].m_vInters[k].nOut == 6 && m_mTree[nId].m_vInters[k].nIn == 7) { + else 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 ) { + else 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) { @@ -3434,14 +3282,22 @@ Tree::OnWhichEdge( int nId, Point3d& ptToAssign, int& nEdge) const Point3d ptTl ( ptBL.x, ptTR.y) ; Point3d ptBr ( ptTR.x, ptBL.y) ; - if ( ptToAssign.x >= ptBL.x && ptToAssign.x <= ptTR.x && abs( ptToAssign.y - ptTR.y) < EPS_SMALL) + if ( ptToAssign.x > ptBL.x && ptToAssign.x < ptTR.x && abs( ptToAssign.y - ptTR.y) < EPS_SMALL) nEdge = 0 ; - else if ( ptToAssign.y >= ptBL.y && ptToAssign.y <= ptTR.y && abs( ptToAssign.x - ptBL.x) < EPS_SMALL) + else if ( ptToAssign.y > ptBL.y && ptToAssign.y < ptTR.y && abs( ptToAssign.x - ptBL.x) < EPS_SMALL) nEdge = 1 ; - else if ( ptToAssign.x >= ptBL.x && ptToAssign.x <= ptTR.x && abs( ptToAssign.y - ptBL.y) < EPS_SMALL) + else if ( ptToAssign.x > ptBL.x && ptToAssign.x < ptTR.x && abs( ptToAssign.y - ptBL.y) < EPS_SMALL) nEdge = 2 ; - else if ( ptToAssign.y >= ptBL.y && ptToAssign.y <= ptTR.y && abs( ptToAssign.x - ptTR.x) < EPS_SMALL) + else if ( ptToAssign.y > ptBL.y && ptToAssign.y < ptTR.y && abs( ptToAssign.x - ptTR.x) < EPS_SMALL) nEdge = 3 ; + if ( AreSamePointApprox( ptToAssign, ptTR)) + nEdge = 7 ; + else if ( AreSamePointApprox( ptToAssign, ptTl)) + nEdge = 4 ; + else if ( AreSamePointApprox( ptToAssign, ptBL)) + nEdge = 5 ; + else if ( AreSamePointApprox( ptToAssign, ptBr)) + nEdge = 6 ; else return false ; return true ; diff --git a/Tree.h b/Tree.h index 62a3830..cbe70a6 100644 --- a/Tree.h +++ b/Tree.h @@ -141,7 +141,7 @@ private : INTVECTOR FindCell ( const Point3d& ptToAssign, CurveLine& cl) const ; // dato un punto, trova la cella foglia a cui appartiene INTVECTOR FindCell ( const Point3d& ptToAssign, CurveLine& cl, INTVECTOR vCells) const ; // dato un punto, trova la cella foglia a cui appartiene bool TraceLoopLabelCell( void) ; // tracing dei loop e labelling delle celle - bool FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVertex) ; // trova le intersezioni tra una cella e una linea di trim + bool FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool bFirstInters = true) ; // trova le intersezioni tra una cella e una linea di trim // resituisce l'id della cella verso cui la curva di trim esce e il vettore delle intersezioni per la cella successiva con il primo punto bool CreateCellPolygons ( int nLeafId, std::vector& vPolygons, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk, PolyLine plCell) ; bool CreateIslandAndHoles ( int nLeafId, std::vector& vPolygons, int& nPoly, INTVECTOR& vnParentChunk) ; From 06a69fa66bcb434ccfa6597fd4c225af5912476d Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Thu, 15 Jun 2023 15:28:04 +0200 Subject: [PATCH 18/44] EgtGeomKernel : - pulizia del codice Problemi : - bug dovuto a problemi numerici sulle intersezione tra trim e celle --- Tree.cpp | 847 ++++++++++++++++++++++++------------------------------- Tree.h | 74 +++-- 2 files changed, 408 insertions(+), 513 deletions(-) diff --git a/Tree.cpp b/Tree.cpp index c8245c4..c4022ed 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -28,7 +28,7 @@ //---------------------------------------------------------------------------- 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_ptPbl( ORIG), m_ptPtr(), m_bProcessed( false), m_bSplitVert( true) { Point3d ptTr ( 1 * SBZ_TREG_COEFF, 1 * SBZ_TREG_COEFF) ; m_ptPtr = ptTr ; @@ -36,9 +36,9 @@ Cell::Cell( void) //---------------------------------------------------------------------------- -Cell::Cell( Point3d& ptBL, Point3d& ptTR) +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_ptPbl( ptBL), m_ptPtr( ptTR), m_bProcessed( false), m_bSplitVert( true) {} @@ -77,7 +77,7 @@ Tree::Tree( void) } //---------------------------------------------------------------------------- -Tree::Tree( const SurfBezier* pSrfBz, bool bSplitPatches) +Tree::Tree( const SurfBezier* pSrfBz, const bool bSplitPatches) : m_bBilinear( false), m_bMulti( false), m_bClosed( false), m_bSplitPatches( bSplitPatches) { SetSurf( pSrfBz, m_bSplitPatches) ; @@ -90,7 +90,7 @@ Tree::~Tree( void) //---------------------------------------------------------------------------- void -Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) +Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches) { m_pSrfBz = pSrfBz ; m_bSplitPatches = bSplitPatches ; @@ -111,45 +111,17 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) if ( m_bTrimmed) { int nLoop = 0 ; INTVECTOR vChunk ; - // dalla superficie recupero un vettore con i loop di trim - // - //PtrOwner pLoop( GetBasicCurveComposite( m_pSrfBz->GetLoop( nLoop))) ; - //while ( ! IsNull( pLoop) && pLoop->IsValid()) { - // if ( nLoop == 0) { - // m_vLoop.push_back( Release( pLoop)) ; - // vChunck.push_back( nLoop) ; - // ++ nLoop ; - // } - // else { - // // se il loop corrente è contenuto nel precedente e sono girati in verso opposto, allora lo aggiungo allo stesso chunk - // if ( ) { - - // } - // // salvo il precedente chunk e creo un nuovo chunk - // else { - // m_vChunk.push_back( vChunk) ; - // vChunk.clear() ; - // vChunk.push_back( nLoop) ; - // } - // ++ nLoop ; - // PtrOwner pLoop( GetBasicCurveComposite( m_pSrfBz->GetLoop( nLoop))) ; - // } - //} // recupero la superficie di trim per avere accesso diretto ai loop e mantenendo le informazioni sui chunk - Frame3d frSurf ; - //const SurfFlatRegion* pTrimReg_( m_pSrfBz->GetTrimRegion()) ; - //PtrOwner pTrimReg( pTrimReg_->Clone()) ; PtrOwner pTrimReg( m_pSrfBz->GetTrimRegion()->Clone()) ; for ( int i = 0 ; i < pTrimReg->GetChunkCount() ; ++ i) { PtrOwner pChunk( pTrimReg->CloneChunk( i)) ; - //pChunk->Scale( frSurf, 1./ SBZ_TREG_COEFF, 1./ SBZ_TREG_COEFF, 1) ; for ( int j = 0 ; j < pChunk->GetLoopCount( 0) ; ++ j) { vChunk.push_back( nLoop) ; // i chunk della superficie orignale non possono avere dei sub chunk - PtrOwner pLoop (pChunk->GetLoop(0, j)) ; - m_vLoop.emplace_back( Release( pLoop )) ; + PtrOwner pLoop ( pChunk->GetLoop( 0, j)) ; + m_vLoop.emplace_back( Release( pLoop)) ; m_mChunk[nLoop] = i ; ++ nLoop ; } @@ -165,13 +137,13 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) Point3d ptP00, ptP10, ptP11, ptP01 ; bool bOk = false ; PNTVECTOR vVert ; - ptP00 = m_pSrfBz->GetControlPoint( 0, &bOk); + 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) ; + 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 @@ -186,7 +158,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) INTVECTOR vLeaves ; GetHeightLeaves( -1, vLeaves) ; for ( int nId : vLeaves) { - for ( int j = nSpanV - 1 ; j > 0 ; --j ) { + 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 ; @@ -202,11 +174,11 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) if ( ( AreSamePointApprox( ptP00, ptP01) && AreSamePointApprox( ptP10, ptP11)) || ( AreSamePointApprox( ptP00, ptP10) && AreSamePointApprox( ptP01, ptP11))) { m_bClosed = true ; - if ( AreSamePointApprox(ptP00, ptP01)) { + if ( AreSamePointApprox( ptP00, ptP01)) { m_mTree[-1].m_nTop = -1 ; m_mTree[-1].m_nBottom = -1 ; m_mTree[-1].SetSplitDirVert( false) ; - Split(-1) ; + 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 @@ -227,7 +199,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) Split( 1) ; } } - if ( AreSamePointApprox(ptP00, ptP10)) { + if ( AreSamePointApprox( ptP00, ptP10)) { if( (int) m_mTree.size() == 1) { m_mTree[-1].m_nLeft = -1 ; m_mTree[-1].m_nRight = -1 ; @@ -242,7 +214,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) 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) ; + ptU1 = m_pSrfBz->GetControlPoint( i + ( nDegU * nSpanU + 1) * ( nDegV * nSpanV), &bOk) ; bCapped1 = bCapped1 && AreSamePointApprox( ptP01, ptU1) ; } if ( bCapped0 && bCapped1) { @@ -279,7 +251,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) //---------------------------------------------------------------------------- void -Tree::Split( int nId, double dSplitValue) +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) || @@ -366,7 +338,7 @@ Tree::Split( int nId, double dSplitValue) //---------------------------------------------------------------------------- void -Tree::Split( int nId) +Tree::Split( const int& nId) { double dValue ; if ( m_mTree[nId].IsSplitVert()) @@ -453,7 +425,7 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) // ptP00P10 è un punto tra P00 e P10 double dCurvU = 0, dCurvV = 0 ; double dLenParU = ( m_mTree[nCToSplit].GetTopRight().x - m_mTree[nCToSplit].GetBottomLeft().x) / SBZ_TREG_COEFF ; - double dLenParV = ( m_mTree[nCToSplit].GetTopRight().y - m_mTree[nCToSplit].GetBottomLeft().y) / SBZ_TREG_COEFF; + double dLenParV = ( m_mTree[nCToSplit].GetTopRight().y - m_mTree[nCToSplit].GetBottomLeft().y) / SBZ_TREG_COEFF ; if ( dLenParU <= 1. / m_nDegV || dLenParV <= 1. / m_nDegU) { double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 / SBZ_TREG_COEFF ; double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 / SBZ_TREG_COEFF ; @@ -472,11 +444,11 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) // faccio un'analisi più fine della curvatura se almeno il grado di una curva di uno dei due parametri è alto e // se sto ancora guardando una cella abbastanza grande else{ - Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00, ptPSrfMid; + Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00, ptPSrfMid ; double dStep = 1. / m_nDegU ; for ( double k = dStep ; k < 1 ; k = k + dStep) { double dU = ( k * m_mTree[nCToSplit].GetTopRight().x + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().x) / SBZ_TREG_COEFF ; - double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 / SBZ_TREG_COEFF; + double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 / SBZ_TREG_COEFF ; m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; if ( k == 0.5) ptPSrfMid = ptPSrf ; @@ -568,7 +540,7 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) int nStepsV = int( 51 * dDimV + 5 * ( 1 - dDimV)) ; for ( int u = 0 ; u < nStepsU && ! bSplit ; ++ u) { double dU = double ( u) / double ( nStepsU - 1) ; - double dULoc = (( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x) / SBZ_TREG_COEFF ; + double dULoc = ( ( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x) / SBZ_TREG_COEFF ; 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 ; @@ -652,7 +624,7 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) double dDistU = 0, dDistV = 0 ; PNTVECTOR vPtU, vPtV ; if ( ! m_bMulti) { - if ( std::max(dLen0, dLen2) > std::max(dLen1, dLen3)) { + if ( std::max( dLen0, dLen2) > std::max( dLen1, dLen3)) { bVert = true ; } else { @@ -660,9 +632,9 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) } } else { - for ( double i = 0.25 ; i < 1 ; i = i + 0.25 ) { - dU = (( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().x + i * m_mTree[nCToSplit].GetTopRight().x) / SBZ_TREG_COEFF ; - dV = (( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().y + i * m_mTree[nCToSplit].GetTopRight().y) / SBZ_TREG_COEFF ; + for ( double i = 0.25 ; i < 1 ; i = i + 0.25) { + dU = ( ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().x + i * m_mTree[nCToSplit].GetTopRight().x) / SBZ_TREG_COEFF ; + dV = ( ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().y + i * m_mTree[nCToSplit].GetTopRight().y) / SBZ_TREG_COEFF ; double dVLoc = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 / SBZ_TREG_COEFF ; double dULoc = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 / SBZ_TREG_COEFF ; m_pSrfBz->GetPointD1D2( dU, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfU) ; @@ -671,9 +643,9 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) vPtV.push_back( ptPSrfV) ; } // devo guardare se i tre punti in vPtU e vPtV sono allineati - CurveLine clU, clV; - clU.Set(vPtU[0], vPtU[1]) ; - clV.Set(vPtV[0], vPtV[1]) ; + CurveLine clU, clV ; + clU.Set( vPtU[0], vPtU[1]) ; + clV.Set( vPtV[0], vPtV[1]) ; DistPointCurve dpcU( vPtU[2], clU, false) ; DistPointCurve dpcV( vPtV[2], clV, false) ; dpcU.GetDist( dDistU) ; @@ -726,7 +698,7 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) } } else { - dErr = 1. / 4. * ( (ptP00 - ptP01) + (ptP11 - ptP10)).Len() ; + dErr = 1. / 4. * ( ( ptP00 - ptP01) + ( ptP11 - ptP10)).Len() ; } // se la cella è abbastanza grande da poter essere divisa ancora e devo approssimare meglio, la divido if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && dErr > dLinTol) { @@ -776,7 +748,7 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) void Tree::Balance() { - //for ( int i : vCheck ) { + //for ( int i : vCheck) { // // non ancora implementato // // rendo il tree balanced : ogni foglia deve avere una profondità di +- 1 rispetto alle foglie adiacenti. //} @@ -787,77 +759,77 @@ Tree::Balance() //---------------------------------------------------------------------------- void -Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) const +Tree::GetTopNeigh( const int& nId, INTVECTOR& vTopNeighs) const { if ( (int) vTopNeighs.size() == 0) { - if ( m_mTree.at(nId).m_nTop == -2) + if ( m_mTree.at( nId).m_nTop == -2) return ; - if ( m_mTree.at(m_mTree.at(nId).m_nTop).IsLeaf()) - vTopNeighs.push_back( m_mTree.at(nId).m_nTop) ; + if ( m_mTree.at( m_mTree.at( nId).m_nTop).IsLeaf()) + vTopNeighs.push_back( m_mTree.at( nId).m_nTop) ; else { - if ( m_mTree.at(m_mTree.at(nId).m_nTop).IsSplitVert()) { + if ( m_mTree.at( m_mTree.at( nId).m_nTop).IsSplitVert()) { // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima - if ( m_mTree.at(m_mTree.at(nId).m_nTop).GetTopRight().x - m_mTree.at(m_mTree.at(nId).m_nTop).GetBottomLeft().x <= - m_mTree.at(nId).GetTopRight().x - m_mTree.at(nId).GetBottomLeft().x) { - vTopNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild1) ; - vTopNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild2) ; + if ( m_mTree.at( m_mTree.at( nId).m_nTop).GetTopRight().x - m_mTree.at( m_mTree.at( nId).m_nTop).GetBottomLeft().x <= + m_mTree.at( nId).GetTopRight().x - m_mTree.at( nId).GetBottomLeft().x) { + vTopNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nTop).m_nChild1) ; + vTopNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nTop).m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else{ - if ( m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild1).GetTopRight().x <= m_mTree.at(nId).GetBottomLeft().x || - m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild1).GetBottomLeft().x >= m_mTree.at(nId).GetTopRight().x ) - vTopNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild2) ; + if ( m_mTree.at( m_mTree.at( m_mTree.at( nId).m_nTop).m_nChild1).GetTopRight().x <= m_mTree.at( nId).GetBottomLeft().x || + m_mTree.at( m_mTree.at( m_mTree.at( nId).m_nTop).m_nChild1).GetBottomLeft().x >= m_mTree.at( nId).GetTopRight().x ) + vTopNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nTop).m_nChild2) ; else - vTopNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild1) ; + vTopNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nTop).m_nChild1) ; } } else { - vTopNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild2) ; + vTopNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nTop).m_nChild2) ; } } bool bAllLeaves = true ; - for ( int i : vTopNeighs ) { - if ( ! m_mTree.at(i).IsLeaf()) + for ( int i : vTopNeighs) { + if ( ! m_mTree.at( i).IsLeaf()) bAllLeaves = false ; } - if ( ! bAllLeaves ) + if ( ! bAllLeaves) // almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child GetTopNeigh( nId, vTopNeighs) ; } else { for ( int j = 0 ; j != (int) vTopNeighs.size() ; ++ j) { - int i = vTopNeighs.at(j) ; - if ( m_mTree.at(i).IsLeaf()) - continue; + int i = vTopNeighs.at( j) ; + if ( m_mTree.at( i).IsLeaf()) + continue ; else { // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child vTopNeighs.erase( remove( vTopNeighs.begin(),vTopNeighs.end(),i)) ; -- j ; - if ( m_mTree.at(i).IsSplitVert() ) { + if ( m_mTree.at( i).IsSplitVert()) { // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima - if ( m_mTree.at(i).GetTopRight().x - m_mTree.at(i).GetBottomLeft().x <= - m_mTree.at(nId).GetTopRight().x - m_mTree.at(nId).GetBottomLeft().x) { - vTopNeighs.push_back( m_mTree.at(i).m_nChild1) ; - vTopNeighs.push_back( m_mTree.at(i).m_nChild2) ; + if ( m_mTree.at( i).GetTopRight().x - m_mTree.at( i).GetBottomLeft().x <= + m_mTree.at( nId).GetTopRight().x - m_mTree.at( nId).GetBottomLeft().x) { + vTopNeighs.push_back( m_mTree.at( i).m_nChild1) ; + vTopNeighs.push_back( m_mTree.at( i).m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else { - if ( m_mTree.at(m_mTree.at(i).m_nChild1).GetTopRight().x <= m_mTree.at(nId).GetBottomLeft().x || - m_mTree.at(m_mTree.at(i).m_nChild1).GetBottomLeft().x >= m_mTree.at(nId).GetTopRight().x ) - vTopNeighs.push_back( m_mTree.at(i).m_nChild2) ; + if ( m_mTree.at( m_mTree.at( i).m_nChild1).GetTopRight().x <= m_mTree.at( nId).GetBottomLeft().x || + m_mTree.at( m_mTree.at( i).m_nChild1).GetBottomLeft().x >= m_mTree.at( nId).GetTopRight().x ) + vTopNeighs.push_back( m_mTree.at( i).m_nChild2) ; else - vTopNeighs.push_back( m_mTree.at(i).m_nChild1) ; + vTopNeighs.push_back( m_mTree.at( i).m_nChild1) ; } } else { - vTopNeighs.push_back( m_mTree.at(i).m_nChild2) ; + vTopNeighs.push_back( m_mTree.at( i).m_nChild2) ; } } } } std::vector vCells ; for ( int k : vTopNeighs) - vCells.push_back( m_mTree.at(k)) ; + vCells.push_back( m_mTree.at( k)) ; std::sort( vCells.begin(), vCells.end(), Cell::minorX) ; vTopNeighs.clear() ; for ( Cell c : vCells) @@ -867,77 +839,77 @@ Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) const //---------------------------------------------------------------------------- void -Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) const +Tree::GetBottomNeigh( const int& nId, INTVECTOR& vBottomNeighs) const { if ( (int) vBottomNeighs.size() == 0) { - if ( m_mTree.at(nId).m_nBottom == -2) + if ( m_mTree.at( nId).m_nBottom == -2) return ; - if ( m_mTree.at(m_mTree.at(nId).m_nBottom).IsLeaf()) - vBottomNeighs.push_back( m_mTree.at(nId).m_nBottom) ; + if ( m_mTree.at( m_mTree.at( nId).m_nBottom).IsLeaf()) + vBottomNeighs.push_back( m_mTree.at( nId).m_nBottom) ; else { - if ( m_mTree.at(m_mTree.at(nId).m_nBottom).IsSplitVert()) { + if ( m_mTree.at( m_mTree.at( nId).m_nBottom).IsSplitVert()) { // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima - if ( m_mTree.at(m_mTree.at(nId).m_nBottom).GetTopRight().x - m_mTree.at(m_mTree.at(nId).m_nBottom).GetBottomLeft().x <= - m_mTree.at(nId).GetTopRight().x - m_mTree.at(nId).GetBottomLeft().x) { - vBottomNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild1) ; - vBottomNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild2) ; + if ( m_mTree.at( m_mTree.at( nId).m_nBottom).GetTopRight().x - m_mTree.at( m_mTree.at( nId).m_nBottom).GetBottomLeft().x <= + m_mTree.at( nId).GetTopRight().x - m_mTree.at( nId).GetBottomLeft().x) { + vBottomNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nBottom).m_nChild1) ; + vBottomNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nBottom).m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else{ - if ( m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild1).GetTopRight().x <= m_mTree.at(nId).GetBottomLeft().x || - m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild1).GetBottomLeft().x >= m_mTree.at(nId).GetTopRight().x ) - vBottomNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild2) ; + if ( m_mTree.at( m_mTree.at( m_mTree.at( nId).m_nBottom).m_nChild1).GetTopRight().x <= m_mTree.at( nId).GetBottomLeft().x || + m_mTree.at( m_mTree.at( m_mTree.at( nId).m_nBottom).m_nChild1).GetBottomLeft().x >= m_mTree.at( nId).GetTopRight().x ) + vBottomNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nBottom).m_nChild2) ; else - vBottomNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild1) ; + vBottomNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nBottom).m_nChild1) ; } } else { - vBottomNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild1) ; + vBottomNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nBottom).m_nChild1) ; } } bool bAllLeaves = true ; for ( int i : vBottomNeighs) { - if ( ! m_mTree.at(i).IsLeaf()) + if ( ! m_mTree.at( i).IsLeaf()) bAllLeaves = false ; } - if ( ! bAllLeaves ) + if ( ! bAllLeaves) // almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child GetBottomNeigh( nId, vBottomNeighs) ; } else { for ( int j = 0 ; j != (int) vBottomNeighs.size() ; ++ j) { - int i = vBottomNeighs.at(j) ; - if ( m_mTree.at(i).IsLeaf()) - continue; + int i = vBottomNeighs.at( j) ; + if ( m_mTree.at( i).IsLeaf()) + continue ; else { // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child vBottomNeighs.erase( remove( vBottomNeighs.begin(),vBottomNeighs.end(),i)) ; -- j ; - if ( m_mTree.at(i).IsSplitVert()) { + if ( m_mTree.at( i).IsSplitVert()) { // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima - if ( m_mTree.at(i).GetTopRight().x - m_mTree.at(i).GetBottomLeft().x <= - m_mTree.at(nId).GetTopRight().x - m_mTree.at(nId).GetBottomLeft().x) { - vBottomNeighs.push_back( m_mTree.at(i).m_nChild1) ; - vBottomNeighs.push_back( m_mTree.at(i).m_nChild2) ; + if ( m_mTree.at( i).GetTopRight().x - m_mTree.at( i).GetBottomLeft().x <= + m_mTree.at( nId).GetTopRight().x - m_mTree.at( nId).GetBottomLeft().x) { + vBottomNeighs.push_back( m_mTree.at( i).m_nChild1) ; + vBottomNeighs.push_back( m_mTree.at( i).m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else { - if ( m_mTree.at(m_mTree.at(i).m_nChild1).GetTopRight().x <= m_mTree.at(nId).GetBottomLeft().x || - m_mTree.at(m_mTree.at(i).m_nChild1).GetBottomLeft().x >= m_mTree.at(nId).GetTopRight().x) - vBottomNeighs.push_back( m_mTree.at(i).m_nChild2) ; + if ( m_mTree.at( m_mTree.at( i).m_nChild1).GetTopRight().x <= m_mTree.at( nId).GetBottomLeft().x || + m_mTree.at( m_mTree.at( i).m_nChild1).GetBottomLeft().x >= m_mTree.at( nId).GetTopRight().x) + vBottomNeighs.push_back( m_mTree.at( i).m_nChild2) ; else - vBottomNeighs.push_back( m_mTree.at(i).m_nChild1) ; + vBottomNeighs.push_back( m_mTree.at( i).m_nChild1) ; } } else { - vBottomNeighs.push_back( m_mTree.at(i).m_nChild1) ; + vBottomNeighs.push_back( m_mTree.at( i).m_nChild1) ; } } } } std::vector vCells ; for ( int k : vBottomNeighs) - vCells.push_back( m_mTree.at(k)) ; + vCells.push_back( m_mTree.at( k)) ; std::sort( vCells.begin(), vCells.end(), Cell::minorX) ; vBottomNeighs.clear() ; for ( Cell c : vCells) @@ -947,77 +919,77 @@ Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) const //---------------------------------------------------------------------------- void -Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) const +Tree::GetLeftNeigh( const int& nId, INTVECTOR& vLeftNeighs) const { if ( (int) vLeftNeighs.size() == 0) { - if ( m_mTree.at(nId).m_nLeft == -2) + if ( m_mTree.at( nId).m_nLeft == -2) return ; - if ( m_mTree.at(m_mTree.at(nId).m_nLeft).IsLeaf()) - vLeftNeighs.push_back( m_mTree.at(nId).m_nLeft) ; + if ( m_mTree.at( m_mTree.at( nId).m_nLeft).IsLeaf()) + vLeftNeighs.push_back( m_mTree.at( nId).m_nLeft) ; else { - if ( ! m_mTree.at(m_mTree.at(nId).m_nLeft).IsSplitVert()) { + if ( ! m_mTree.at( m_mTree.at( nId).m_nLeft).IsSplitVert()) { // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima - if ( m_mTree.at(m_mTree.at(nId).m_nLeft).GetTopRight().y - m_mTree.at(m_mTree.at(nId).m_nLeft).GetBottomLeft().y <= - m_mTree.at(nId).GetTopRight().y - m_mTree.at(nId).GetBottomLeft().y) { - vLeftNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild1) ; - vLeftNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild2) ; + if ( m_mTree.at( m_mTree.at( nId).m_nLeft).GetTopRight().y - m_mTree.at( m_mTree.at( nId).m_nLeft).GetBottomLeft().y <= + m_mTree.at( nId).GetTopRight().y - m_mTree.at( nId).GetBottomLeft().y) { + vLeftNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nLeft).m_nChild1) ; + vLeftNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nLeft).m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else{ - if ( m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild1).GetTopRight().y <= m_mTree.at(nId).GetBottomLeft().y || - m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild1).GetBottomLeft().y >= m_mTree.at(nId).GetTopRight().y) - vLeftNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild2) ; + if ( m_mTree.at( m_mTree.at( m_mTree.at( nId).m_nLeft).m_nChild1).GetTopRight().y <= m_mTree.at( nId).GetBottomLeft().y || + m_mTree.at( m_mTree.at( m_mTree.at( nId).m_nLeft).m_nChild1).GetBottomLeft().y >= m_mTree.at( nId).GetTopRight().y) + vLeftNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nLeft).m_nChild2) ; else - vLeftNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild1) ; + vLeftNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nLeft).m_nChild1) ; } } else { - vLeftNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild2) ; + vLeftNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nLeft).m_nChild2) ; } } bool bAllLeaves = true ; for ( int i : vLeftNeighs) { - if ( ! m_mTree.at(i).IsLeaf()) + if ( ! m_mTree.at( i).IsLeaf()) bAllLeaves = false ; } - if ( ! bAllLeaves ) + if ( ! bAllLeaves) // almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child GetLeftNeigh( nId, vLeftNeighs) ; } else { for ( int j = 0 ; j != (int) vLeftNeighs.size() ; ++ j) { - int i = vLeftNeighs.at(j) ; - if ( m_mTree.at(i).IsLeaf()) - continue; + int i = vLeftNeighs.at( j) ; + if ( m_mTree.at( i).IsLeaf()) + continue ; else { // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child vLeftNeighs.erase( remove( vLeftNeighs.begin(),vLeftNeighs.end(),i)) ; -- j ; - if ( ! m_mTree.at(i).IsSplitVert()) { + if ( ! m_mTree.at( i).IsSplitVert()) { // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima - if ( m_mTree.at(i).GetTopRight().y - m_mTree.at(i).GetBottomLeft().y <= - m_mTree.at(nId).GetTopRight().y - m_mTree.at(nId).GetBottomLeft().y) { - vLeftNeighs.push_back( m_mTree.at(i).m_nChild1) ; - vLeftNeighs.push_back( m_mTree.at(i).m_nChild2) ; + if ( m_mTree.at( i).GetTopRight().y - m_mTree.at( i).GetBottomLeft().y <= + m_mTree.at( nId).GetTopRight().y - m_mTree.at( nId).GetBottomLeft().y) { + vLeftNeighs.push_back( m_mTree.at( i).m_nChild1) ; + vLeftNeighs.push_back( m_mTree.at( i).m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else { - if ( m_mTree.at(m_mTree.at(i).m_nChild1).GetTopRight().y <= m_mTree.at(nId).GetBottomLeft().y || - m_mTree.at(m_mTree.at(i).m_nChild1).GetBottomLeft().y >= m_mTree.at(nId).GetTopRight().y) - vLeftNeighs.push_back( m_mTree.at(i).m_nChild2) ; + if ( m_mTree.at( m_mTree.at( i).m_nChild1).GetTopRight().y <= m_mTree.at( nId).GetBottomLeft().y || + m_mTree.at( m_mTree.at( i).m_nChild1).GetBottomLeft().y >= m_mTree.at( nId).GetTopRight().y) + vLeftNeighs.push_back( m_mTree.at( i).m_nChild2) ; else - vLeftNeighs.push_back( m_mTree.at(i).m_nChild1) ; + vLeftNeighs.push_back( m_mTree.at( i).m_nChild1) ; } } else { - vLeftNeighs.push_back( m_mTree.at(i).m_nChild2) ; + vLeftNeighs.push_back( m_mTree.at( i).m_nChild2) ; } } } } std::vector vCells ; for ( int k : vLeftNeighs) - vCells.push_back( m_mTree.at(k)) ; + vCells.push_back( m_mTree.at( k)) ; std::sort( vCells.begin(), vCells.end(), Cell::minorY) ; vLeftNeighs.clear() ; for ( Cell c : vCells) @@ -1026,77 +998,77 @@ Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) const //---------------------------------------------------------------------------- void -Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) const +Tree::GetRightNeigh( const int& nId, INTVECTOR& vRightNeighs) const { if ( (int) vRightNeighs.size() == 0) { - if ( m_mTree.at(nId).m_nRight == -2) + if ( m_mTree.at( nId).m_nRight == -2) return ; - if ( m_mTree.at(m_mTree.at(nId).m_nRight).IsLeaf()) - vRightNeighs.push_back( m_mTree.at(nId).m_nRight) ; + if ( m_mTree.at( m_mTree.at( nId).m_nRight).IsLeaf()) + vRightNeighs.push_back( m_mTree.at( nId).m_nRight) ; else { - if ( ! m_mTree.at(m_mTree.at(nId).m_nRight).IsSplitVert()) { + if ( ! m_mTree.at( m_mTree.at( nId).m_nRight).IsSplitVert()) { // se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima - if ( m_mTree.at(m_mTree.at(nId).m_nRight).GetTopRight().y - m_mTree.at(m_mTree.at(nId).m_nRight).GetBottomLeft().y <= - m_mTree.at(nId).GetTopRight().y - m_mTree.at(nId).GetBottomLeft().y) { - vRightNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild1) ; - vRightNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild2) ; + if ( m_mTree.at( m_mTree.at( nId).m_nRight).GetTopRight().y - m_mTree.at( m_mTree.at( nId).m_nRight).GetBottomLeft().y <= + m_mTree.at( nId).GetTopRight().y - m_mTree.at( nId).GetBottomLeft().y) { + vRightNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nRight).m_nChild1) ; + vRightNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nRight).m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else{ - if ( m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild1).GetTopRight().y <= m_mTree.at(nId).GetBottomLeft().y || - m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild1).GetBottomLeft().y >= m_mTree.at(nId).GetTopRight().y) - vRightNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild2) ; + if ( m_mTree.at( m_mTree.at( m_mTree.at( nId).m_nRight).m_nChild1).GetTopRight().y <= m_mTree.at( nId).GetBottomLeft().y || + m_mTree.at( m_mTree.at( m_mTree.at( nId).m_nRight).m_nChild1).GetBottomLeft().y >= m_mTree.at( nId).GetTopRight().y) + vRightNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nRight).m_nChild2) ; else - vRightNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild1) ; + vRightNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nRight).m_nChild1) ; } } else { - vRightNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild1) ; + vRightNeighs.push_back( m_mTree.at( m_mTree.at( nId).m_nRight).m_nChild1) ; } } bool bAllLeaves = true ; for ( int i : vRightNeighs) { - if ( ! m_mTree.at(i).IsLeaf()) + if ( ! m_mTree.at( i).IsLeaf()) bAllLeaves = false ; } - if ( ! bAllLeaves ) + if ( ! bAllLeaves) // almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child GetRightNeigh( nId, vRightNeighs) ; } else { for ( int j = 0 ; j != (int) vRightNeighs.size() ; ++ j) { - int i = vRightNeighs.at(j) ; - if ( m_mTree.at(i).IsLeaf()) - continue; + int i = vRightNeighs.at( j) ; + if ( m_mTree.at( i).IsLeaf()) + continue ; else { // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child vRightNeighs.erase( remove( vRightNeighs.begin(),vRightNeighs.end(), i)) ; -- j ; - if ( ! m_mTree.at(i).IsSplitVert()) { + if ( ! m_mTree.at( i).IsSplitVert()) { // se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima - if ( m_mTree.at(i).GetTopRight().y - m_mTree.at(i).GetBottomLeft().y <= - m_mTree.at(nId).GetTopRight().y - m_mTree.at(nId).GetBottomLeft().y) { - vRightNeighs.push_back( m_mTree.at(i).m_nChild1) ; - vRightNeighs.push_back( m_mTree.at(i).m_nChild2) ; + if ( m_mTree.at( i).GetTopRight().y - m_mTree.at( i).GetBottomLeft().y <= + m_mTree.at( nId).GetTopRight().y - m_mTree.at( nId).GetBottomLeft().y) { + vRightNeighs.push_back( m_mTree.at( i).m_nChild1) ; + vRightNeighs.push_back( m_mTree.at( i).m_nChild2) ; } // altrimenti solo uno dei figli lo sarà else { - if ( m_mTree.at(m_mTree.at(i).m_nChild1).GetTopRight().y <= m_mTree.at(nId).GetBottomLeft().y || - m_mTree.at(m_mTree.at(i).m_nChild1).GetBottomLeft().y >= m_mTree.at(nId).GetTopRight().y) - vRightNeighs.push_back( m_mTree.at(i).m_nChild2) ; + if ( m_mTree.at( m_mTree.at( i).m_nChild1).GetTopRight().y <= m_mTree.at( nId).GetBottomLeft().y || + m_mTree.at( m_mTree.at( i).m_nChild1).GetBottomLeft().y >= m_mTree.at( nId).GetTopRight().y) + vRightNeighs.push_back( m_mTree.at( i).m_nChild2) ; else - vRightNeighs.push_back( m_mTree.at(i).m_nChild1) ; + vRightNeighs.push_back( m_mTree.at( i).m_nChild1) ; } } else { - vRightNeighs.push_back( m_mTree.at(i).m_nChild1) ; + vRightNeighs.push_back( m_mTree.at( i).m_nChild1) ; } } } } std::vector vCells ; for ( int k : vRightNeighs) - vCells.push_back( m_mTree.at(k)) ; + vCells.push_back( m_mTree.at( k)) ; std::sort( vCells.begin(), vCells.end(), Cell::minorY) ; vRightNeighs.clear() ; for ( Cell c : vCells) @@ -1105,41 +1077,41 @@ Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) const //---------------------------------------------------------------------------- void -Tree::GetRootNeigh( int nEdge, INTVECTOR& vNeigh) +Tree::GetRootNeigh( const int& nEdge, INTVECTOR& vNeigh) { int nId = -1 ; bool bMod = false ; - if ( nEdge == 0 ) { - if ( m_mTree[nId].m_nBottom == -2 ) { + if ( nEdge == 0) { + if ( m_mTree[nId].m_nBottom == -2) { m_mTree[nId].m_nBottom = -1 ; - bMod = true; + bMod = true ; } GetBottomNeigh( nId, vNeigh) ; if ( bMod) m_mTree[nId].m_nBottom = -2 ; } - else if ( nEdge == 1 ) { - if ( m_mTree[nId].m_nRight == -2 ) { + else if ( nEdge == 1) { + if ( m_mTree[nId].m_nRight == -2) { m_mTree[nId].m_nRight = -1 ; - bMod = true; + bMod = true ; } GetRightNeigh( nId, vNeigh) ; if ( bMod) m_mTree[nId].m_nRight = -2 ; } - else if ( nEdge == 2 ) { - if ( m_mTree[nId].m_nTop == -2 ) { + else if ( nEdge == 2) { + if ( m_mTree[nId].m_nTop == -2) { m_mTree[nId].m_nTop = -1 ; - bMod = true; + bMod = true ; } GetTopNeigh( nId, vNeigh) ; if ( bMod) m_mTree[nId].m_nTop = -2 ; } - else if ( nEdge == 3 ) { - if ( m_mTree[nId].m_nLeft == -2 ) { + else if ( nEdge == 3) { + if ( m_mTree[nId].m_nLeft == -2) { m_mTree[nId].m_nLeft = -1 ; - bMod = true; + bMod = true ; } GetLeftNeigh( nId, vNeigh) ; if ( bMod) @@ -1149,52 +1121,53 @@ Tree::GetRootNeigh( int nEdge, INTVECTOR& vNeigh) //---------------------------------------------------------------------------- int -Tree::GetHeightLeaves( int nId, INTVECTOR& vnLeaves, int d) const +Tree::GetHeightLeaves( const int& nId, INTVECTOR& vnLeaves, int d) const { - if ( nId == -1 && m_mTree.at(-1).IsLeaf()) { + if ( nId == -1 && m_mTree.at( -1).IsLeaf()) { vnLeaves.push_back( -1) ; return 0 ; } else { if ( (int) vnLeaves.size() == 0) { - if ( m_mTree.at(nId).IsLeaf()) + if ( m_mTree.at( nId).IsLeaf()) return d ; else { - vnLeaves.push_back( m_mTree.at(nId).m_nChild1) ; - vnLeaves.push_back( m_mTree.at(nId).m_nChild2) ; - if ( ! m_mTree.at(m_mTree.at(nId).m_nChild1).IsLeaf() || ! m_mTree.at(m_mTree.at(nId).m_nChild2).IsLeaf()) + vnLeaves.push_back( m_mTree.at( nId).m_nChild1) ; + vnLeaves.push_back( m_mTree.at( nId).m_nChild2) ; + if ( ! m_mTree.at( m_mTree.at( nId).m_nChild1).IsLeaf() || ! m_mTree.at( m_mTree.at( nId).m_nChild2).IsLeaf()) // almeno un child non è leaf quindi devo richiamare ricorsivamente questa funzione sui child in questione - d = GetHeightLeaves( nId, vnLeaves, m_mTree.at(m_mTree.at(nId).m_nChild1).m_nDepth) ; + d = GetHeightLeaves( nId, vnLeaves, m_mTree.at( m_mTree.at( nId).m_nChild1).m_nDepth) ; } } else { for ( int j = 0 ; j != (int) vnLeaves.size() ; ++ j) { - int i = vnLeaves.at(j) ; - if ( m_mTree.at(i).IsLeaf() ) { + int i = vnLeaves.at( j) ; + if ( m_mTree.at( i).IsLeaf()) { continue ; } else { // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child vnLeaves.erase( remove( vnLeaves.begin(),vnLeaves.end(),i)) ; -- j ; - vnLeaves.push_back( m_mTree.at(i).m_nChild1) ; - vnLeaves.push_back( m_mTree.at(i).m_nChild2) ; - d = std::max ( d, m_mTree.at(m_mTree.at(i).m_nChild1).m_nDepth) ; + vnLeaves.push_back( m_mTree.at( i).m_nChild1) ; + vnLeaves.push_back( m_mTree.at( i).m_nChild2) ; + d = std::max ( d, m_mTree.at( m_mTree.at( i).m_nChild1).m_nDepth) ; } } return d ; } - return d - m_mTree.at(nId).m_nDepth ; + return d - m_mTree.at( nId).m_nDepth ; } } //---------------------------------------------------------------------------- int -Tree::GetDepth( int nId, int nRef = -2) const +Tree::GetDepth( const int& nId, const int& nRef = -2) const { int c = 0 ; - while ( m_mTree.at(nId).m_nParent != nRef) { - nId = m_mTree.at(nId).m_nParent ; + int nCell = nId ; + while ( m_mTree.at( nCell).m_nParent != nRef) { + nCell = m_mTree.at( nCell).m_nParent ; ++ c ; } return c ; @@ -1210,7 +1183,7 @@ struct generator //---------------------------------------------------------------------------- bool Tree::GetPolygons( std::vector& vPolygons) { - if ( (int) m_vPolygons.size() == 0 ) { + if ( (int) m_vPolygons.size() == 0) { if ( ! m_bTrimmed) { vPolygons.clear() ; POLYLINEVECTOR vPolygonsBasic ; @@ -1230,7 +1203,7 @@ Tree::GetPolygons( std::vector& vPolygons) { GetPolygonsBasic( vPolygonsBasic) ; // scorro sui poligoni delle celle non trimmate int nCells = (int)vPolygonsBasic.size() ; - for ( int i = 0 ; i < nCells ; ++i ) { + for ( int i = 0 ; i < nCells ; ++i) { // costruisco i poligoni partendo dal vettore delle intersezioni, come spiegato a pag15 di Cripps int nId = m_vnLeaves[i] ; @@ -1262,7 +1235,7 @@ Tree::GetPolygons( std::vector& vPolygons) { CreateIslandAndHoles( i, vPolygons, nPoly, vnParentChunk) ; } } - return true; + return true ; } } else { @@ -1283,12 +1256,12 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons) for ( int nId : m_vnLeaves) { vVertices.clear() ; vNeigh.clear() ; - vVertices.push_back( m_mTree.at(nId).GetBottomLeft()) ; + vVertices.push_back( m_mTree.at( nId).GetBottomLeft()) ; GetBottomNeigh( nId, vNeigh) ; // aggiungo i vertici che sono sul lato bottom, solo se ho più di un vicino bottom if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1){ - for ( int j : vNeigh ) - vVertices.push_back( m_mTree.at(j).GetTopRight()) ; + for ( int j : vNeigh) + vVertices.push_back( m_mTree.at( j).GetTopRight()) ; bBottomRight = true ; } else @@ -1297,22 +1270,22 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons) GetRightNeigh ( nId, vNeigh) ; // aggiungo i vertici che sono sul lato right, solo se ho più di un vicino right if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1){ - for ( int j : vNeigh ) - vVertices.push_back( m_mTree.at(j).GetBottomLeft()) ; + for ( int j : vNeigh) + vVertices.push_back( m_mTree.at( j).GetBottomLeft()) ; } // se non l'ho già aggiunto tramite i vicini bottom aggiungo il punto bottom right - else if ( ! bBottomRight ) { - Point3d ptBr( m_mTree.at(nId).GetTopRight().x, m_mTree.at(nId).GetBottomLeft().y) ; + else if ( ! bBottomRight) { + Point3d ptBr( m_mTree.at( nId).GetTopRight().x, m_mTree.at( nId).GetBottomLeft().y) ; vVertices.push_back( ptBr) ; } vNeigh.clear() ; - vVertices.push_back( m_mTree.at(nId).GetTopRight()) ; + vVertices.push_back( m_mTree.at( nId).GetTopRight()) ; GetTopNeigh ( nId, vNeigh) ; std::reverse( vNeigh.begin(), vNeigh.end()) ; // aggiungo i vertici che sono sul lato top, solo se ho più di un vicino top if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) { for ( int j : vNeigh) - vVertices.push_back( m_mTree.at(j).GetBottomLeft()) ; + vVertices.push_back( m_mTree.at( j).GetBottomLeft()) ; bTopLeft = true ; } else @@ -1323,34 +1296,34 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons) // aggiungo i vertici che sono sul lato left, solo se ho più di un vicino left if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) { for ( int j : vNeigh) - vVertices.push_back( m_mTree.at(j).GetTopRight()) ; + vVertices.push_back( m_mTree.at( j).GetTopRight()) ; } // se non l'ho già aggiunto tramite i vicini top aggiungo il punto top left else if ( ! bTopLeft) { - Point3d ptTl( m_mTree.at(nId).GetBottomLeft().x, m_mTree.at(nId).GetTopRight().y) ; + Point3d ptTl( m_mTree.at( nId).GetBottomLeft().x, m_mTree.at( nId).GetTopRight().y) ; vVertices.push_back( ptTl) ; } vNeigh.clear() ; - vVertices.push_back( m_mTree.at(nId).GetBottomLeft()) ; + vVertices.push_back( m_mTree.at( nId).GetBottomLeft()) ; if ( ! m_bTrimmed) { // se ho una cella con vicino dello stesso grado ( quindi il poligono ha solo 5 punti) controllo la curvatura nella cella e // se necessario cambio l'ordine dei vertici per scegliere la diagonale di split migliore if ( vVertices.size() == 5) { - Point3d ptPSrf, ptP00, ptP10, ptP11, ptP01; + Point3d ptPSrf, ptP00, ptP10, ptP11, ptP01 ; double dU, dV ; - dU = ( m_mTree.at(nId).GetBottomLeft().x + m_mTree.at(nId).GetTopRight().x) / 2 / SBZ_TREG_COEFF; - dV = ( m_mTree.at(nId).GetBottomLeft().y + m_mTree.at(nId).GetTopRight().y) / 2 / SBZ_TREG_COEFF; + dU = ( m_mTree.at( nId).GetBottomLeft().x + m_mTree.at( nId).GetTopRight().x) / 2 / SBZ_TREG_COEFF ; + dV = ( m_mTree.at( nId).GetBottomLeft().y + m_mTree.at( nId).GetTopRight().y) / 2 / SBZ_TREG_COEFF ; m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - ptP00 = m_mVert.at(nId).at(0) ; - ptP10 = m_mVert.at(nId).at(1) ; - ptP11 = m_mVert.at(nId).at(2) ; - ptP01 = m_mVert.at(nId).at(3) ; + ptP00 = m_mVert.at( nId).at( 0) ; + ptP10 = m_mVert.at( nId).at( 1) ; + ptP11 = m_mVert.at( nId).at( 2) ; + ptP01 = m_mVert.at( nId).at( 3) ; Point3d ptP00P11 = ( ptP00 + ptP11) / 2 ; Point3d ptP10P01 = ( ptP10 + ptP01) / 2 ; // ho la curvatura maggiore sulla diagonale tra P10 e P01, ruoto l'ordine dei vertici, in modo che triangulate prenda la diagonale giusta - if ( Dist(ptP00P11, ptPSrf) + EPS_SMALL > Dist(ptP10P01, ptPSrf)) { - rotate(vVertices.begin(), vVertices.begin() + 1,vVertices.end()) ; - vVertices.back() = vVertices.at(0) ; + if ( Dist( ptP00P11, ptPSrf) + EPS_SMALL > Dist( ptP10P01, ptPSrf)) { + rotate( vVertices.begin(), vVertices.begin() + 1,vVertices.end()) ; + vVertices.back() = vVertices.at( 0) ; } } } @@ -1358,7 +1331,7 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons) m_vPolygons.emplace_back() ; m_vPolygons.back().emplace_back() ; for ( int i = 0 ; i < (int) vVertices.size() ; ++i) { - m_vPolygons.back().back().AddUPoint(i, vVertices.at(i)) ; + m_vPolygons.back().back().AddUPoint( i, vVertices.at( i)) ; } } @@ -1366,7 +1339,7 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons) // restituisco i poligoni delle celle del tree nello spazio parametrico for ( int t = 0 ; t < (int)m_vPolygons.size() ; ++ t) { - for ( int z = 0 ; z < (int)m_vPolygons[t].size(); ++z ) { + for ( int z = 0 ; z < (int)m_vPolygons[t].size() ; ++z) { vPolygons.push_back( m_vPolygons[t][z]) ; } } @@ -1378,21 +1351,21 @@ void Tree::ResetTree( void) { // setto tutte le foglie a Processed = false - for ( int nC : m_vnLeaves ) { + for ( int nC : m_vnLeaves) { m_mTree[nC].SetProcessed( false) ; } } //---------------------------------------------------------------------------- INTVECTOR -Tree::FindCell( const Point3d& ptToAssign, CurveLine& clTrim) const +Tree::FindCell( const Point3d& ptToAssign, const CurveLine& clTrim) const { INTVECTOR nCells ; int nId = -1 ; // se fallisce ritorna un vettore vuoto // verifico che il punto sia all'interno dello spazio parametrico - if ( ptToAssign.x < m_mTree.at(-1).GetBottomLeft().x || ptToAssign.x > m_mTree.at( -1).GetTopRight().x || - ptToAssign.y < m_mTree.at(-1).GetBottomLeft().y || ptToAssign.y > m_mTree.at( -1).GetTopRight().y ) { + if ( ptToAssign.x < m_mTree.at( -1).GetBottomLeft().x || ptToAssign.x > m_mTree.at( -1).GetTopRight().x || + ptToAssign.y < m_mTree.at( -1).GetBottomLeft().y || ptToAssign.y > m_mTree.at( -1).GetTopRight().y ) { //nCells.push_back( - 2) ; return nCells ; } @@ -1404,35 +1377,35 @@ Tree::FindCell( const Point3d& ptToAssign, CurveLine& clTrim) const nId = nParents.back() ; } // individuo la foglia in cui ho lo start del loop - while ( ! m_mTree.at(nId).IsLeaf()) { - if ( m_mTree.at(nId).IsSplitVert()) { - double dMid = ( m_mTree.at(nId).GetBottomLeft().x + m_mTree.at(nId).GetTopRight().x) / 2 ; + while ( ! m_mTree.at( nId).IsLeaf()) { + if ( m_mTree.at( nId).IsSplitVert()) { + double dMid = ( m_mTree.at( nId).GetBottomLeft().x + m_mTree.at( nId).GetTopRight().x) / 2 ; if ( ptToAssign.x < dMid + EPS_SMALL) { - nId = m_mTree.at(nId).m_nChild1 ; + nId = m_mTree.at( nId).m_nChild1 ; } else { - nId = m_mTree.at(nId).m_nChild2 ; + nId = m_mTree.at( nId).m_nChild2 ; } } else { - double dMid = ( m_mTree.at(nId).GetBottomLeft().y + m_mTree.at(nId).GetTopRight().y) / 2 ; - if ( ptToAssign.y < dMid + EPS_SMALL ) { - nId = m_mTree.at(nId).m_nChild2 ; + double dMid = ( m_mTree.at( nId).GetBottomLeft().y + m_mTree.at( nId).GetTopRight().y) / 2 ; + if ( ptToAssign.y < dMid + EPS_SMALL) { + nId = m_mTree.at( nId).m_nChild2 ; } else { - nId = m_mTree.at(nId).m_nChild1 ; + nId = m_mTree.at( nId).m_nChild1 ; } } } nCells.push_back( nId) ; - 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())) + 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())) { Point3d ptToAssignPlus ; double dParam ; @@ -1454,24 +1427,23 @@ Tree::FindCell( const Point3d& ptToAssign, CurveLine& clTrim) const //---------------------------------------------------------------------------- INTVECTOR -Tree::FindCell( const Point3d& ptToAssign, CurveLine& cl, INTVECTOR vCells) const +Tree::FindCell( const Point3d& ptToAssign, const CurveLine& cl, INTVECTOR vCells) const { // se non trova nulla restituisce un vettore vuoto // restituisce sempre solo una cella // la CurveLine è il segmento di trim su cui giace ptToAssign - // devo usare ptInters + qualcosa/////////////////////////////////////////////// Point3d ptIntersPlus ; double dParam ; Vector3d vDir ; cl.GetParamAtPoint( ptToAssign, dParam, EPS_SMALL) ; + // mi sposto appena più avanti di ptToAssign cl.GetPointTang( dParam + EPS_SMALL, ICurve::FROM_MINUS, ptIntersPlus, vDir) ; INTVECTOR nCells ; int nId = -1 ; - bool bFound = false ; - for ( int nCell : vCells ) { - if ( ptIntersPlus.x >= m_mTree.at(nCell).GetBottomLeft().x && ptIntersPlus.x <= m_mTree.at(nCell).GetTopRight().x && - ptIntersPlus.y >= m_mTree.at(nCell).GetBottomLeft().y && ptIntersPlus.y <= m_mTree.at(nCell).GetTopRight().y) { + for ( int nCell : vCells) { + if ( ptIntersPlus.x >= m_mTree.at( nCell).GetBottomLeft().x && ptIntersPlus.x <= m_mTree.at( nCell).GetTopRight().x && + ptIntersPlus.y >= m_mTree.at( nCell).GetBottomLeft().y && ptIntersPlus.y <= m_mTree.at( nCell).GetTopRight().y) { nId = nCell ; nCells.push_back( nId) ; } @@ -1485,8 +1457,7 @@ Tree::TraceLoopLabelCell( void) { // approssimo i loop di trim con delle spezzate POLYLINEVECTOR vPlApprox ; - //for ( PtrOwner pCrv : m_vLoop){ - for ( int p = 0 ; p < (int) m_vLoop.size(); ++ p){ + for ( int p = 0 ; p < (int) m_vLoop.size() ; ++ p){ PtrOwner pCrv( m_vLoop[p]->Clone()) ; double dLinTol = 0.01 ; // questo è riferito allo spazio parametrico perché le curve di loop sono già state riscalate!!!!!! double dAngTolDeg = 5 ; @@ -1502,14 +1473,14 @@ Tree::TraceLoopLabelCell( void) 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) vPlApprox.size(); ++ i) { + for ( int i = 0 ; i < (int) vPlApprox.size() ; ++ i) { PolyLine plLoop = vPlApprox[i] ; // calcolo se il loop è CCW o Cw double dArea ; Plane3d plExtPlane ; bool bCCW ; plLoop.IsClosedAndFlat( plExtPlane, dArea, 50 * EPS_SMALL) ; - if ( plExtPlane.GetVersN().z > 0 ) + if ( plExtPlane.GetVersN().z > 0) bCCW = true ; else bCCW = false ; @@ -1517,7 +1488,7 @@ Tree::TraceLoopLabelCell( void) Point3d ptStart ; plLoop.GetFirstPoint( ptStart) ; PNTULIST lPt = plLoop.GetUPointList() ; - PNTULIST:: iterator ptFirst = lPt.begin(); + PNTULIST:: iterator ptFirst = lPt.begin() ; PNTULIST:: iterator ptSecond = ptFirst ; std::advance( ptSecond, 1) ; CurveLine clFirst ; @@ -1543,7 +1514,11 @@ 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) ; @@ -1551,7 +1526,7 @@ Tree::TraceLoopLabelCell( void) 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 - if ( bEraseNextPoint ) { + if ( bEraseNextPoint) { vptInters.pop_back() ; bEraseNextPoint = false ; } @@ -1561,13 +1536,15 @@ Tree::TraceLoopLabelCell( void) // al precedente FindInters avrei dovuto passare di cella if ( ! FindInters( nId, clTrim, vptInters, true)) { // scarterò il punto molto vicino al lato e tengo solo l'intersezione del trim col lato - m_mTree[nId].m_vInters.back().vpt.pop_back() ; + //m_mTree[nId].m_vInters.back().vpt.pop_back() ; + vptInters.pop_back() ; plLoop.GetPrevPoint( ptTEnd) ; plLoop.GetPrevPoint( ptTStart) ; plLoop.GetNextPoint( ptCurr) ; clTrim.Set( ptTStart, ptTEnd) ; - //clTrim.ExtendEndByLen( EPS_SMALL * 2) ; - vptInters.clear() ; + clTrim.ExtendEndByLen( EPS_SMALL * 2) ; + clTrim.ExtendStartByLen( EPS_SMALL * 2) ; + //vptInters.clear() ; if ( FindInters( nId, clTrim, vptInters, true)) return false ; bEraseNextPoint = true ; @@ -1579,6 +1556,8 @@ 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) ; @@ -1587,7 +1566,6 @@ Tree::TraceLoopLabelCell( void) vptInters.pop_back() ; m_mTree[nId].m_vInters.back().vpt = vptInters ; if ( bLoopInside) { - //m_mTree[nId].m_vnLoop.push_back( i) ; // setto la categoria della cella if ( m_mTree[nId].m_nFlag == -1) m_mTree[nId].m_nFlag = 2 ; @@ -1621,8 +1599,8 @@ Tree::TraceLoopLabelCell( void) else if ( nId == nFirstCell) { int nOut = m_mTree[nId].m_vInters[nPass].nOut ; m_mTree[nId].m_vInters.back().vpt.insert( m_mTree[nId].m_vInters.back().vpt.end(), - m_mTree[nId].m_vInters[nPass].vpt.begin(), - m_mTree[nId].m_vInters[nPass].vpt.end()) ; + m_mTree[nId].m_vInters[nPass].vpt.begin(), + m_mTree[nId].m_vInters[nPass].vpt.end()) ; m_mTree[nId].m_vInters[nPass] = m_mTree[nId].m_vInters.back() ; m_mTree[nId].m_vInters.pop_back() ; // sistemo il lato d'uscita @@ -1633,7 +1611,7 @@ Tree::TraceLoopLabelCell( void) // riordino i vettori di intersezione per ogni cella e setto il flag RightEdgeIn for ( int nId : m_vnLeaves) { - std::sort( m_mTree[nId].m_vInters.begin( ), m_mTree[nId].m_vInters.end()) ; + std::sort( m_mTree[nId].m_vInters.begin(), m_mTree[nId].m_vInters.end()) ; SetRightEdgeIn( nId) ; } @@ -1651,30 +1629,19 @@ Tree::TraceLoopLabelCell( void) 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 && ! bDone) || ! m_mTree[nCell].IsProcessed()) { - // per debug - if ( nInProcessing != nCell) { - nInProcessing = nCell ; - c = 0 ; - } - else - ++ c ; + while ( ( (int)vNeigh.size() > 0 && ! bDone) || ! 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) { - if ( m_mTree[vNeigh[i]].m_nFlag2 == 0 ) { + 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 ; } } - if ( ! bProceeded ) { + if ( ! bProceeded) { m_mTree[nCell].SetProcessed() ; } else { //categorizzo la cella @@ -1695,42 +1662,30 @@ Tree::TraceLoopLabelCell( void) } } } - // 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) ; - for ( int p = 0; p < (int)vNeigh.size() ; ++ p) { - if ( m_mTree[vNeigh[p]].m_nFlag2 != 0 ) { + for ( int p = 0 ; p < (int)vNeigh.size() ; ++ p) { + if ( m_mTree[vNeigh[p]].m_nFlag2 != 0) { nCell = vNeigh[p] ; 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 ) { + 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() ) { + if ( nCell == nLastLeft && m_mTree[nCell].IsProcessed()) { // categorizzo m_mTree[nCell].m_nFlag2 = 1 ; CategorizeCell( nCell) ; @@ -1742,9 +1697,8 @@ Tree::TraceLoopLabelCell( void) vNeigh.clear() ; GetRightNeigh( nCell, vNeigh) ; bool bDone = true ; - for ( int k = 0; k < (int)vNeigh.size() ; ++ k) { - if ( ! m_mTree[vNeigh[k]].IsProcessed() ) { - //nCell = vNeigh[k] ; + for ( int k = 0 ; k < (int)vNeigh.size() ; ++ k) { + if ( ! m_mTree[vNeigh[k]].IsProcessed()) { bDone = false ; break ; } @@ -1756,9 +1710,6 @@ Tree::TraceLoopLabelCell( void) CategorizeCell( nCell) ; } } - // per debug - if ( c > 3) - break ; } vNeigh.clear() ; GetRightNeigh( nCell, vNeigh) ; @@ -1769,7 +1720,7 @@ Tree::TraceLoopLabelCell( void) //---------------------------------------------------------------------------- bool -Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool bFirstInters) +Tree::FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool bFirstInters) { CurveLine clEdge , clEdge2 ; Point3d ptStart , ptEnd ; @@ -1882,9 +1833,7 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool bFirst } OnWhichEdge( nId, ptInters, nEdge) ; m_mTree[nId].m_vInters.back().nOut = nEdge ; - if ( (int)vptInters.size() == 0) - vptInters.push_back( ptInters) ; - else if ( ! AreSamePointExact(ptInters , vptInters.back())) + if ( (int)vptInters.size() == 0 || ! AreSamePointExact( ptInters , vptInters.back())) vptInters.push_back( ptInters) ; // salvo il vettore intersezione per la cella e capisco in quale altra cella passare if ( (int)vptInters.size() == 1) @@ -1902,7 +1851,7 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool bFirst if ( nEdge == 0) { GetTopNeigh( nId, vNeigh) ; std::reverse( vNeigh.begin(), vNeigh.end()) ; - for ( int j : vNeigh ) { + for ( int j : vNeigh) { if ( ptInters.x >= m_mTree[j].GetBottomLeft().x) { nId = j ; break ; @@ -1922,7 +1871,7 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool bFirst else if ( nEdge == 1) { GetLeftNeigh( nId, vNeigh) ; std::reverse( vNeigh.begin(), vNeigh.end()) ; - for ( int j : vNeigh ) { + for ( int j : vNeigh) { if ( ptInters.y >= m_mTree[j].GetBottomLeft().y) { nId = j ; break ; @@ -1941,7 +1890,7 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool bFirst } else if ( nEdge == 2) { GetBottomNeigh( nId, vNeigh) ; - for ( int j : vNeigh ) { + for ( int j : vNeigh) { if ( ptInters.x <= m_mTree[j].GetTopRight().x) { nId = j ; break ; @@ -1960,7 +1909,7 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool bFirst } else if ( nEdge == 3) { GetRightNeigh( nId, vNeigh) ; - for ( int j : vNeigh ) { + for ( int j : vNeigh) { if ( ptInters.y <= m_mTree[j].GetTopRight().y) { nId = j ; break ; @@ -2182,13 +2131,13 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool bFirst //---------------------------------------------------------------------------- bool -Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk, PolyLine plCell) +Tree::CreateCellPolygons( const int& nLeafId, std::vector& vPolygons, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk, const PolyLine& plCell) { // conto quanti vertici in più ho per lato e creo un vettore dei vertici per lato int nId = m_vnLeaves[nLeafId] ; std::vector vEdgeVertex ; - Point3d ptTl(m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; - Point3d ptBr(m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; + Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; + Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; vEdgeVertex.emplace_back() ; vEdgeVertex.back().push_back( m_mTree[nId].GetTopRight()) ; vEdgeVertex.emplace_back() ; @@ -2210,12 +2159,10 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I while ( plCell.GetNextPoint( ptToAdd) && ! AreSamePointExact( ptToAdd, vEdgeVertex[next][0])) { vEdgeVertex[j].push_back( ptToAdd) ; } - //vEdgeVertex[next].push_back( ptToAdd) ; } // comincio a costruire il poligono INTVECTOR vToCheckNow = vToCheck ; - //vToCheck.clear() ; // vettore dei poligoni ( loop) della cella nId POLYLINEVECTOR vCellPolygons ; // costruisco i poligoni partendo dal vettore delle intersezioni, come spiegato a pag15 di Cripps @@ -2236,57 +2183,57 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I // indice del loop in m_vInters int j = vToCheckNow[w] ; Inters inA = m_mTree[nId].m_vInters[j] ; - if ( inA.nIn != -1 ) { + if ( inA.nIn != -1) { int nEdge ; - if ( nEdgeIn == -1 ) { + if ( nEdgeIn == -1) { // salvo il lato di ingresso del primo lato del poligono che sto costruendo nEdgeIn = inA.nIn ; nFirstLoopInPoly = j ; } - for ( Point3d ptInt : inA.vpt ) { + for ( Point3d ptInt : inA.vpt) { AddVertex( nId, vEdgeVertex, plTrimmedPoly, c, ptInt) ; } vAddedLoops.push_back( j) ; nEdge = inA.nOut ; // devo verificare di non essere uscito in un vertice, con un tratto sovrapposto al lato che ripercorrerò tra poco - Point3d ptLast, ptSecondToLast; - plTrimmedPoly.GetLastPoint(ptLast) ; - plTrimmedPoly.GetPrevPoint(ptSecondToLast) ; + Point3d ptLast, ptSecondToLast ; + plTrimmedPoly.GetLastPoint( ptLast) ; + plTrimmedPoly.GetPrevPoint( ptSecondToLast) ; Vector3d vLast = ptLast - ptSecondToLast ; - vLast.Normalize(); + vLast.Normalize() ; Vector3d vEdge ; if ( AreSameEdge( nEdge, 0)) { - if ( AreSamePointExact(ptLast, ptTl) ) { + if ( AreSamePointExact( ptLast, ptTl)) { vEdge = m_mTree[nId].GetBottomLeft() - ptTl ; vEdge.Normalize() ; - if ( AreOppositeVectorApprox(vLast, vEdge) ) { + if ( AreOppositeVectorApprox( vLast, vEdge)) { plTrimmedPoly.EraseLastUPoint() ; nEdge = 1 ; } } } - else if ( AreSameEdge( nEdge, 1) && AreSamePointExact(ptLast, m_mTree[nId].GetBottomLeft()) ) { + else if ( AreSameEdge( nEdge, 1) && AreSamePointExact( ptLast, m_mTree[nId].GetBottomLeft())) { vEdge = ptBr - m_mTree[nId].GetBottomLeft() ; vEdge.Normalize() ; - if ( AreOppositeVectorApprox(vLast, vEdge) ) { + if ( AreOppositeVectorApprox( vLast, vEdge)) { plTrimmedPoly.EraseLastUPoint() ; nEdge = 2 ; } } - else if ( AreSameEdge( nEdge, 2) ) { - if ( AreSamePointExact(ptLast, ptBr) ) { + else if ( AreSameEdge( nEdge, 2)) { + if ( AreSamePointExact( ptLast, ptBr)) { vEdge = m_mTree[nId].GetTopRight() - ptBr ; vEdge.Normalize() ; - if ( AreOppositeVectorApprox(vLast, vEdge) ) { + if ( AreOppositeVectorApprox( vLast, vEdge)) { plTrimmedPoly.EraseLastUPoint() ; nEdge = 3 ; } } } - else if ( AreSameEdge( nEdge, 3) && AreSamePointExact(ptLast, m_mTree[nId].GetTopRight()) ) { + else if ( AreSameEdge( nEdge, 3) && AreSamePointExact( ptLast, m_mTree[nId].GetTopRight())) { vEdge = ptTl - m_mTree[nId].GetTopRight() ; vEdge.Normalize() ; - if ( AreOppositeVectorApprox(vLast, vEdge) ) { + if ( AreOppositeVectorApprox( vLast, vEdge)) { plTrimmedPoly.EraseLastUPoint() ; nEdge = 0 ; } @@ -2294,16 +2241,16 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I // se mi è rimasto solo un punto sulla polyline vuol dire che avevo solo un tratto parallelo ad lato // quindi salto al prossimo loop - if ( plTrimmedPoly.GetPointNbr() == 1 ) { + if ( plTrimmedPoly.GetPointNbr() == 1) { plTrimmedPoly.Clear() ; if ( j == nFirstLoopInPoly) nEdgeIn = -1 ; continue ; } - if ( nEdge > 3 && nEdge != 7 ) { + if ( nEdge > 3 && nEdge != 7) { nEdge = nEdge - 3 ; } - else if ( nEdge == 7 ) { + else if ( nEdge == 7) { nEdge = 0 ; } // se ho altri Pass vado avanti ad aggiungere vertici finché trovo il prossimo o finché non sono tornato sul lato di partenza @@ -2323,7 +2270,6 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I } else { ++ nSecondCheck ; - //vToCheck.push_back( vToCheckNow[t]) ; } } @@ -2342,7 +2288,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I AddVertex( nId, vEdgeVertex, plTrimmedPoly, c, ptVert) ; if ( nEdge > 3 && nEdge != 7) nEdge = nEdge - 4 ; - else if ( nEdge < 3 ) + else if ( nEdge < 3) ++ nEdge ; else nEdge = 0 ; @@ -2357,7 +2303,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I // se ho trovato un altro loop salto all'inizio del for, dopo aver aggiunto eventuali punti intermedi if ( bValidNextStart) { for ( int p = 1 ; p < (int) vEdgeVertex[nEdge].size() ; ++ p) { - if ( CheckIfBefore( nEdge, vEdgeVertex[nEdge][p], m_mTree[nId].m_vInters[vToCheckNow[nNext]].vpt[0]) ) { + if ( CheckIfBefore( nEdge, vEdgeVertex[nEdge][p], m_mTree[nId].m_vInters[vToCheckNow[nNext]].vpt[0])) { plTrimmedPoly.AddUPoint( c, vEdgeVertex[nEdge][p]) ; ++ c ; } @@ -2370,7 +2316,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I Point3d ptStart ; plTrimmedPoly.GetFirstPoint( ptStart) ; for ( int p = 1 ; p < (int) vEdgeVertex[nEdge].size() ; ++ p) { - if ( CheckIfBefore( nEdge, vEdgeVertex[nEdge][p], ptStart) ) { + if ( CheckIfBefore( nEdge, vEdgeVertex[nEdge][p], ptStart)) { plTrimmedPoly.AddUPoint( c, vEdgeVertex[nEdge][p]) ; ++ c ; } @@ -2396,7 +2342,7 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I AddVertex( nId, vEdgeVertex, plTrimmedPoly, c, ptVert) ; if ( nEdge > 3 && nEdge != 7) nEdge = nEdge - 4 ; - else if ( nEdge < 3 ) + else if ( nEdge < 3) ++ nEdge ; else nEdge = 0 ; @@ -2430,8 +2376,8 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I // 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] ) { - vToCheck.erase(vToCheck.begin() + k) ; + if ( vToCheck[k] == vAddedLoops[i]) { + vToCheck.erase( vToCheck.begin() + k) ; } } } @@ -2444,17 +2390,13 @@ Tree::CreateCellPolygons( int nLeafId, std::vector& vPolygons, I //---------------------------------------------------------------------------- bool -Tree::CreateIslandAndHoles( int nLeafId, std::vector& vPolygons, int& nPoly, INTVECTOR& vnParentChunk) +Tree::CreateIslandAndHoles( const int& nLeafId, std::vector& vPolygons, int& nPoly, INTVECTOR& vnParentChunk) { // vettore dei poligoni ( loop) della cella nId POLYLINEVECTOR vCellPolygons ; - // costruisco i poligoni partendo dal vettore delle intersezioni, come spiegato a pag15 di Cripps + // costruisco i poligoni partendo dal vettore delle intersezioni int nId = m_vnLeaves[nLeafId] ; PolyLine plTrimmedPoly ; - // numero di volte che la cella è stata attraversata da una curva di trim - int nPass = (int) m_mTree[nId].m_vInters.size() ; - // numero di vertici aggiunti al nuovo poligono - int c = 0 ; // loop interni in una cella intersecata if ( m_mTree[nId].m_nFlag == 3 || m_mTree[nId].m_nFlag == 2) { @@ -2462,7 +2404,6 @@ Tree::CreateIslandAndHoles( int nLeafId, std::vector& vPolygons, // numero dei loop interni passati Inters inA ; // se ho almeno un loop CW che non è contenuto in un altro poligono o in un loop interno CCW devo aggiungere il bordo - //bool bEdgeToAdd = true ; bool bAllContained = true ; bool bContained = false ; int nInters = (int) m_mTree[nId].m_vInters.size() ; @@ -2491,7 +2432,6 @@ Tree::CreateIslandAndHoles( int nLeafId, std::vector& vPolygons, break ; } - //if ( m_mTree[nId].m_nFlag == 2 && ( bEdgeToAdd || ! bAllContained)) { if ( m_mTree[nId].m_nFlag == 2 && ! bAllContained) { // i loop esterni sono CW, quindi prima dei loop di trim aggiungo il bordo cella Point3d ptVert = m_mTree[nId].GetTopRight() ; @@ -2504,7 +2444,7 @@ Tree::CreateIslandAndHoles( int nLeafId, std::vector& vPolygons, ptVert.x = m_mTree[nId].GetTopRight().x ; ptVert.y = m_mTree[nId].GetBottomLeft().y ; plInLoop.AddUPoint( 3, ptVert) ; - plInLoop.Close(); + plInLoop.Close() ; vCellPolygons.push_back( plInLoop) ; vPolygons.push_back( vCellPolygons) ; ++ nPoly ; @@ -2512,8 +2452,8 @@ Tree::CreateIslandAndHoles( int nLeafId, std::vector& vPolygons, vCellPolygons.clear() ; plInLoop.Clear() ; } - for ( int i = 0 ; i < nInters ; ++ i) { - inA = m_mTree[nId].m_vInters[i] ; + for ( int nLoop = 0 ; nLoop < nInters ; ++ nLoop) { + inA = m_mTree[nId].m_vInters[nLoop] ; if ( inA.nIn == -1) { // numero di vertici aggiunti al nuovo poligono int k = 0 ; @@ -2521,15 +2461,15 @@ Tree::CreateIslandAndHoles( int nLeafId, std::vector& vPolygons, plInLoop.AddUPoint( k, ptInt) ; ++ k ; } - plInLoop.Close(); + plInLoop.Close() ; bool bAdded = false ; // se il loop è CW devo controllare in quale altro dei poligoni che ho già aggiunto è contenuto if ( ! inA.bCCW) { Point3d ptStart ; plInLoop.GetFirstPoint( ptStart) ; int nOtherPoly = (int)vPolygons.size() ; - for ( int r = 0 ; r < nPoly ; ++r ) { - if ( IsPointInsidePolyLine( ptStart, vPolygons[nOtherPoly - r - 1][0], -0.01) && vnParentChunk[nPoly - r - 1] == inA.nChunk ) { + for ( int r = 0 ; r < nPoly ; ++r) { + if ( IsPointInsidePolyLine( ptStart, vPolygons[nOtherPoly - r - 1][0], -0.01) && vnParentChunk[nLoop - r - 1] == inA.nChunk) { vPolygons[nOtherPoly - r - 1].push_back( plInLoop) ; plInLoop.Clear() ; vnParentChunk.push_back( inA.nChunk) ; @@ -2557,7 +2497,7 @@ Tree::CreateIslandAndHoles( int nLeafId, std::vector& vPolygons, //---------------------------------------------------------------------------- bool -Tree::CheckIfBefore( PolyLine& pl, int nEdge) const +Tree::CheckIfBefore( const PolyLine& pl, const int& nEdge) const { // controllo se ptEnd è prima di ptStart sul lato nEdge rispetto al senso antiorario ( quindi se è dopo in senso orario) Point3d ptStart, ptEnd ; @@ -2566,13 +2506,13 @@ Tree::CheckIfBefore( PolyLine& pl, int nEdge) const if ( AreSameEdge( nEdge, 0)) { return ptEnd.x > ptStart.x ; } - else if ( AreSameEdge( nEdge, 1) ) { + else if ( AreSameEdge( nEdge, 1)) { return ptEnd.y > ptStart.y ; } - else if ( AreSameEdge( nEdge, 2) ) { + else if ( AreSameEdge( nEdge, 2)) { return ptEnd.x < ptStart.x ; } - else if ( AreSameEdge( nEdge, 3) ) { + else if ( AreSameEdge( nEdge, 3)) { return ptEnd.y < ptStart.y ; } return false ; @@ -2580,7 +2520,7 @@ Tree::CheckIfBefore( PolyLine& pl, int nEdge) const //---------------------------------------------------------------------------- bool -Tree::CheckIfBefore( Inters& inA) const +Tree::CheckIfBefore( const Inters& inA) const { // questa funzione è pensata in riferimento al lato 3, quindi nessuno dei due punti può stare su Edge = 3 // controllo se l'ingresso è prima dell'uscita @@ -2614,7 +2554,7 @@ Tree::CheckIfBefore( Inters& inA) const //---------------------------------------------------------------------------- bool -Tree::CheckIfBefore( int& nEdge1, Point3d& ptP1, int& nEdge2, Point3d& ptP2) const +Tree::CheckIfBefore( const int& nEdge1, const Point3d& ptP1, const int& nEdge2, const Point3d& ptP2) const { if ( nEdge1 == -1 || nEdge2 == -1) return false ; @@ -2643,20 +2583,20 @@ Tree::CheckIfBefore( int& nEdge1, Point3d& ptP1, int& nEdge2, Point3d& ptP2) con //---------------------------------------------------------------------------- bool -Tree::CheckIfBefore( int& nEdge, Point3d& ptP1, Point3d& ptP2) const +Tree::CheckIfBefore( const int& nEdge, const Point3d& ptP1, const Point3d& ptP2) const { // sul lato nEdge controllo se ptP1 viene prima di ptP2. // i lati vengono percorsi in senso antiorario - if ( AreSameEdge(nEdge, 0) ) { + if ( AreSameEdge( nEdge, 0)) { return ptP1.x > ptP2.x ; } - else if ( AreSameEdge(nEdge, 1) ) { + else if ( AreSameEdge( nEdge, 1)) { return ptP1.y > ptP2.y ; } - else if ( AreSameEdge(nEdge, 2) ) { + else if ( AreSameEdge( nEdge, 2)) { return ptP1.x < ptP2.x ; } - else if ( AreSameEdge(nEdge, 3) ) { + else if ( AreSameEdge( nEdge, 3)) { return ptP1.y < ptP2.y ; } return false ; @@ -2664,90 +2604,53 @@ Tree::CheckIfBefore( int& nEdge, Point3d& ptP1, Point3d& ptP2) const //---------------------------------------------------------------------------- bool -Tree::CheckIfAfter( PolyLine& pl, Point3d& ptNextStart, int nEdge) const -{ - // controllo se ptNextStart è più avanti rispetto a ptEnd in senso antiorario - // ATTENZIONE i due punti devono essere sullo stesso lato! - - // se i punti non sono sullo stesso lato ritorno false - Point3d ptEnd ; - pl.GetLastPoint( ptEnd) ; - if ( AreSameEdge(nEdge, 0) ) { - if ( ptNextStart.y > ptEnd.y - EPS_SMALL && ptNextStart.y < ptEnd.y + EPS_SMALL) - return ptEnd.x > ptNextStart.x ; - else - return false ; - } - else if ( AreSameEdge(nEdge, 1) ) { - if ( ptNextStart.x > ptEnd.x - EPS_SMALL && ptNextStart.x < ptEnd.x + EPS_SMALL) - return ptEnd.y > ptNextStart.y ; - else - return false ; - } - else if ( AreSameEdge(nEdge, 2) ) { - if ( ptNextStart.y > ptEnd.y - EPS_SMALL && ptNextStart.y < ptEnd.y + EPS_SMALL) - return ptEnd.x < ptNextStart.x ; - else - return false ; - } - else if ( AreSameEdge(nEdge, 3) ) { - if ( ptNextStart.x > ptEnd.x - EPS_SMALL && ptNextStart.x < ptEnd.x + EPS_SMALL) - return ptEnd.y < ptNextStart.y ; - else - return false ; - } - return false ; -} - -//---------------------------------------------------------------------------- -bool -Tree::AreSameEdge( int nEdge1, int nEdge2) const +Tree::AreSameEdge( const int& nEdge1, const int nEdge2) const { if ( nEdge1 == 0) { if ( nEdge2 == 4 || nEdge2 == 0 || nEdge2 == 7) - return true; + return true ; else return false ; } else if ( nEdge1 == 1) { if ( nEdge2 == 4 || nEdge2 == 1 || nEdge2 == 5) - return true; + return true ; else return false ; } else if ( nEdge1 == 2) { if ( nEdge2 == 6 || nEdge2 == 2 || nEdge2 == 5) - return true; + return true ; else return false ; } else if ( nEdge1 == 3) { if ( nEdge2 == 6 || nEdge2 == 3 || nEdge2 == 7) - return true; + return true ; else return false ; } else if ( nEdge1 == 4) { if ( nEdge2 == 0 || nEdge2 == 1 || nEdge2 == 7 || nEdge2 == 5) - return true; + return true ; else return false ; } else if ( nEdge1 == 5) { if ( nEdge2 == 2 || nEdge2 == 1 || nEdge2 == 4 || nEdge2 == 6) - return true; + return true ; else return false ; } else if ( nEdge1 == 6) { if ( nEdge2 == 2 || nEdge2 == 3 || nEdge2 == 5 || nEdge2 == 7) - return true; + return true ; else return false ; } else if ( nEdge1 == 7) { if ( nEdge2 == 0 || nEdge2 == 3 || nEdge2 == 4 || nEdge2 == 6) - return true; + return true ; else return false ; } @@ -2757,7 +2660,7 @@ Tree::AreSameEdge( int nEdge1, int nEdge2) const //---------------------------------------------------------------------------- bool -Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimmedPoly, int& c, Point3d& ptToAdd) const +Tree::AddVertex( const int& nId, const std::vector& vEdgeVertex, PolyLine& plTrimmedPoly, int& c, const Point3d& ptToAdd) const { // se è il primo punto della PolyLine lo aggiungo if ( plTrimmedPoly.GetPointNbr() == 0) { @@ -2772,8 +2675,8 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm Point3d ptLast ; plTrimmedPoly.GetLastPoint( ptLast) ; // verifico di essere allineato con un lato, sennò aggiungo e basta - Vector3d vDir; - if ( ! AreSamePointExact(ptToAdd, ptLast)) + Vector3d vDir ; + if ( ! AreSamePointExact( ptToAdd, ptLast)) vDir = ptToAdd - ptLast ; else return true ; @@ -2794,7 +2697,7 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm if ( abs( vDir.x) > 1 - EPS_SMALL || abs( vDir.y) > 1 - EPS_SMALL) { // se su un edge devo fare dei controlli // edge 0 - if ( ptToAdd.x >= ptBL.x && ptToAdd.x <= ptTR.x && ptToAdd.y == ptTR.y && abs(vDir.x) > 1 - EPS_SMALL) { + if ( ptToAdd.x >= ptBL.x && ptToAdd.x <= ptTR.x && ptToAdd.y == ptTR.y && abs( vDir.x) > 1 - EPS_SMALL) { for ( int t = 0 ; t < (int)vEdgeVertex[0].size() ; ++ t) { Point3d ptIntermed = vEdgeVertex[0][t] ; if ( ptIntermed.x > ptToAdd.x && ptIntermed.x < ptLast.x) { @@ -2806,7 +2709,7 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm ++ c ; } // edge 1 - else if ( ptToAdd.y >= ptBL.y && ptToAdd.y <= ptTR.y && ptToAdd.x == ptBL.x && abs(vDir.y) > 1 - EPS_SMALL) { + else if ( ptToAdd.y >= ptBL.y && ptToAdd.y <= ptTR.y && ptToAdd.x == ptBL.x && abs( vDir.y) > 1 - EPS_SMALL) { for ( int t = 0 ; t < (int)vEdgeVertex[1].size() ; ++ t) { Point3d ptIntermed = vEdgeVertex[1][t] ; if ( ptIntermed.y > ptToAdd.y && ptIntermed.y < ptLast.y) { @@ -2818,7 +2721,7 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm ++ c ; } // edge 2 - else if ( ptToAdd.x >= ptBL.x && ptToAdd.x <= ptTR.x && ptToAdd.y == ptBL.y && abs(vDir.x) > 1 - EPS_SMALL) { + else if ( ptToAdd.x >= ptBL.x && ptToAdd.x <= ptTR.x && ptToAdd.y == ptBL.y && abs( vDir.x) > 1 - EPS_SMALL) { for ( int t = 0 ; t < (int)vEdgeVertex[2].size() ; ++ t) { Point3d ptIntermed = vEdgeVertex[2][t] ; if ( ptIntermed.x < ptToAdd.x && ptIntermed.x > ptLast.x) { @@ -2830,7 +2733,7 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm ++ c ; } // edge 3 - else if ( ptToAdd.y >= ptBL.y && ptToAdd.y <= ptTR.y && ptToAdd.x == ptTR.x && abs(vDir.y) > 1 - EPS_SMALL) { + else if ( ptToAdd.y >= ptBL.y && ptToAdd.y <= ptTR.y && ptToAdd.x == ptTR.x && abs( vDir.y) > 1 - EPS_SMALL) { for ( int t = 0 ; t < (int)vEdgeVertex[3].size() ; ++ t) { Point3d ptIntermed = vEdgeVertex[3][t] ; if ( ptIntermed.y < ptToAdd.y && ptIntermed.y > ptLast.y) { @@ -2844,13 +2747,13 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm // sono allineato con un lato, ma NON sono su un lato // aggiungo e basta else { - plTrimmedPoly.AddUPoint( c, ptToAdd); + plTrimmedPoly.AddUPoint( c, ptToAdd) ; ++ c ; } } // non su un edge, quindi aggiungo e basta else { - plTrimmedPoly.AddUPoint( c, ptToAdd); + plTrimmedPoly.AddUPoint( c, ptToAdd) ; ++ c ; } return true ; @@ -2861,19 +2764,19 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm //bool //Tree::SetRightEdgeIn( int nId, std::vector& vEdgeVertex, PolyLine& plTrimmedPoly) //{ -// Point3d ptBr( m_mTree.at(nId).GetTopRight().x , m_mTree.at(nId).GetBottomLeft().y) ; -// Point3d ptTR = m_mTree.at(nId).GetTopRight() ; +// Point3d ptBr( m_mTree.at( nId).GetTopRight().x , m_mTree.at( nId).GetBottomLeft().y) ; +// Point3d ptTR = m_mTree.at( nId).GetTopRight() ; // int nPos0 = -1 , nPos1 = -1 ; // bool bSave = false ; // PNTLIST lPtInt ; // for ( int k = 0 ; k < plTrimmedPoly.GetPointNbr() ; ++ k) { // Point3d ptIter ; // plTrimmedPoly. GetNextPoint( ptIter) ; -// if ( AreSamePointExact( ptIter, ptBr) ) { +// if ( AreSamePointExact( ptIter, ptBr)) { // nPos0 = k ; // bSave = bSave ^ true ; // } -// if ( AreSamePointExact( ptIter, ptTR) ) { +// if ( AreSamePointExact( ptIter, ptTR)) { // nPos1 = k ; // bSave = bSave ^ true ; // } @@ -2883,7 +2786,7 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm // } // lPtInt.pop_front() ; // // verifico se ci sono tutti e due i punti -// if ( nPos0 != -1 && nPos1 != -1 ) { +// if ( nPos0 != -1 && nPos1 != -1) { // // se sono di seguito tutto il lato destro è dentro // if ( nPos1 == nPos0 + 1 || nPos0 == nPos1 + 1) { // m_mTree[nId].m_nRightEdgeIn = 1 ; @@ -2896,7 +2799,7 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm // bool bAllOn = true ; // // PNTLIST::iterator lIter = lPtInt.begin() ; -// std::advance(lIter, 0) ; +// std::advance( lIter, 0) ; // for ( int p = 0 ; p < (int)lPtInt.size() ; ++ p) { // if ( ! clRightEdge.IsPointOn( *lIter)) { // bAllOn = false ; @@ -2923,16 +2826,14 @@ Tree::AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimm //usando le intersezioni con le celle //---------------------------------------------------------------------------- bool -Tree::SetRightEdgeIn( int nId) +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 - Point3d ptBr( m_mTree.at(nId).GetTopRight().x , m_mTree.at(nId).GetBottomLeft().y) ; - Point3d ptTR = m_mTree.at(nId).GetTopRight() ; int nPass = (int) m_mTree[nId].m_vInters.size() ; 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 ) { + if ( m_mTree[nId].m_nFlag == 2) { bool bAllContained = true ; bool bContained = false ; Inters inA ; @@ -2982,7 +2883,7 @@ Tree::SetRightEdgeIn( int nId) bDone = true ; break ; } - else if ( m_mTree[nId].m_vInters[k].nOut == 7 && m_mTree[nId].m_vInters[k].nIn == 6 ) { + else 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 ; @@ -3040,7 +2941,7 @@ Tree::SetRightEdgeIn( int nId) //---------------------------------------------------------------------------- bool -Tree::CategorizeCell( int& nId) +Tree::CategorizeCell( const int& nId) { if ( m_mTree[nId].m_nFlag != -1) { return true ; @@ -3050,7 +2951,7 @@ Tree::CategorizeCell( int& nId) // mi servono i vicini di sinistra per capire se sono dentro il loop o fuori // nRightEdgeIn // 0 right edge fuori, 1 right edge dentro, 2 metà e metà // nFlag // 0 fuori, 1 intersecata, 2 contiene loop, 3 = 1 & 2, 4 dentro - if ( (int)vNeigh.size() == 0 ) { + if ( (int)vNeigh.size() == 0) { m_mTree[nId].m_nFlag = 0 ; } else if ( (int)vNeigh.size() == 1) { @@ -3070,7 +2971,7 @@ Tree::CategorizeCell( int& nId) } // 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 ) { + else if ( m_mTree[vNeigh[0]].m_nRightEdgeIn == 2) { GetBottomNeigh( nId, vNeigh1) ; if ( (int) vNeigh1.size() > 0) { int nNeigh = vNeigh1[0] ; @@ -3085,16 +2986,16 @@ Tree::CategorizeCell( int& nId) m_mTree[nId].m_nFlag = 0 ; else if ( m_mTree[nNeigh].m_nRightEdgeIn == 1) m_mTree[nId].m_nFlag = 4 ; - else if ( m_mTree[nNeigh].m_nRightEdgeIn == 2 ) { + else if ( m_mTree[nNeigh].m_nRightEdgeIn == 2) { // in questo caso devo verificare le intersezioni sul lato destro del vicino bottom // scorro e cerco l'intersezione più alta, se è out la cella è dentro, se è in devo verificare l'out se è più a sinistra o a destra. int nPass = (int) m_mTree[nNeigh].m_vInters.size() ; bool bTopMost = false ; - bool bFound = false; + bool bFound = false ; Point3d ptInters, ptBr( m_mTree[nNeigh].GetTopRight().x, m_mTree[nNeigh].GetBottomLeft().y) ; ptInters = ptBr ; // inizializzato a vertice bottom right - int nEdgeIn = 3, nEdgeOut = 3, nLoop ; - for ( int r = 0 ; r < nPass; ++ r ) { + int nLoop ; + 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 ( 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)) { @@ -3114,7 +3015,7 @@ Tree::CategorizeCell( int& nId) bFound = true ; break ; } - if ( m_mTree[nNeigh].m_vInters[r].nOut == 6 || m_mTree[nNeigh].m_vInters[r].nIn == 6 ) { + if ( m_mTree[nNeigh].m_vInters[r].nOut == 6 || m_mTree[nNeigh].m_vInters[r].nIn == 6) { nLoop = r ; ptInters = ptBr ; bFound = true ; @@ -3124,15 +3025,15 @@ Tree::CategorizeCell( int& nId) bTopMost = true ; } if ( bFound && bTopMost) { - if ( AreSameEdge(m_mTree[nNeigh].m_vInters[nLoop].nIn, 3) && AreSameEdge(m_mTree[nNeigh].m_vInters[nLoop].nOut, 3) ) { + if ( AreSameEdge( m_mTree[nNeigh].m_vInters[nLoop].nIn, 3) && AreSameEdge( m_mTree[nNeigh].m_vInters[nLoop].nOut, 3)) { if ( CheckIfBefore( m_mTree[nNeigh].m_vInters[nLoop])) m_mTree[nId].m_nFlag = 4 ; else m_mTree[nId].m_nFlag = 0 ; } - else if ( AreSameEdge(m_mTree[nNeigh].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) ) { + else if ( AreSameEdge( m_mTree[nNeigh].m_vInters[nLoop].nIn, 3)) { // devo verificare se l'uscita è più a sinistra o più a destra della cella Point3d ptOut = m_mTree[nNeigh].m_vInters[nLoop].vpt.back() ; Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; @@ -3148,21 +3049,18 @@ Tree::CategorizeCell( int& nId) // se non ho vicini bottom devo per forza guardare il vicino a sinistra else { Point3d ptInters = m_mTree[vNeigh[0]].GetTopRight() ; - int nLoop ; int nEdge = 3 ; 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) ) { + 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)) { ptInters = m_mTree[vNeigh[0]].m_vInters[k].vpt[0] ; - nLoop = k ; 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 ( AreSameEdge( m_mTree[vNeigh[0]].m_vInters[k].nOut, 3)) { + if ( CheckIfBefore( nEdge, m_mTree[vNeigh[0]].m_vInters[k].vpt.back(), ptInters)) { ptInters = m_mTree[vNeigh[0]].m_vInters[k].vpt.back() ; - nLoop = k ; bIntersIn = false ; } } @@ -3198,7 +3096,7 @@ Tree::CategorizeCell( int& nId) //---------------------------------------------------------------------------- bool -Tree::CheckIfBetween( Inters& inA, Inters& inB) const +Tree::CheckIfBetween( const Inters& inA, const Inters& inB) const { // controllo se inB è compreso tra l'end e lo start di inA // ( dall'end di A percorro i bordi della cella fino a tornare allo start e devo incontrare In e Out di B) @@ -3220,11 +3118,11 @@ Tree::CheckIfBetween( Inters& inA, Inters& inB) const vEdges.push_back( nEdge) ; 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, 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()) ) { + //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])) bFound = true ; } @@ -3234,27 +3132,28 @@ Tree::CheckIfBetween( Inters& inA, Inters& inB) const bFound = true ; } } - else if ( AreSameEdge(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)) + Point3d ptEnd ; pl.GetLastPoint( ptEnd) ; + if ( CheckIfBefore( i, ptEnd, inB.vpt[0])) bFound = true ; } - else if ( AreSameEdge(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.vpt[0])) + if ( CheckIfBefore( inA.nIn, inB.vpt[0], inA.vpt[0])) 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())) { bFound = true ; } - else if ( ! AreSameEdge(inB.nOut,inB.nIn)) + else if ( ! AreSameEdge( inB.nOut,inB.nIn)) bFound = true ; } - if ( AreSameEdge(inB.nOut, i) && ! bFound && CheckIfBefore(i, inA.vpt[0], inB.vpt.back()) && CheckIfBefore(i, inA.vpt.back(), inB.vpt.back())) + 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 ; @@ -3275,10 +3174,10 @@ Tree::GetLeaves( std::vector& vLeaves) const //---------------------------------------------------------------------------- bool -Tree::OnWhichEdge( int nId, Point3d& ptToAssign, int& nEdge) const +Tree::OnWhichEdge( const int& nId, const Point3d& ptToAssign, int& nEdge) const { - Point3d ptTR = m_mTree.at(nId).GetTopRight() ; - Point3d ptBL = m_mTree.at(nId).GetBottomLeft() ; + Point3d ptTR = m_mTree.at( nId).GetTopRight() ; + Point3d ptBL = m_mTree.at( nId).GetBottomLeft() ; Point3d ptTl ( ptBL.x, ptTR.y) ; Point3d ptBr ( ptTR.x, ptBL.y) ; diff --git a/Tree.h b/Tree.h index cbe70a6..3f79dac 100644 --- a/Tree.h +++ b/Tree.h @@ -68,19 +68,19 @@ class Cell public : ~Cell( void) ; Cell( void) ; - Cell( Point3d& ptBL, Point3d& ptTR) ; + Cell( const Point3d& ptBL, const Point3d& ptTR) ; inline bool IsSame( const Cell& cOtherCell) const ; - void SetBottomLeft( Point3d ptBL) { m_ptPbl = ptBL ; } - void SetTopRight( Point3d ptTR) { m_ptPtr = ptTR ; } - void SetSplitDirVert( bool bVert) { m_bSplitVert = bVert ; } - void SetParent( int nParent) { m_nParent = nParent ; } + void SetBottomLeft( const Point3d ptBL) { m_ptPbl = ptBL ; } + void SetTopRight( const Point3d ptTR) { m_ptPtr = ptTR ; } + void SetSplitDirVert( const bool bVert) { m_bSplitVert = bVert ; } + void SetParent( const int& nParent) { m_nParent = nParent ; } Point3d GetBottomLeft( void) const { return m_ptPbl ; } Point3d GetTopRight( void) const { return m_ptPtr ; } double GetSplitValue( void) const { return m_dSplit ; } bool IsSplitVert( void) const { return m_bSplitVert ; } // se true la cella verrebbe splittata verticalmente, sennò orizzontalmente bool IsLeaf( void) const ; // flag che indica se la cella ha figli o se è una foglia bool IsProcessed( void) const { return m_bProcessed ; } // flag che indica se tutti i figli della cella, se ce ne sono, sono stati processati - void SetProcessed( bool bProcessed = true) { m_bProcessed = bProcessed ; } + void SetProcessed( const bool bProcessed = true) { m_bProcessed = bProcessed ; } static bool minorX ( const Cell& c1, const Cell& c2) { return c1.m_ptPbl.x < c2.m_ptPbl.x ; } static bool minorY ( const Cell& c1, const Cell& c2) { return c1.m_ptPbl.y < c2.m_ptPbl.y ; } @@ -99,7 +99,6 @@ 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à - //INTVECTOR m_vnLoop ; // indice dei loop contenuti nella cella 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 @@ -116,47 +115,46 @@ class Tree public : ~Tree( void) ; Tree( void) ; - Tree ( const SurfBezier* pSrfBz, bool bSplitPatches = true) ; - void SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches = true) ; - bool BuildTree( double dLinTol = LIN_TOL_STD, double dSideMin = 5, double dSideMax = INFINITO) ; // dSideMax è il massimo per la dimensione maggiore di un triangolo della trimesh + 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 // dSideMin è lunghezza minima del lato di una cella nello spazio reale - bool BuildTree_test( double dLinTol = LIN_TOL_STD, double dSideMin = 5, double dSideMax = INFINITO) ; + bool BuildTree_test( const double dLinTol = LIN_TOL_STD, const double dSideMin = 5, 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 bool GetLeaves ( std::vector& vLeaves) const ; private : - void Split( int nId, double dSplitValue) ; // funzione di split di una cella al parametro indicato nella direzione data da bVert - void Split( int nId) ; // funzione di split di una cella dell'albero a metà nella direzione data da bVert + void Split( const int& nId, const double& dSplitValue) ; // funzione di split di una cella al parametro indicato nella direzione data da bVert + void Split( const int& nId) ; // funzione di split di una cella dell'albero a metà nella direzione data da bVert void Balance () ; // creo rami in modo che tutte tutte le foglie abbiano come adiacenti foglie ad una profonditù di +- 1 - int GetHeightLeaves ( int nId, INTVECTOR& vnLeaves, int d = 0) const ; // altezza del subtree a partire dal nodo nId - int GetDepth ( int nId, int nRef) const ; // livello del nodo nId - void GetTopNeigh( int nId, INTVECTOR& vTopNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato top - void GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato bottom - void GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato left - void GetRightNeigh( int nId, INTVECTOR& vRightNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato right - void GetRootNeigh( int nEdge, INTVECTOR& vNeigh) ; // restituisce le foglie dell'albero che sono adiacenti al lato nEdge, numerato a partire dal top ( 0) in senso antiorario + int GetHeightLeaves ( const int& nId, INTVECTOR& vnLeaves, int d = 0) const ; // altezza del subtree a partire dal nodo nId + int GetDepth ( const int& nId, const int& nRef) const ; // livello del nodo nId + void GetTopNeigh( const int& nId, INTVECTOR& vTopNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato top + void GetBottomNeigh( const int& nId, INTVECTOR& vBottomNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato bottom + void GetLeftNeigh( const int& nId, INTVECTOR& vLeftNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato left + void GetRightNeigh( const int& nId, INTVECTOR& vRightNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato right + void GetRootNeigh( const int& nEdge, INTVECTOR& vNeigh) ; // restituisce le foglie dell'albero che sono adiacenti al lato nEdge, numerato a partire dal top ( 0) in senso antiorario void ResetTree ( void) ; // resetto m_bProcessed a false per tutti i nodi dell'albero - INTVECTOR FindCell ( const Point3d& ptToAssign, CurveLine& cl) const ; // dato un punto, trova la cella foglia a cui appartiene - INTVECTOR FindCell ( const Point3d& ptToAssign, CurveLine& cl, INTVECTOR vCells) const ; // dato un punto, trova la cella foglia a cui appartiene + INTVECTOR FindCell ( const Point3d& ptToAssign, const CurveLine& cl) const ; // dato un punto, trova la cella foglia a cui appartiene + INTVECTOR FindCell ( const Point3d& ptToAssign, const CurveLine& cl, INTVECTOR vCells) const ; // dato un punto, trova la cella foglia a cui appartiene bool TraceLoopLabelCell( void) ; // tracing dei loop e labelling delle celle - bool FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool bFirstInters = true) ; // trova le intersezioni tra una cella e una linea di trim + bool FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool bFirstInters = true) ; // trova le intersezioni tra una cella e una linea di trim // resituisce l'id della cella verso cui la curva di trim esce e il vettore delle intersezioni per la cella successiva con il primo punto - bool CreateCellPolygons ( int nLeafId, std::vector& vPolygons, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk, PolyLine plCell) ; - bool CreateIslandAndHoles ( int nLeafId, std::vector& vPolygons, int& nPoly, INTVECTOR& vnParentChunk) ; - bool CheckIfBefore( PolyLine& pl, int nEdge) const ; - bool CheckIfBefore( Inters& inA) const ; - bool CheckIfBefore( int& nEdge1, Point3d& ptP1, int& nEdge2, Point3d& ptP2) const ; - bool CheckIfBefore( int& nEdge, Point3d& ptP1, Point3d& ptP2) const ; - bool CheckIfAfter( PolyLine& pl, Point3d& ptNextStart, int nEdge) const ; - bool AreSameEdge( int nEdge1, int nEdge2) const ; - bool AddVertex( int nId, std::vector& vEdgeVertex, PolyLine& plTrimmedPoly, int& c, Point3d& ptToAdd) const ; + bool CreateCellPolygons ( const int& nLeafId, std::vector& vPolygons, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk, const PolyLine& plCell) ; + 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 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) ; - bool SetRightEdgeIn( int nId) ; - bool CategorizeCell( int& nId) ; - bool CheckIfBetween( Inters& inA, Inters& inB) const ; - bool OnWhichEdge( int nId, Point3d& ptToAssign, int& nEdge) const ; + bool SetRightEdgeIn( const int& nId) ; + bool CategorizeCell( const int& nId) ; + bool CheckIfBetween( const Inters& inA, const Inters& inB) const ; + bool OnWhichEdge( const int& nId, const Point3d& ptToAssign, int& nEdge) const ; private : const SurfBezier* m_pSrfBz ; // superficie di bezier @@ -164,7 +162,6 @@ private : bool m_bTrimmed ; // superficie trimmata std::vector m_vChunk ; // elenco dei loop divisi per chunk std::map m_mChunk ; - //std::vector m_vLoop ; ICURVEPOVECTOR m_vLoop ; // curve di loop. la 0 è il bordo dello spazio parametrico, le altre sono i loop interni bool m_bBilinear ; // superficie bilineare bool m_bMulti ; // superficie multi-patch @@ -174,8 +171,7 @@ private : int m_nDegV ; // grado della superficie nel parametro V int m_nSpanU ; int m_nSpanV ; - std::vector m_vPolygons ; // vettore dei poligoni del tree - //std::map m_mPolygons ; // mappa dei poligoni + std::vector m_vPolygons ; // vettore dei poligoni del tree std::map m_mTree ; // mappa che contiene tutti i nodi e le foglie dell'albero. -2 è puntatore Null e -1 è root std::map m_mVert ; // mappa che contiene tutti i vertici 3d delle celle del tree. L'Id è lo stesso che la cella ha in m_mTree INTVECTOR m_vnLeaves ; // vettore delle foglie From ebda605497a9415c06a8a38ead3f359b141641ac Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 19 Jun 2023 08:50:47 +0200 Subject: [PATCH 19/44] EgftGeomKernel : - sistemati i bug noti - pulito il codice Da aggiungere : - calcolo del tree solo nelle bbox delle curve di trim --- Tree.cpp | 668 +++++++++++++++++++++++++++---------------------------- Tree.h | 7 +- 2 files changed, 336 insertions(+), 339 deletions(-) diff --git a/Tree.cpp b/Tree.cpp index c4022ed..6017b2e 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -115,19 +115,46 @@ Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches) // 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 dAngTolDeg = 5 ; for ( int i = 0 ; i < pTrimReg->GetChunkCount() ; ++ i) { PtrOwner pChunk( pTrimReg->CloneChunk( i)) ; for ( int j = 0 ; j < pChunk->GetLoopCount( 0) ; ++ j) { vChunk.push_back( nLoop) ; - // i chunk della superficie orignale non possono avere dei sub chunk + // i chunk della falt region sono ancora flat region composte da 1 chunk PtrOwner pLoop ( pChunk->GetLoop( 0, j)) ; + PtrOwner pCrv( pLoop->Clone()) ; m_vLoop.emplace_back( Release( pLoop)) ; m_mChunk[nLoop] = i ; ++ nLoop ; + // approssimo i loop di trim con delle spezzate + PolyLine plApprox ; + int nType = 0 ; + pCrv->ApproxWithLines( dLinTol,dAngTolDeg, nType, plApprox) ; + // calcolo se il loop è CCW o CW + double dArea ; + Plane3d plExtPlane ; + bool bCCW ; + plApprox.IsClosedAndFlat( plExtPlane, dArea, 50 * EPS_SMALL) ; + if ( plExtPlane.GetVersN().z > 0) + bCCW = true ; + else + bCCW = false ; + m_vPlApprox.push_back( std::tuple(plApprox,bCCW)) ; } + // li riordino dal più grande al più piccolo + std::sort(vChunk.begin(), vChunk.end(), [this]( const int& a, const int& b) { double dArea1, dArea2 ; + m_vLoop[a]->GetAreaXY( dArea1) ; + m_vLoop[b]->GetAreaXY( dArea2) ; + return dArea1 > dArea2 ;}) ; m_vChunk.push_back( vChunk) ; vChunk.clear() ; } + // li riordino dal più grande al più piccolo + std::sort(m_vChunk.begin(), m_vChunk.end(), [this]( const INTVECTOR& a, const INTVECTOR& b) { double dArea1, dArea2 ; + m_vLoop[a[0]]->GetAreaXY( dArea1) ; + m_vLoop[b[0]]->GetAreaXY( dArea2) ; + return dArea1 > dArea2 ;}) ; } // salvo i vertici 3d della cella root Point3d ptBottom ( 0, 0) ; @@ -350,7 +377,7 @@ Tree::Split( const int& nId) //---------------------------------------------------------------------------- bool -Tree::BuildTree_test( double dLinTol_, double dSideMin, double dSideMax) +Tree::BuildTree_test( const double& dLinTol, const double& dSideMin, const double& dSideMax) { //int nCToSplit = -1 ; //celle 0,1 @@ -410,337 +437,328 @@ Tree::BuildTree_test( double dLinTol_, double dSideMin, double dSideMax) //---------------------------------------------------------------------------- bool -Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) +Tree::BuildTree( const double& dLinTol, const double& dSideMin, const double& dSideMax) { - // suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri + // suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri int nCToSplit = -1 ; - //double dLinTol = 0.2 ; - //double dSideMin = 1 ; - if ( ! m_bTrimmed || m_bTrimmed) { - if ( ! m_bBilinear) { - while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { - // controllo che la cella non sia già stata preliminarmente splittata - if ( m_mTree[nCToSplit].IsLeaf()) { - // calcolo in quale direzione ho più curvatura - // ptP00P10 è un punto tra P00 e P10 - double dCurvU = 0, dCurvV = 0 ; - double dLenParU = ( m_mTree[nCToSplit].GetTopRight().x - m_mTree[nCToSplit].GetBottomLeft().x) / SBZ_TREG_COEFF ; - double dLenParV = ( m_mTree[nCToSplit].GetTopRight().y - m_mTree[nCToSplit].GetBottomLeft().y) / SBZ_TREG_COEFF ; - if ( dLenParU <= 1. / m_nDegV || dLenParV <= 1. / m_nDegU) { - double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 / SBZ_TREG_COEFF ; + if ( ! m_bBilinear) { + while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { + // controllo che la cella non sia già stata preliminarmente splittata + if ( m_mTree[nCToSplit].IsLeaf()) { + // calcolo in quale direzione ho più curvatura + // ptP00P10 è un punto tra P00 e P10 + double dCurvU = 0, dCurvV = 0 ; + double dLenParU = ( m_mTree[nCToSplit].GetTopRight().x - m_mTree[nCToSplit].GetBottomLeft().x) / SBZ_TREG_COEFF ; + double dLenParV = ( m_mTree[nCToSplit].GetTopRight().y - m_mTree[nCToSplit].GetBottomLeft().y) / SBZ_TREG_COEFF ; + if ( dLenParU <= 1. / m_nDegV || dLenParV <= 1. / m_nDegU) { + double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 / SBZ_TREG_COEFF ; + double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 / SBZ_TREG_COEFF ; + double dULoc = 0.5, dVLoc = 0.5 ; + Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00 ; + m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x / SBZ_TREG_COEFF, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x / SBZ_TREG_COEFF, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; + Point3d ptV = ( 1 - dULoc) * ptP00P10 + dULoc * ptP11P01 ; + Point3d ptU = ( 1 - dVLoc) * ptP10P11 + dVLoc * ptP01P00 ; + dCurvV = Dist( ptV, ptPSrf) ; + dCurvU = Dist( ptU, ptPSrf) ; + } + // faccio un'analisi più fine della curvatura se almeno il grado di una curva di uno dei due parametri è alto e + // se sto ancora guardando una cella abbastanza grande + else{ + Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00, ptPSrfMid ; + double dStep = 1. / m_nDegU ; + for ( double k = dStep ; k < 1 ; k = k + dStep) { + double dU = ( k * m_mTree[nCToSplit].GetTopRight().x + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().x) / SBZ_TREG_COEFF ; double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 / SBZ_TREG_COEFF ; - double dULoc = 0.5, dVLoc = 0.5 ; - Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00 ; m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + if ( k == 0.5) + ptPSrfMid = ptPSrf ; m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x / SBZ_TREG_COEFF, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x / SBZ_TREG_COEFF, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; - Point3d ptV = ( 1 - dULoc) * ptP00P10 + dULoc * ptP11P01 ; - Point3d ptU = ( 1 - dVLoc) * ptP10P11 + dVLoc * ptP01P00 ; - dCurvV = Dist( ptV, ptPSrf) ; - dCurvU = Dist( ptU, ptPSrf) ; + CurveLine clV ; + clV.Set( ptP00P10, ptP11P01) ; + DistPointCurve dpc( ptPSrf, clV) ; + double dDist ; + dpc.GetDist( dDist) ; + dCurvV = std::max( dCurvV, dDist) ; } - // faccio un'analisi più fine della curvatura se almeno il grado di una curva di uno dei due parametri è alto e - // se sto ancora guardando una cella abbastanza grande - else{ - Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00, ptPSrfMid ; - double dStep = 1. / m_nDegU ; - for ( double k = dStep ; k < 1 ; k = k + dStep) { - double dU = ( k * m_mTree[nCToSplit].GetTopRight().x + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().x) / SBZ_TREG_COEFF ; - double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 / SBZ_TREG_COEFF ; + dStep = 1. / m_nDegV ; + for ( double k = dStep ; k < 1 ; k = k + dStep) { + double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 / SBZ_TREG_COEFF ; + double dV = ( k * m_mTree[nCToSplit].GetTopRight().y + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().y) / SBZ_TREG_COEFF ; + if ( k == 0.5) + ptPSrf = ptPSrfMid ; + else m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - if ( k == 0.5) - ptPSrfMid = ptPSrf ; - m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; - m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; - CurveLine clV ; - clV.Set( ptP00P10, ptP11P01) ; - DistPointCurve dpc( ptPSrf, clV) ; - double dDist ; - dpc.GetDist( dDist) ; - dCurvV = std::max( dCurvV, dDist) ; - } - dStep = 1. / m_nDegV ; - for ( double k = dStep ; k < 1 ; k = k + dStep) { - double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 / SBZ_TREG_COEFF ; - double dV = ( k * m_mTree[nCToSplit].GetTopRight().y + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().y) / SBZ_TREG_COEFF ; - if ( k == 0.5) - ptPSrf = ptPSrfMid ; - else - m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x / SBZ_TREG_COEFF, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x / SBZ_TREG_COEFF, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; - CurveLine clU ; - clU.Set( ptP01P00, ptP10P11) ; - DistPointCurve dpc( ptPSrf, clU) ; - double dDist ; - dpc.GetDist( dDist) ; - dCurvU = std::max( dCurvU, dDist) ; - } + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x / SBZ_TREG_COEFF, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x / SBZ_TREG_COEFF, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; + CurveLine clU ; + clU.Set( ptP01P00, ptP10P11) ; + DistPointCurve dpc( ptPSrf, clU) ; + double dDist ; + dpc.GetDist( dDist) ; + dCurvU = std::max( dCurvU, dDist) ; } + } - // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza - // misura approssimativa della curvatura in una direzione - bool bVert ; - if ( dCurvV > dCurvU) { - // lungo la direzione V ho una curvatura maggiore - bVert = false ; + // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza + // misura approssimativa della curvatura in una direzione + bool bVert ; + if ( dCurvV > dCurvU) { + // lungo la direzione V ho una curvatura maggiore + bVert = false ; + } + else { + // lungo la direzione U ho una curvatura maggiore + bVert = true ; + } + m_mTree[nCToSplit].SetSplitDirVert( bVert) ; + Point3d ptP00, ptP10, ptP11, ptP01 ; + // distanza reale tra i vertici della cella + ptP00 = m_mVert[nCToSplit][0] ; + ptP10 = m_mVert[nCToSplit][1] ; + ptP11 = m_mVert[nCToSplit][2] ; + ptP01 = m_mVert[nCToSplit][3] ; + double dLen0 = Dist( ptP00, ptP10) ; + double dLen1 = Dist( ptP10, ptP11) ; + double dLen2 = Dist( ptP01, ptP11) ; + double dLen3 = Dist( ptP00, ptP01) ; + // 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) ; + else + dSideMinVal = std::max( dLen0, dLen2) ; + } + else { + if ( dLen1 != 0 && dLen3 != 0) + dSideMinVal = std::max( dLen1, dLen3) ; + else + dSideMinVal = std::max( dLen1, dLen3) ; + } + // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella + dSideMaxVal = std::max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; + + // 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)) { + CurveLine cl0010, cl0001, cl1011, cl0111 ; + // U=0 + cl0010.Set( ptP00, ptP10) ; + // U=1 + cl0111.Set( ptP01, ptP11) ; + Point3d pt0010, pt0111, ptBz0, ptBz1, ptBzV ; + int nFlag ; + CurveLine clV ; + // determino quanti Step fare per ogni direzione parametrica + double dDimU = ( dLen0 >= dLen2 ? dLen0 / m_vDim[0] : dLen2 / m_vDim[2]) ; + dDimU = ( dDimU > 1 ? 1 : dDimU) ; + double dDimV = ( dLen1 >= dLen3 ? dLen1 / m_vDim[1] : dLen3 / m_vDim[3]) ; + dDimV = ( dDimV > 1 ? 1 : dDimV) ; + // numero di Step per campionare la superficie nelle due direzioni parametriche + int nStepsU = int( 51 * dDimU + 5 * ( 1 - dDimU)) ; + int nStepsV = int( 51 * dDimV + 5 * ( 1 - dDimV)) ; + for ( int u = 0 ; u < nStepsU && ! bSplit ; ++ u) { + double dU = double ( u) / double ( nStepsU - 1) ; + double dULoc = ( ( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x) / SBZ_TREG_COEFF ; + 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) ; + clV.Set( pt0010, pt0111) ; + for ( int v = 0 ; v < nStepsV ; ++ v) { + double dV = double ( v) / double ( nStepsV - 1) ; + double dVLoc = ( ( 1 - dV) * m_mTree[nCToSplit].GetBottomLeft().y + dV * m_mTree[nCToSplit].GetTopRight().y) / SBZ_TREG_COEFF ; + if ( ! m_pSrfBz->GetPointD1D2( dULoc, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBzV)) + return false ; + DistPointCurve dpc( ptBzV, clV) ; + // distanza di approssimazione locale + double dDist ; + dpc.GetDist( dDist) ; + if ( dDist > dLinTol) { + bSplit = true ; + break ; + } + } } - else { - // lungo la direzione U ho una curvatura maggiore + } + + if ( bSplit || dSideMaxVal > dSideMax) { + m_mTree[nCToSplit].SetSplitDirVert( bVert) ; + // effettuo lo split + Split( nCToSplit) ; + + // procedo con lo split del Child1 + nCToSplit = m_mTree[nCToSplit].m_nChild1 ; + } + else { + // sono arrivato ad una cella Leaf, quindi salvo la cella + m_vnLeaves.push_back( nCToSplit) ; + m_mTree[nCToSplit].SetProcessed() ; + // risalgo i parent finché non trovo il primo Child2 da processare + nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( nCToSplit == -2) + return true ; + if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + m_mTree[nCToSplit].SetProcessed() ; + while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { + if ( m_mTree[nCToSplit].m_nParent != -2) + nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + m_mTree[nCToSplit].SetProcessed() ; + if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + break ; + } + nCToSplit = m_mTree[nCToSplit].m_nChild2 ; + } + } + else { + nCToSplit = m_mTree[nCToSplit].m_nChild1 ; + } + } + Balance() ; // da implementare quando dividerò ad un parametro a scelta e non a metà + } + // bilineare + else { + while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { + if ( m_mTree[nCToSplit].IsLeaf()) { + // vertici della cella + Point3d ptP00, ptP10, ptP11, ptP01 ; + ptP00 = m_mVert[nCToSplit][0] ; + ptP10 = m_mVert[nCToSplit][1] ; + ptP11 = m_mVert[nCToSplit][2] ; + ptP01 = m_mVert[nCToSplit][3] ; + // distanza reale tra i vertici della cella + double dLen0 = Dist( ptP00, ptP10) ; + double dLen1 = Dist( ptP10, ptP11) ; + double dLen2 = Dist( ptP01, ptP11) ; + double dLen3 = Dist( ptP00, ptP01) ; + + bool bVert = false ; + // calcolo in quale direzione è meglio dividere in base allo stretch + Point3d ptPSrfU, ptPSrfV ; + double dU = 0, dV = 0 ; + double dDistU = 0, dDistV = 0 ; + PNTVECTOR vPtU, vPtV ; + if ( ! m_bMulti) { + if ( std::max( dLen0, dLen2) > std::max( dLen1, dLen3)) { bVert = true ; } - m_mTree[nCToSplit].SetSplitDirVert( bVert) ; - Point3d ptP00, ptP10, ptP11, ptP01 ; - // distanza reale tra i vertici della cella - ptP00 = m_mVert[nCToSplit][0] ; - ptP10 = m_mVert[nCToSplit][1] ; - ptP11 = m_mVert[nCToSplit][2] ; - ptP01 = m_mVert[nCToSplit][3] ; - double dLen0 = Dist( ptP00, ptP10) ; - double dLen1 = Dist( ptP10, ptP11) ; - double dLen2 = Dist( ptP01, ptP11) ; - double dLen3 = Dist( ptP00, ptP01) ; - // 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) ; - else - dSideMinVal = std::max( dLen0, dLen2) ; - } else { - if ( dLen1 != 0 && dLen3 != 0) - dSideMinVal = std::max( dLen1, dLen3) ; - else - dSideMinVal = std::max( dLen1, dLen3) ; - } - // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella - dSideMaxVal = std::max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; - - // 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)) { - CurveLine cl0010, cl0001, cl1011, cl0111 ; - // U=0 - cl0010.Set( ptP00, ptP10) ; - // U=1 - cl0111.Set( ptP01, ptP11) ; - Point3d pt0010, pt0111, ptBz0, ptBz1, ptBzV ; - int nFlag ; - CurveLine clV ; - // determino quanti Step fare per ogni direzione parametrica - double dDimU = ( dLen0 >= dLen2 ? dLen0 / m_vDim[0] : dLen2 / m_vDim[2]) ; - dDimU = ( dDimU > 1 ? 1 : dDimU) ; - double dDimV = ( dLen1 >= dLen3 ? dLen1 / m_vDim[1] : dLen3 / m_vDim[3]) ; - dDimV = ( dDimV > 1 ? 1 : dDimV) ; - // numero di Step per campionare la superficie nelle due direzioni parametriche - int nStepsU = int( 51 * dDimU + 5 * ( 1 - dDimU)) ; - int nStepsV = int( 51 * dDimV + 5 * ( 1 - dDimV)) ; - for ( int u = 0 ; u < nStepsU && ! bSplit ; ++ u) { - double dU = double ( u) / double ( nStepsU - 1) ; - double dULoc = ( ( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x) / SBZ_TREG_COEFF ; - 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) ; - clV.Set( pt0010, pt0111) ; - for ( int v = 0 ; v < nStepsV ; ++ v) { - double dV = double ( v) / double ( nStepsV - 1) ; - double dVLoc = ( ( 1 - dV) * m_mTree[nCToSplit].GetBottomLeft().y + dV * m_mTree[nCToSplit].GetTopRight().y) / SBZ_TREG_COEFF ; - if ( ! m_pSrfBz->GetPointD1D2( dULoc, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBzV)) - return false ; - DistPointCurve dpc( ptBzV, clV) ; - // distanza di approssimazione locale - double dDist ; - dpc.GetDist( dDist) ; - if ( dDist > dLinTol) { - bSplit = true ; - break ; - } - } - } - } - - if ( bSplit || dSideMaxVal > dSideMax) { - m_mTree[nCToSplit].SetSplitDirVert( bVert) ; - // effettuo lo split - Split( nCToSplit) ; - - // procedo con lo split del Child1 - nCToSplit = m_mTree[nCToSplit].m_nChild1 ; - } - else { - // sono arrivato ad una cella Leaf, quindi salvo la cella - m_vnLeaves.push_back( nCToSplit) ; - m_mTree[nCToSplit].SetProcessed() ; - // risalgo i parent finché non trovo il primo Child2 da processare - nCToSplit = m_mTree[nCToSplit].m_nParent ; - if ( nCToSplit == -2) - return true ; - if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) - m_mTree[nCToSplit].SetProcessed() ; - while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { - if ( m_mTree[nCToSplit].m_nParent != -2) - nCToSplit = m_mTree[nCToSplit].m_nParent ; - if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) - m_mTree[nCToSplit].SetProcessed() ; - if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) - break ; - } - nCToSplit = m_mTree[nCToSplit].m_nChild2 ; + bVert = false ; } } else { - nCToSplit = m_mTree[nCToSplit].m_nChild1 ; + for ( double i = 0.25 ; i < 1 ; i = i + 0.25) { + dU = ( ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().x + i * m_mTree[nCToSplit].GetTopRight().x) / SBZ_TREG_COEFF ; + dV = ( ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().y + i * m_mTree[nCToSplit].GetTopRight().y) / SBZ_TREG_COEFF ; + double dVLoc = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 / SBZ_TREG_COEFF ; + double dULoc = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 / SBZ_TREG_COEFF ; + m_pSrfBz->GetPointD1D2( dU, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfU) ; + m_pSrfBz->GetPointD1D2( dULoc, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfV) ; + vPtU.push_back( ptPSrfU) ; + vPtV.push_back( ptPSrfV) ; + } + // devo guardare se i tre punti in vPtU e vPtV sono allineati + CurveLine clU, clV ; + clU.Set( vPtU[0], vPtU[1]) ; + clV.Set( vPtV[0], vPtV[1]) ; + DistPointCurve dpcU( vPtU[2], clU, false) ; + DistPointCurve dpcV( vPtV[2], clV, false) ; + dpcU.GetDist( dDistU) ; + dpcV.GetDist( dDistV) ; + if ( dDistU > dDistV) { + bVert = true ; + } + else { + bVert = false ; + } } - } - Balance() ; // da implementare quando dividerò ad un parametro a scelta e non a metà - } - // bilineare - else { - while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { - if ( m_mTree[nCToSplit].IsLeaf()) { - // vertici della cella - Point3d ptP00, ptP10, ptP11, ptP01 ; - ptP00 = m_mVert[nCToSplit][0] ; - ptP10 = m_mVert[nCToSplit][1] ; - ptP11 = m_mVert[nCToSplit][2] ; - ptP01 = m_mVert[nCToSplit][3] ; - // distanza reale tra i vertici della cella - double dLen0 = Dist( ptP00, ptP10) ; - double dLen1 = Dist( ptP10, ptP11) ; - double dLen2 = Dist( ptP01, ptP11) ; - double dLen3 = Dist( ptP00, ptP01) ; - - bool bVert = false ; - // calcolo in quale direzione è meglio dividere in base allo stretch - Point3d ptPSrfU, ptPSrfV ; - double dU = 0, dV = 0 ; - double dDistU = 0, dDistV = 0 ; - PNTVECTOR vPtU, vPtV ; - if ( ! m_bMulti) { - if ( std::max( dLen0, dLen2) > std::max( dLen1, dLen3)) { - bVert = true ; - } - else { - bVert = false ; - } - } - else { - for ( double i = 0.25 ; i < 1 ; i = i + 0.25) { - dU = ( ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().x + i * m_mTree[nCToSplit].GetTopRight().x) / SBZ_TREG_COEFF ; - dV = ( ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().y + i * m_mTree[nCToSplit].GetTopRight().y) / SBZ_TREG_COEFF ; - double dVLoc = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 / SBZ_TREG_COEFF ; - double dULoc = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 / SBZ_TREG_COEFF ; - m_pSrfBz->GetPointD1D2( dU, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfU) ; - m_pSrfBz->GetPointD1D2( dULoc, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfV) ; - vPtU.push_back( ptPSrfU) ; - vPtV.push_back( ptPSrfV) ; - } - // devo guardare se i tre punti in vPtU e vPtV sono allineati - CurveLine clU, clV ; - clU.Set( vPtU[0], vPtU[1]) ; - clV.Set( vPtV[0], vPtV[1]) ; - DistPointCurve dpcU( vPtU[2], clU, false) ; - DistPointCurve dpcV( vPtV[2], clV, false) ; - dpcU.GetDist( dDistU) ; - dpcV.GetDist( dDistV) ; - if ( dDistU > dDistV) { - bVert = true ; - } - else { - bVert = false ; - } - } - // verifico che la cella sia abbastanza grande da poter essere splittata - double dSideMinVal = 0, dSideMaxVal = 0 ; - if ( bVert) { - if ( dLen0 != 0 && dLen2 != 0) - dSideMinVal = std::max( dLen0, dLen2) ; - else - dSideMinVal = std::max( dLen0, dLen2) ; - } - else { - if ( dLen1 != 0 && dLen3 != 0) - dSideMinVal = std::max( dLen1, dLen3) ; - else - dSideMinVal = std::max( dLen1, dLen3) ; - } - // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella - dSideMaxVal = std::max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; + // verifico che la cella sia abbastanza grande da poter essere splittata + double dSideMinVal = 0, dSideMaxVal = 0 ; + if ( bVert) { + if ( dLen0 != 0 && dLen2 != 0) + dSideMinVal = std::max( dLen0, dLen2) ; + else + dSideMinVal = std::max( dLen0, dLen2) ; + } + else { + if ( dLen1 != 0 && dLen3 != 0) + dSideMinVal = std::max( dLen1, dLen3) ; + else + dSideMinVal = std::max( dLen1, dLen3) ; + } + // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella + dSideMaxVal = std::max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; - double dErr = 0 ; - if ( m_bMulti) { - Point3d ptPSrf ; - Plane3d plAppr ; - if ( ! AreSamePointApprox( ptP00, ptP10) && ! AreSamePointApprox( ptP00, ptP01)) - plAppr.Set( ptP00, ( ptP00 - ptP01) ^ ( ptP00 - ptP10)) ; - else if ( AreSamePointApprox( ptP00, ptP10)) { - plAppr.Set( ptP01, ( ptP00 - ptP01) ^ ( ptP01 - ptP11)) ; - } - else if ( AreSamePointApprox( ptP00, ptP01)) { - plAppr.Set( ptP10, ( ptP10 - ptP11) ^ ( ptP00 - ptP10)) ; - } - for ( double i = 0.25 ; i < 1 ; i = i + 0.25) { - for ( double j = 0.25 ; j < 1 ; j = j + 0.25) { - double dU = ( ( 1 - i) * m_mTree[nCToSplit].GetTopRight().x + i * m_mTree[nCToSplit].GetBottomLeft().x) / SBZ_TREG_COEFF ; - double dV = ( ( 1 - j) * m_mTree[nCToSplit].GetTopRight().y + j * m_mTree[nCToSplit].GetBottomLeft().y) / SBZ_TREG_COEFF ; - m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - dErr = std::max( abs( DistPointPlane( ptPSrf, plAppr)), dErr) ; - } - } + double dErr = 0 ; + if ( m_bMulti) { + Point3d ptPSrf ; + Plane3d plAppr ; + if ( ! AreSamePointApprox( ptP00, ptP10) && ! AreSamePointApprox( ptP00, ptP01)) + plAppr.Set( ptP00, ( ptP00 - ptP01) ^ ( ptP00 - ptP10)) ; + else if ( AreSamePointApprox( ptP00, ptP10)) { + plAppr.Set( ptP01, ( ptP00 - ptP01) ^ ( ptP01 - ptP11)) ; } - else { - dErr = 1. / 4. * ( ( ptP00 - ptP01) + ( ptP11 - ptP10)).Len() ; + else if ( AreSamePointApprox( ptP00, ptP01)) { + plAppr.Set( ptP10, ( ptP10 - ptP11) ^ ( ptP00 - ptP10)) ; } - // se la cella è abbastanza grande da poter essere divisa ancora e devo approssimare meglio, la divido - if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && dErr > dLinTol) { - m_mTree[nCToSplit].SetSplitDirVert( bVert) ; - // effettuo lo split - Split( nCToSplit) ; - - // procedo con lo split del Child1 - nCToSplit = m_mTree[nCToSplit].m_nChild1 ; - } - else { - // sono arrivato ad una cella Leaf, quindi salvo la cella - m_vnLeaves.push_back( nCToSplit) ; - m_mTree[nCToSplit].SetProcessed() ; - // risalgo i parent finché non trovo il primo Child2 da processare - nCToSplit = m_mTree[nCToSplit].m_nParent ; - if ( nCToSplit == -2) - return true ; - if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) - m_mTree[nCToSplit].SetProcessed() ; - while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { - if ( m_mTree[nCToSplit].m_nParent != -2) - nCToSplit = m_mTree[nCToSplit].m_nParent ; - if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) - m_mTree[nCToSplit].SetProcessed() ; - if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) - break ; + for ( double i = 0.25 ; i < 1 ; i = i + 0.25) { + for ( double j = 0.25 ; j < 1 ; j = j + 0.25) { + double dU = ( ( 1 - i) * m_mTree[nCToSplit].GetTopRight().x + i * m_mTree[nCToSplit].GetBottomLeft().x) / SBZ_TREG_COEFF ; + double dV = ( ( 1 - j) * m_mTree[nCToSplit].GetTopRight().y + j * m_mTree[nCToSplit].GetBottomLeft().y) / SBZ_TREG_COEFF ; + m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + dErr = std::max( abs( DistPointPlane( ptPSrf, plAppr)), dErr) ; } - nCToSplit = m_mTree[nCToSplit].m_nChild2 ; } } else { + dErr = 1. / 4. * ( ( ptP00 - ptP01) + ( ptP11 - ptP10)).Len() ; + } + // se la cella è abbastanza grande da poter essere divisa ancora e devo approssimare meglio, la divido + if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && dErr > dLinTol) { + m_mTree[nCToSplit].SetSplitDirVert( bVert) ; + // effettuo lo split + Split( nCToSplit) ; + + // procedo con lo split del Child1 nCToSplit = m_mTree[nCToSplit].m_nChild1 ; } + else { + // sono arrivato ad una cella Leaf, quindi salvo la cella + m_vnLeaves.push_back( nCToSplit) ; + m_mTree[nCToSplit].SetProcessed() ; + // risalgo i parent finché non trovo il primo Child2 da processare + nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( nCToSplit == -2) + return true ; + if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + m_mTree[nCToSplit].SetProcessed() ; + while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { + if ( m_mTree[nCToSplit].m_nParent != -2) + nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + m_mTree[nCToSplit].SetProcessed() ; + if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + break ; + } + nCToSplit = m_mTree[nCToSplit].m_nChild2 ; + } + } + else { + nCToSplit = m_mTree[nCToSplit].m_nChild1 ; } } } - // NON IMPLEMENTATO - // se la superficie è trimmata creo l'albero solo all'interno dei bbox delle curve di trim ( se ho solo trim CW allora tengo il bordo) - else { - SurfFlatRegion sfrTrimReg ; - } return true ; } @@ -1225,7 +1243,7 @@ Tree::GetPolygons( std::vector& vPolygons) { int nPoly = 0 ; // scorro sui vettori intersezione della cella nId e sui suoi vertici // in questo for analizzo solo i loop che tagliano la cella - while( nPoly == 0 || (int)vToCheck.size() != 0) { + while( (int)vToCheck.size() != 0) { int nPolyBefore = nPoly ; CreateCellPolygons( i, vPolygons, vToCheck, nPoly, vnParentChunk, vPolygonsBasic[i]) ; if ( nPolyBefore == nPoly) @@ -1455,35 +1473,15 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& cl, INTVECTOR vCells bool Tree::TraceLoopLabelCell( void) { - // approssimo i loop di trim con delle spezzate - POLYLINEVECTOR vPlApprox ; - for ( int p = 0 ; p < (int) m_vLoop.size() ; ++ p){ - PtrOwner pCrv( m_vLoop[p]->Clone()) ; - double dLinTol = 0.01 ; // questo è riferito allo spazio parametrico perché le curve di loop sono già state riscalate!!!!!! - double dAngTolDeg = 5 ; - PolyLine plApprox ; - int nType = 0 ; - pCrv->ApproxWithLines( dLinTol,dAngTolDeg, nType, plApprox) ; - vPlApprox.push_back( plApprox) ; - } - // ora le curve di trim hanno lo stesso indice delle loro corrispondenti spezzate nel vettore vPlApprox - 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 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) vPlApprox.size() ; ++ i) { - PolyLine plLoop = vPlApprox[i] ; - // calcolo se il loop è CCW o Cw - double dArea ; - Plane3d plExtPlane ; - bool bCCW ; - plLoop.IsClosedAndFlat( plExtPlane, dArea, 50 * EPS_SMALL) ; - if ( plExtPlane.GetVersN().z > 0) - bCCW = true ; - else - bCCW = false ; + 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 + bool bCCW = std::get<1>(m_vPlApprox[i]) ; // trovo in quale cella è il ptStart Point3d ptStart ; plLoop.GetFirstPoint( ptStart) ; @@ -1514,11 +1512,11 @@ 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 ; + //// per debug + //int c = 0 ; Cell cUnderWork ; while ( plLoop.GetNextPoint( ptCurr)) { - ++ c ; + //++ c ; // sto uscendo dalla cella, quindi cerco l'intersezione Point3d ptTStart, ptTEnd ; plLoop.GetPrevPoint( ptTStart) ; @@ -1536,7 +1534,6 @@ Tree::TraceLoopLabelCell( void) // al precedente FindInters avrei dovuto passare di cella if ( ! FindInters( nId, clTrim, vptInters, true)) { // scarterò il punto molto vicino al lato e tengo solo l'intersezione del trim col lato - //m_mTree[nId].m_vInters.back().vpt.pop_back() ; vptInters.pop_back() ; plLoop.GetPrevPoint( ptTEnd) ; plLoop.GetPrevPoint( ptTStart) ; @@ -1544,8 +1541,7 @@ Tree::TraceLoopLabelCell( void) clTrim.Set( ptTStart, ptTEnd) ; clTrim.ExtendEndByLen( EPS_SMALL * 2) ; clTrim.ExtendStartByLen( EPS_SMALL * 2) ; - //vptInters.clear() ; - if ( FindInters( nId, clTrim, vptInters, true)) + if ( ! FindInters( nId, clTrim, vptInters, true)) return false ; bEraseNextPoint = true ; } @@ -2401,7 +2397,6 @@ Tree::CreateIslandAndHoles( const int& nLeafId, std::vector& vPo // loop interni in una cella intersecata if ( m_mTree[nId].m_nFlag == 3 || m_mTree[nId].m_nFlag == 2) { PolyLine plInLoop ; - // numero dei loop interni passati Inters inA ; // se ho almeno un loop CW che non è contenuto in un altro poligono o in un loop interno CCW devo aggiungere il bordo bool bAllContained = true ; @@ -2469,10 +2464,9 @@ Tree::CreateIslandAndHoles( const int& nLeafId, std::vector& vPo plInLoop.GetFirstPoint( ptStart) ; int nOtherPoly = (int)vPolygons.size() ; for ( int r = 0 ; r < nPoly ; ++r) { - if ( IsPointInsidePolyLine( ptStart, vPolygons[nOtherPoly - r - 1][0], -0.01) && vnParentChunk[nLoop - r - 1] == inA.nChunk) { + if ( IsPointInsidePolyLine( ptStart, vPolygons[nOtherPoly - r - 1][0], -0.01) && vnParentChunk[nPoly - r - 1] == inA.nChunk) { vPolygons[nOtherPoly - r - 1].push_back( plInLoop) ; plInLoop.Clear() ; - vnParentChunk.push_back( inA.nChunk) ; bAdded = true ; break ; } @@ -2676,7 +2670,7 @@ Tree::AddVertex( const int& nId, const std::vector& vEdgeVertex, Poly plTrimmedPoly.GetLastPoint( ptLast) ; // verifico di essere allineato con un lato, sennò aggiungo e basta Vector3d vDir ; - if ( ! AreSamePointExact( ptToAdd, ptLast)) + if ( ! AreSamePointApprox( ptToAdd, ptLast)) vDir = ptToAdd - ptLast ; else return true ; @@ -2691,6 +2685,8 @@ Tree::AddVertex( const int& nId, const std::vector& vEdgeVertex, Poly plTrimmedPoly.AddUPoint( c, ptTl) ; else if ( AreSamePointApprox( ptToAdd, ptBL)) plTrimmedPoly.AddUPoint( c, ptBL) ; + else + plTrimmedPoly.AddUPoint( c, ptToAdd) ; ++ c ; return true ; } diff --git a/Tree.h b/Tree.h index 3f79dac..57bf9cd 100644 --- a/Tree.h +++ b/Tree.h @@ -117,9 +117,9 @@ public : 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 + 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 // 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 = 5, 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 @@ -162,7 +162,8 @@ private : bool m_bTrimmed ; // superficie trimmata std::vector m_vChunk ; // elenco dei loop divisi per chunk std::map m_mChunk ; - ICURVEPOVECTOR m_vLoop ; // curve di loop. la 0 è il bordo dello spazio parametrico, le altre sono i loop interni + ICURVEPOVECTOR m_vLoop ; // curve di loop + std::vector> m_vPlApprox ; bool m_bBilinear ; // superficie bilineare bool m_bMulti ; // superficie multi-patch bool m_bClosed ; // superficie chiusa From e9c22b895b25eb14e53836a9cd1a0f42c75dc62a Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Wed, 21 Jun 2023 09:30:07 +0200 Subject: [PATCH 20/44] EgtGeomKernel : - risolti vari bug - ridotto il calcolo del tree alle bbox delle curve di trim --- SurfBezier.cpp | 44 +++--- Tree.cpp | 380 +++++++++++++++++++++++++++++++++---------------- Tree.h | 38 +++-- 3 files changed, 307 insertions(+), 155 deletions(-) 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) ; From 8279e66caead5b2174611f99e0589ca193c858c6 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Fri, 23 Jun 2023 16:56:48 +0200 Subject: [PATCH 21/44] EgtGeomKernel : - correzione minore alle superfici di bezier --- Tree.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Tree.cpp b/Tree.cpp index ce186fa..4eeaec8 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -303,10 +303,10 @@ Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches, const Point3d 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)) ; + m_vDim.push_back( ( dLen0 > EPS_ZERO ? dLen0 : 1)) ; + m_vDim.push_back( ( dLen1 > EPS_ZERO ? dLen1 : 1)) ; + m_vDim.push_back( ( dLen2 > EPS_ZERO ? dLen2 : 1)) ; + m_vDim.push_back( ( dLen3 > EPS_ZERO ? dLen3 : 1)) ; } //---------------------------------------------------------------------------- From 8a81c3543eb9ca80047706ee9d4a01eb34581917 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 28 Aug 2023 09:39:34 +0200 Subject: [PATCH 22/44] EgtGeomKernel : - aggiunta della funzione di conversione da superficie NURBS a Bezier --- CurveAux.cpp | 4 +- EgtGeomKernel.vcxproj | 2 + EgtGeomKernel.vcxproj.filters | 6 + SurfAux.cpp | 578 ++++++++++++++++++++++++++++++++++ SurfAux.h | 33 ++ 5 files changed, 622 insertions(+), 1 deletion(-) create mode 100644 SurfAux.cpp create mode 100644 SurfAux.h diff --git a/CurveAux.cpp b/CurveAux.cpp index 4e0ba4d..795c6e4 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -617,6 +617,7 @@ NurbsToBezierCurve( const CNurbsData& cnData) int b = cnData.nDeg ; bool bPrevRejected = false ; // ciclo + int n = 0 ; // debug while ( b < nU - 1) { int i = b ; while ( b < nU - 1 && abs( cnData.vU[b+1] - cnData.vU[b]) < EPS_ZERO) @@ -684,7 +685,8 @@ NurbsToBezierCurve( const CNurbsData& cnData) pCrvBez.Reset() ; bPrevRejected = true ; } - + // debug + ++n ; // inizializzazioni per la prossima curva di Bezier if ( b < nU - 1) { if ( ! cnData.bRat) { diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index 6feb619..eeea39e 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -400,6 +400,7 @@ copy $(TargetPath) \EgtProg\Dll64 + @@ -619,6 +620,7 @@ copy $(TargetPath) \EgtProg\Dll64 + diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index d9b5749..da86913 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -480,6 +480,9 @@ File di origine\GeoInters + + File di origine\Geo + @@ -1121,6 +1124,9 @@ File di intestazione + + File di intestazione + diff --git a/SurfAux.cpp b/SurfAux.cpp new file mode 100644 index 0000000..b2f6a25 --- /dev/null +++ b/SurfAux.cpp @@ -0,0 +1,578 @@ +//---------------------------------------------------------------------------- +// EgalTech 2023-2023 +//---------------------------------------------------------------------------- +// File : SurfAux.cpp Data : 09.08.23 Versione : +// Contenuto : Implementazione di alcune funzioni di utilità per le Superfici. +// +// +// +// Modifiche : 09.08.23 DB Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "CurveAux.h" +#include "GeoConst.h" +#include "CurveLine.h" +#include "CurveArc.h" +#include "CurveBezier.h" +#include "CurveComposite.h" +#include "/EgtDev/Include/EgtPointerOwner.h" +#include "/EgtDev/Include/EGkSurf.h" +#include "/EgtDev/Include/EGkSurfAux.h" +#include "/EgtDev/Include/EGkSurfBezier.h" + +using namespace std ; + +//---------------------------------------------------------------------------- +ISurf* +NurbsToBezierSurface(const CNurbsSurfData& cnData) +{ + // la superficie Nurbs deve essere in forma canonica + if ( cnData.bPeriodicU || cnData.bPeriodicV || cnData.bExtraKnotes ) + return nullptr ; + // controllo sul numero dei nodi + int nU = cnData.nCPU + cnData.nDegU - 1 ; + int nV = cnData.nCPV + cnData.nDegV - 1 ; + // controllo nodi e punti di controllo + //if ( nU != int( cnData.vU.size()) || nV != int( cnData.vV.size()) || cnData.nCPU * cnData.nCPV != int( cnData.vCP.size())) + if ( nU != int(cnData.vU.size()) || nV != int(cnData.vV.size())) { + return nullptr ; + } + + //// numero degli intervalli + //int nInt = nU - 2 * cnData.nDeg + 1 ; + // verifico le condizioni agli estremi sui nodi (i primi nDeg nodi e gli ultimi nDeg nodi devono essere uguali tra loro) + bool bOk = true ; + // direzione U + for ( int i = 1 ; i < cnData.nDegU ; ++ i) { + if ( abs( cnData.vU[i] - cnData.vU[0]) >= EPS_ZERO) + bOk = false ; + } + for ( int i = 1 ; i < cnData.nDegU ; ++ i) { + if ( abs( cnData.vU[nU - 1 - i] - cnData.vU[nU - 1]) >= EPS_ZERO) + bOk = false ; + } + // direzione V + for ( int i = 1 ; i < cnData.nDegV ; ++ i) { + if ( abs( cnData.vV[i] - cnData.vV[0]) >= EPS_ZERO) + bOk = false ; + } + for ( int i = 1 ; i < cnData.nDegV ; ++ i) { + if ( abs( cnData.vV[nV - 1 - i] - cnData.vV[nV - 1]) >= EPS_ZERO) + bOk = false ; + } + if ( ! bOk) + return nullptr ; + + //// se 1 solo intervallo, la Nurbs è già una curva di Bezier + //if ( nInt == 1) { + // // creo la curva di Bezier + // PtrOwner pCrvBez( CreateCurveBezier()) ; + // if ( IsNull( pCrvBez)) + // return nullptr ; + // // la inizializzo + // if ( ! pCrvBez->Init( cnData.nDeg, cnData.bRat)) + // return nullptr ; + // for ( int i = 0 ; i <= cnData.nDeg ; ++ i) { + // if ( ! cnData.bRat) { + // if ( ! pCrvBez->SetControlPoint( i, cnData.vCP[i])) + // return nullptr ; + // } + // else { + // if ( ! pCrvBez->SetControlPoint( i, cnData.vCP[i], cnData.vW[i])) + // return nullptr ; + // } + // } + // // se non è una curva ma un punto, la invalido + // if ( pCrvBez->IsAPoint()) + // pCrvBez->Init( cnData.nDeg, cnData.bRat) ; + // // restituisco la curva + // return Release( pCrvBez) ; + //} + + + // algoritmo 5.7 del libro "The NURBS book"////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // creazione delle strips nella direzione U ( trasformo le curve iso con U costante in bezier) + int a = cnData.nDegU - 1 ; + int b = cnData.nDegU ; + int nb = 0 ; // numero di strisce in U ( lunghezza con U costante) + //PNTVECTOR vBC ; + //vBC.resize( cnData.nCPV * cnData.nDegU) ; + //for (int row = 0 ; row < cnData.nCPV ; ++row ) { + // for ( int i = 0 ; i <= cnData.nDegU ; ++i ) { + // vBC[nDegU*row + i] = ( cnData.vCP[nCPU*row + i]) ; + // } + //} + vector vCPV( cnData.nCPV) ; + vector< vector> mBC (cnData.nDegU + 1,vCPV ) ; + vector< vector> mBC_next (cnData.nDegU - 1, vCPV) ; + vector< vector> mPC_strip(cnData.nDegU + 1, vCPV) ; // matrice che verrà ingrandita e conterrà la superficie metà bezier e metà NURBS + DBLVECTOR vV_W( cnData.nCPV) ; + vector mW( cnData.nDegU + 1, vV_W) ; + vector mW_next( cnData.nDegU - 1, vV_W) ; + vector mW_strip( cnData.nDegU + 1, vV_W) ; + DBLVECTOR vAlpha ; + vAlpha.resize( cnData.nDegU - 1) ; + if ( ! cnData.bRat ) { + for ( int i = 0 ; i <= cnData.nDegU ; ++i ) { + for ( int row = 0 ; row < cnData.nCPV ; ++row ) { + mBC[i][row] = cnData.mCP[i][row] ; + } + } + } + else { + for ( int i = 0 ; i <= cnData.nDegU ; ++i ) { + for (int row = 0 ; row < cnData.nCPV ; ++ row) { + mW[i][row] = cnData.mW[i][row] ; + mBC[i][row] = cnData.mCP[i][row] * cnData.mW[i][row] ; + } + } + } + + bool bRef = false ; + 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) + ++ b ; + int mult = b - i + 1 ; + if ( mult < cnData.nDegU ) { + bRef = true ; + // calcolo numeratore e alpha + double numer = cnData.vU[b] - cnData.vU[a] ; + for ( int j = cnData.nDegU ; j > mult ; -- j) + vAlpha[j-mult-1] = numer / ( cnData.vU[a+j] - cnData.vU[a]) ; + int r = cnData.nDegU - mult ; + for ( int j = 1 ; j <= cnData.nDegU - mult ; ++j ) { + int save = r - j ; + int s = mult + j ; + //for ( int row = 0 ; row < cnData.nCPV ; ++row) { + // for ( int k = cnData.nDegU ; k >= s ; --k ) { + // vBC[nCPU*row + k] = vAlpha[k-s]*vBC[nCPU*row + k] + ( 1 - vAlfa[k-s]) * vBC[nCPU*row + k - 1] + // } + //} + if ( ! cnData.bRat ) { + for ( int k = cnData.nDegU ; k >= s ; --k ) { + for ( int row = 0 ; row < cnData.nCPV ; ++row) { + mBC[k][row] = vAlpha[k-s] * mBC[k][row] + ( 1 - vAlpha[k-s]) * mBC[k-1][row] ; + } + } + } + else { + for ( int k = cnData.nDegU ; k >= s ; --k ) { + for ( int row = 0 ; row < cnData.nCPV ; ++row) { + mBC[k][row] = vAlpha[k-s] * mBC[k][row] + ( 1 - vAlpha[k-s]) * mBC[k-1][row] ; + mW[k][row] = vAlpha[k-s] * mW[k][row] + ( 1 - vAlpha[k-s]) * mW[k-1][row] ; + } + } + } + + if ( b < nU - 1 ) { + for ( int row = 0 ; row < cnData.nCPV ; ++row) { + mBC_next[save][row] = mBC[cnData.nDegU][row] ; + } + if ( cnData.bRat ) + for ( int row = 0 ; row < cnData.nCPV ; ++row) { + mW_next[save][row] = mW[cnData.nDegU][row] ; + } + } + } + mPC_strip.resize(cnData.nDegU + 1 + ( cnData.nDegU - 1 ) * ( nb + 1)) ; + mW_strip.resize( cnData.nDegU + 1 + ( cnData.nDegU - 1 ) * ( nb + 1)) ; + if ( ! cnData.bRat) + for ( int i = 0 ; i <= cnData.nDegU ; ++i) { + for ( int row = 0 ; row < cnData.nCPV ; ++row ) { + mPC_strip[i+ nb * cnData.nDegU][row] = mBC[i][row] ; + } + } + else { + for ( int i = 0 ; i <= cnData.nDegU ; ++i) { + for ( int row = 0 ; row < cnData.nCPV ; ++row ) { + mPC_strip[i+ nb * cnData.nDegU][row] = mBC[i][row]/mW[i][row] ; + mW_strip[i+ nb * cnData.nDegU][row] = mW[i][row] ; + } + } + } + ++ nb ; + // ho finito di definire la patch di Bezier attuale e passo alla successiva + + // aggiorno mBC con i valori della prossima pezza di Bezier // corrisponde a nb = nb + 1 + if ( ! cnData.bRat){ + for (int i = 0 ; i < cnData.nDegU - 1 ; ++ i) { + for ( int row = 0 ; row < cnData.nCPV ; ++row) { + mBC[i][row] = mBC_next[i][row] ; + } + } + } + else { + for (int i = 0 ; i < cnData.nDegU - 1 ; ++ i) { + for ( int row = 0 ; row < cnData.nCPV ; ++row) { + mBC[i][row] = mBC_next[i][row] ; + mW[i][row] = mW_next[i][row] ; + } + } + } + + if ( b < nU - 1 ) { + for ( int i = cnData.nDegU - mult ; i <= cnData.nDegU ; ++ i) { + for (int row = 0 ; row < cnData.nCPV ; ++ row ) { + mBC[i][row] = cnData.mCP[b - cnData.nDegU + i][row] ; + } + } + if ( cnData.bRat ) { + for ( int i = cnData.nDegU - mult ; i <= cnData.nDegU ; ++ i) { + for (int row = 0 ; row < cnData.nCPV ; ++ row ) { + mW[i][row] = cnData.mW[b - cnData.nDegU + i][row] ; + } + } + } + a = b ; + ++b ; + } + } + } + + // se non ho raffinato allora tutti i nodi avevano già molteplicità massima. Converto direttamente in Bezier la dir U + int nCPU_ref ; // numero dei punti di controllo in U dopo il raffinamento + if ( ! bRef ) { + nCPU_ref = cnData.nCPU ; + mPC_strip.resize( cnData.nCPU, vCPV) ; + mW_strip.resize( cnData.nCPU, vV_W) ; + if ( ! cnData.bRat) { + for ( int i = 0 ; i < nCPU_ref ; ++i) { + for ( int row = 0 ; row < cnData.nCPV ; ++ row) { + mPC_strip[i][row] = cnData.mCP[i][row] ; + } + } + } + else { + for ( int i = 0 ; i < nCPU_ref ; ++i) { + for ( int row = 0 ; row < cnData.nCPV ; ++ row) { + mPC_strip[i][row] = cnData.mCP[i][row] ; + mW_strip[i][row] = cnData.mW[i][row] ; + } + } + } + // devo vedere quante patch ci stanno prendendo i punti che ci sono + nb = (cnData.nCPU - 1) / cnData.nDegU ; + } + else + nCPU_ref = cnData.nDegU * nb + 1 ; // numero dei punti di controllo in U dopo il raffinamento + + // ora ho ottenuto le strisce nDegU x nCPV + // devo ripetere la procedura, sulla dir V, per ottenere le patch nDegU x nDegV + a = cnData.nDegV - 1 ; + b = cnData.nDegV ; + int nc = 0 ; // numero di strisce in V ( lunghezza con V costante) + vector vDegV(cnData.nDegV + 1) ; + vector vDegV_1(cnData.nDegV - 1) ; + vector< vector> m_BC1( nCPU_ref, vDegV) ; + vector< vector> m_BC1_next( nCPU_ref, vDegV_1) ; + DBLVECTOR vV1_W(cnData.nDegV + 1) ; + DBLVECTOR vV2_W(cnData.nDegV - 1) ; + vector mW1( nCPU_ref, vV1_W) ; + vector mW1_next( nCPU_ref, vV2_W) ; + DBLVECTOR vAlpha1( cnData.nDegV - 1) ; + vector> mPC_tot( nCPU_ref, vDegV) ; + vector mW_tot( nCPU_ref, vV1_W) ; + if ( ! cnData.bRat ) { + for ( int i = 0 ; i < nCPU_ref ; ++i ) { + for ( int row = 0 ; row <= cnData.nDegV ; ++row ) { + m_BC1[i][row] = mPC_strip[i][row] ; + } + } + } + else { + for ( int i = 0 ; i < nCPU_ref ; ++i ) { + for (int row = 0 ; row <= cnData.nDegV ; ++ row) { + mW1[i][row] = mW_strip[i][row] ; + m_BC1[i][row] = mPC_strip[i][row] * mW_strip[i][row] ; + } + } + } + + bRef = false ; + while ( b < nV - 1) { // qui correggo un probabile errore, mettendo nU anziché nCPV, come indicato nell'algoritmo + int i = b ; + while ( b < nV - 1 && abs( cnData.vV[b+1] - cnData.vV[b]) < EPS_ZERO) + ++ b ; + int mult = b - i + 1 ; + if ( mult < cnData.nDegV ) { + bRef = true ; + // calcolo numeratore e alpha + double numer = cnData.vV[b] - cnData.vV[a] ; + for ( int j = cnData.nDegV ; j > mult ; -- j) + vAlpha1[j-mult-1] = numer / ( cnData.vV[a+j] - cnData.vV[a]) ; + int r = cnData.nDegV - mult ; + for ( int j = 1 ; j <= cnData.nDegV - mult ; ++j ) { + int save = r - j ; + int s = mult + j ; + //for ( int row = 0 ; row < cnData.nCPV ; ++row) { + // for ( int k = cnData.nDegU ; k >= s ; --k ) { + // vBC[nCPU*row + k] = vAlpha1[k-s]*vBC[nCPU*row + k] + ( 1 - vAlpha1[k-s]) * vBC[nCPU*row + k - 1] + // } + //} + if ( ! cnData.bRat) { + for ( int k = 0 ; k < nCPU_ref ; ++k) { + for ( int row = cnData.nDegV ; row >= s ; --row ) { + m_BC1[k][row] = vAlpha1[row-s] * m_BC1[k][row] + ( 1 - vAlpha1[row-s]) * m_BC1[k][row-1] ; + } + } + } + else { + for ( int k = 0 ; k < nCPU_ref ; ++k) { + for ( int row = cnData.nDegV ; row >= s ; --row ) { + m_BC1[k][row] = vAlpha1[row-s] * m_BC1[k][row] + ( 1 - vAlpha1[row-s]) * m_BC1[k][row-1] ; + mW1[k][row] = vAlpha1[row-s] * mW1[k][row] + ( 1 - vAlpha1[row-s]) * mW1[k][row-1] ; + } + } + } + + if ( b < nV - 1 ) { + if ( !cnData.bRat ){ + for ( int i = 0 ; i < nCPU_ref ; ++i) { + m_BC1_next[i][save] = m_BC1[i][cnData.nDegV] ; + } + } + else { + for ( int i = 0 ; i < nCPU_ref ; ++i) { + m_BC1_next[i][save] = m_BC1[i][cnData.nDegV] ; + mW1_next[save] = mW1[cnData.nDegV] ; + } + } + } + } + } + vDegV.resize( cnData.nDegV + 1 + ( cnData.nDegV - 1 ) * ( nc + 1)) ; + mPC_tot.resize( nCPU_ref, vDegV) ; + vV_W.resize( cnData.nDegV + 1 + ( cnData.nDegV - 1 ) * ( nc + 1)) ; + mW_tot.resize( nCPU_ref, vV_W) ; + if ( ! cnData.bRat) + for ( int i = 0 ; i < nCPU_ref ; ++i) { + for ( int row = 0 ; row <= cnData.nDegV ; ++row ) { + mPC_tot[i][row + nc * cnData.nDegV] = m_BC1[i][row] ; + } + } + else { + for ( int i = 0 ; i < nCPU_ref ; ++i) { + for ( int row = 0 ; row <= cnData.nDegV ; ++row ) { + mPC_tot[i][row + nc * cnData.nDegV] = m_BC1[i][row]/mW1[i][row] ; + mW_tot[i][row + nc * cnData.nDegV] = mW1[i][row] ; + } + } + } + ++ nc ; + // ho finito di definire la patch di Bezier attuale e passo alla successiva + + // aggiorno mBC con i valori della prossima pezza di Bezier // corrisponde a nc = nc + 1 + if ( ! cnData.bRat){ + for (int i = 0 ; i < nCPU_ref ; ++ i) { + for ( int row = 0 ; row < cnData.nDegV - 1 ; ++row) { + m_BC1[i][row] = m_BC1_next[i][row] ; + } + } + } + else { + for (int i = 0 ; i < nCPU_ref ; ++ i) { + for ( int row = 0 ; row < cnData.nDegV - 1 ; ++row) { + m_BC1[i][row] = m_BC1_next[i][row] ; + mW1[i][row] = mW1_next[i][row] ; + } + } + } + + if ( b < nV - 1 ) { + for (int i = 0 ; i < nCPU_ref ; ++ i ) { + for ( int row = cnData.nDegV - mult ; row <= cnData.nDegV ; ++ row) { + m_BC1[i][row] = cnData.mCP[i][b - cnData.nDegV + row] ; + } + } + if ( cnData.bRat ) { + for (int i = 0 ; i < nCPU_ref ; ++ i ) { + for ( int row = cnData.nDegV - mult ; row <= cnData.nDegV ; ++ row) { + mW1[i][row] = cnData.mW[i][b - cnData.nDegV + row] ; + } + } + } + a = b ; + ++b ; + } + + } + // se non ho raffinato allora aggiungo direttamente alle matrici della superficie totale + int nCPV_ref ; // numero dei punti di controllo in V dopo il raffinamento + vCPV.resize( cnData.nCPV) ; + vV1_W.resize( cnData.nCPV) ; + if ( ! bRef) { + nCPV_ref = cnData.nCPV ; + mPC_tot.resize( nCPU_ref, vCPV) ; + mW_tot.resize( nCPU_ref, vV1_W) ; + if ( ! cnData.bRat) { + for ( int i = 0 ; i < nCPU_ref ; ++i) { + for ( int row = 0 ; row < nCPV_ref ; ++ row) { + mPC_tot[i][row] = mPC_strip[i][row] ; + } + } + } + else { + for ( int i = 0 ; i < nCPU_ref ; ++i) { + for ( int row = 0 ; row < nCPV_ref ; ++ row) { + mPC_tot[i][row] = mPC_strip[i][row] ; + mW_tot[i][row] = mW_strip[i][row] ; + } + } + } + // devo vedere quante patch ci stanno prendendo i punti che ci sono + nc = (cnData.nCPV - 1) / cnData.nDegV ; + } + else + nCPV_ref = cnData.nDegV * nc + 1 ; + + // finalmente setto la superficie di bezier totale divisa in nb patch in U e nc patch in V + PtrOwner pSrfBz( CreateSurfBezier()) ; + if ( IsNull( pSrfBz)) + return nullptr ; + pSrfBz->Init(cnData.nDegU, cnData.nDegV, nb, nc, cnData.bRat) ; ////// qui nb e nc sono sbagliati. manca 1 ad entrambi + if ( !cnData.bRat ) { + for ( int i = 0 ; i < nCPU_ref; ++ i) { + for (int j = 0 ; j < nCPV_ref; ++j) { + pSrfBz->SetControlPoint( i + nCPU_ref * j, mPC_tot[i][j]) ; + } + } + } + else { + for ( int i = 0 ; i < nCPU_ref; ++ i) { + for (int j = 0 ; j < nCPV_ref; ++j) { + pSrfBz->SetControlPoint( i + nCPU_ref * j, mPC_tot[i][j] / mW_tot[i][j], mW_tot[i][j]) ; + } + } + } + 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 diff --git a/SurfAux.h b/SurfAux.h new file mode 100644 index 0000000..09867fc --- /dev/null +++ b/SurfAux.h @@ -0,0 +1,33 @@ +//---------------------------------------------------------------------------- +// EgalTech 2023-2023 +//---------------------------------------------------------------------------- +// File : SurfAux.h Data : 09.08.23 Versione : +// Contenuto : Dichiarazione di alcune funzioni di utilità per le superfici. +// +// +// +// Modifiche : 09.08.23 DB Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once + +#include "/EgtDev/Include/EGkSurfAux.h" + +//---------------------------------------------------------------------------- +//bool IsClosed( const ICurve& crvC) ; +//bool IsValidParam( const ICurve& crvC, double dPar, ICurve::Side nSide) ; +//bool IsStartParam( const ICurve& crvC, double dPar) ; +//bool IsEndParam( const ICurve& crvC, double dPar) ; +//bool GetNearestExtremityToPoint( const Point3d& ptP, const ICurve& Curve, bool& bStart) ; +//bool MoveParamToAvoidTg( double& dU, ICurve::Side nSide, const ICurve& Curve) ; +//bool GetTang( const ICurve& crvC, double dU, ICurve::Side nS, Vector3d& vtTang) ; +//bool GetPointTang( const ICurve& crvC, double dU, ICurve::Side nS, Point3d& ptPos, Vector3d& vtTang) ; +//bool GetPointDiffGeom( const ICurve& crvC, double dU, ICurve::Side nS, CrvPointDiffGeom& oDiffG) ; +//bool ImproveCurveParamAtPoint( double& dU, const Point3d& ptP, const ICurve* pCrv) ; +//bool CurveGetAreaXY( const ICurve& crvC, double& dArea) ; +//bool CurveGetArea( const ICurve& crvC, Plane3d& plPlane, double& dArea) ; +//bool CurveDump( const ICurve& crvC, std::string& sOut, bool bMM, const char* szNewLine) ; +//bool CopyExtrusion( const ICurve* pSouCrv, ICurve* pDestCrv) ; +//bool CopyThickness( const ICurve* pSouCrv, ICurve* pDestCrv) ; From 737f4f4ffa823c9776df99b7d9cde71501b34d5c Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 28 Aug 2023 16:06:26 +0200 Subject: [PATCH 23/44] EgtGeomKernel : - correzione alla conversione da NURBS a Bezier. --- SurfAux.cpp | 93 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 39 deletions(-) diff --git a/SurfAux.cpp b/SurfAux.cpp index b2f6a25..88db54c 100644 --- a/SurfAux.cpp +++ b/SurfAux.cpp @@ -30,6 +30,20 @@ using namespace std ; ISurf* NurbsToBezierSurface(const CNurbsSurfData& cnData) { + //INTVECTOR vInt_sub( 10) ; + //INTMATRIX vInt( 10, vInt_sub) ; + //for ( int i = 0 ; i < 10 ; ++i ) { + // for ( int j = 0 ; j < 10 ; ++j ) { + // vInt[i][j] = i + 10 * j ; + // } + //} + //vInt_sub.resize( 20) ; + //vInt[0].resize( 20) ; + + + + + // la superficie Nurbs deve essere in forma canonica if ( cnData.bPeriodicU || cnData.bPeriodicV || cnData.bExtraKnotes ) return nullptr ; @@ -179,8 +193,8 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } } } - mPC_strip.resize(cnData.nDegU + 1 + ( cnData.nDegU - 1 ) * ( nb + 1)) ; - mW_strip.resize( cnData.nDegU + 1 + ( cnData.nDegU - 1 ) * ( nb + 1)) ; + mPC_strip.resize( cnData.nDegU * ( nb + 1) + 1 , vCPV) ; + mW_strip.resize( cnData.nDegU * ( nb + 1) + 1, vV_W) ; if ( ! cnData.bRat) for ( int i = 0 ; i <= cnData.nDegU ; ++i) { for ( int row = 0 ; row < cnData.nCPV ; ++row ) { @@ -195,42 +209,42 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } } } - ++ nb ; - // ho finito di definire la patch di Bezier attuale e passo alla successiva + } + ++ nb ; + // ho finito di definire la patch di Bezier attuale e passo alla successiva - // aggiorno mBC con i valori della prossima pezza di Bezier // corrisponde a nb = nb + 1 - if ( ! cnData.bRat){ - for (int i = 0 ; i < cnData.nDegU - 1 ; ++ i) { - for ( int row = 0 ; row < cnData.nCPV ; ++row) { - mBC[i][row] = mBC_next[i][row] ; - } + // aggiorno mBC con i valori della prossima pezza di Bezier // corrisponde a nb = nb + 1 + if ( ! cnData.bRat){ + for (int i = 0 ; i < cnData.nDegU - 1 ; ++ i) { + for ( int row = 0 ; row < cnData.nCPV ; ++row) { + mBC[i][row] = mBC_next[i][row] ; } } - else { - for (int i = 0 ; i < cnData.nDegU - 1 ; ++ i) { - for ( int row = 0 ; row < cnData.nCPV ; ++row) { - mBC[i][row] = mBC_next[i][row] ; - mW[i][row] = mW_next[i][row] ; - } + } + else { + for (int i = 0 ; i < cnData.nDegU - 1 ; ++ i) { + for ( int row = 0 ; row < cnData.nCPV ; ++row) { + mBC[i][row] = mBC_next[i][row] ; + mW[i][row] = mW_next[i][row] ; } } + } - if ( b < nU - 1 ) { + if ( b < nU - 1 ) { + for ( int i = cnData.nDegU - mult ; i <= cnData.nDegU ; ++ i) { + for (int row = 0 ; row < cnData.nCPV ; ++ row ) { + mBC[i][row] = cnData.mCP[b - cnData.nDegU + i + 1][row] ; + } + } + if ( cnData.bRat ) { for ( int i = cnData.nDegU - mult ; i <= cnData.nDegU ; ++ i) { for (int row = 0 ; row < cnData.nCPV ; ++ row ) { - mBC[i][row] = cnData.mCP[b - cnData.nDegU + i][row] ; + mW[i][row] = cnData.mW[b - cnData.nDegU + i + 1][row] ; } } - if ( cnData.bRat ) { - for ( int i = cnData.nDegU - mult ; i <= cnData.nDegU ; ++ i) { - for (int row = 0 ; row < cnData.nCPV ; ++ row ) { - mW[i][row] = cnData.mW[b - cnData.nDegU + i][row] ; - } - } - } - a = b ; - ++b ; } + a = b ; + ++b ; } } @@ -345,10 +359,11 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } } } - vDegV.resize( cnData.nDegV + 1 + ( cnData.nDegV - 1 ) * ( nc + 1)) ; - mPC_tot.resize( nCPU_ref, vDegV) ; - vV_W.resize( cnData.nDegV + 1 + ( cnData.nDegV - 1 ) * ( nc + 1)) ; - mW_tot.resize( nCPU_ref, vV_W) ; + int nRef = cnData.nDegV * ( nc + 1) + 1 ; + for ( int k = 0 ; k < nCPU_ref; ++k){ + mPC_tot[k].resize( nRef) ; + mW_tot[k].resize( nRef) ; + } if ( ! cnData.bRat) for ( int i = 0 ; i < nCPU_ref ; ++i) { for ( int row = 0 ; row <= cnData.nDegV ; ++row ) { @@ -383,16 +398,16 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } } - if ( b < nV - 1 ) { + if ( b < nV - 1) { for (int i = 0 ; i < nCPU_ref ; ++ i ) { for ( int row = cnData.nDegV - mult ; row <= cnData.nDegV ; ++ row) { - m_BC1[i][row] = cnData.mCP[i][b - cnData.nDegV + row] ; + m_BC1[i][row] = cnData.mCP[i][b - cnData.nDegV + row + 1] ; } } if ( cnData.bRat ) { for (int i = 0 ; i < nCPU_ref ; ++ i ) { for ( int row = cnData.nDegV - mult ; row <= cnData.nDegV ; ++ row) { - mW1[i][row] = cnData.mW[i][b - cnData.nDegV + row] ; + mW1[i][row] = cnData.mW[i][b - cnData.nDegV + row + 1] ; } } } @@ -403,12 +418,12 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } // se non ho raffinato allora aggiungo direttamente alle matrici della superficie totale int nCPV_ref ; // numero dei punti di controllo in V dopo il raffinamento - vCPV.resize( cnData.nCPV) ; - vV1_W.resize( cnData.nCPV) ; if ( ! bRef) { nCPV_ref = cnData.nCPV ; - mPC_tot.resize( nCPU_ref, vCPV) ; - mW_tot.resize( nCPU_ref, vV1_W) ; + for ( int k = 0 ; k < nCPU_ref ; ++k){ + mPC_tot[k].resize( cnData.nCPV) ; + mW_tot[k].resize( cnData.nCPV) ; + } if ( ! cnData.bRat) { for ( int i = 0 ; i < nCPU_ref ; ++i) { for ( int row = 0 ; row < nCPV_ref ; ++ row) { @@ -434,7 +449,7 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) PtrOwner pSrfBz( CreateSurfBezier()) ; if ( IsNull( pSrfBz)) return nullptr ; - pSrfBz->Init(cnData.nDegU, cnData.nDegV, nb, nc, cnData.bRat) ; ////// qui nb e nc sono sbagliati. manca 1 ad entrambi + pSrfBz->Init(cnData.nDegU, cnData.nDegV, nb, nc, cnData.bRat) ; if ( !cnData.bRat ) { for ( int i = 0 ; i < nCPU_ref; ++ i) { for (int j = 0 ; j < nCPV_ref; ++j) { From 419d325409f779d4f023d4b2c7a72cb4be752d71 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 12 Sep 2023 14:49:43 +0200 Subject: [PATCH 24/44] 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) ; From cb0452a2482e41397bb3257a12dcd2eff63b9862 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 18 Sep 2023 10:21:49 +0200 Subject: [PATCH 25/44] EgtGeomKernel : - aggiunta delle coordinate U e V ai vertici delle TriMesh. Manca da modificare : - funzione MoveVertex. --- StmFromTriangleSoup.cpp | 4 ++-- SurfBezier.cpp | 2 +- SurfTriMesh.cpp | 46 +++++++++++++++++++++++++++++++++++++++-- SurfTriMesh.h | 15 ++++++++++---- 4 files changed, 58 insertions(+), 9 deletions(-) diff --git a/StmFromTriangleSoup.cpp b/StmFromTriangleSoup.cpp index 08db0c7..8c55a74 100644 --- a/StmFromTriangleSoup.cpp +++ b/StmFromTriangleSoup.cpp @@ -99,14 +99,14 @@ StmFromTriangleSoup::AddTriangle( const Point3d& ptP0, const Point3d& ptP1, cons //---------------------------------------------------------------------------- int -StmFromTriangleSoup::AddVertex( const Point3d& ptP) +StmFromTriangleSoup::AddVertex( const Point3d& ptP, const double dU, const double dV) { // verifico se già presente int nId ; if ( m_VertGrid.Find( ptP, 2 * EPS_SMALL, nId)) return nId ; // aggiungo il vertice - if ( ( nId = m_pSTM->AddVertex( ptP)) == SVT_NULL) + if ( ( nId = m_pSTM->AddVertex( ptP, dU, dV)) == SVT_NULL) return SVT_NULL ; m_VertGrid.InsertPoint( ptP, nId) ; return nId ; diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 6c7588a..bb2e591 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -1524,7 +1524,7 @@ SurfBezier::GetAuxSurf( void) const Triangulate Tri ; if ( ! Tri.Make( vPL, vPnt, vTria)) return nullptr ; - + // porto i punti in 3d PNTVECTOR vPnt3d ; for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) { diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index 76ad9e9..d171748 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -107,7 +107,7 @@ SurfTriMesh::Clear( void) //---------------------------------------------------------------------------- int -SurfTriMesh::AddVertex( const Point3d& ptVert) +SurfTriMesh::AddVertex( const Point3d& ptVert, const double dU, const double dV) { // imposto ricalcolo m_nStatus = TO_VERIFY ; @@ -118,7 +118,11 @@ SurfTriMesh::AddVertex( const Point3d& ptVert) try { m_vVert.emplace_back( ptVert) ;} catch(...) { return SVT_NULL ;} // ne determino l'indice - return int( m_vVert.size() - 1) ; + int nId = int( m_vVert.size() - 1) ; + // aggiugo le coordinate corrispondenti allo spazio parametrico + m_vVert[nId].dU = dU ; + m_vVert[nId].dV = dV ; + return nId ; } //---------------------------------------------------------------------------- @@ -475,6 +479,19 @@ SurfTriMesh::GetVertex( int nId, Point3d& ptP) const return true ; } +//---------------------------------------------------------------------------- +bool +SurfTriMesh::GetVertexParam( int nId, double& dU, double& dV) const +{ + // verifico esistenza del vertice + if ( nId < 0 || nId >= GetVertexSize() || m_vVert[nId].nIdTria == SVT_DEL) + return false ; + // recupero i dati + dU = m_vVert[nId].dU ; + dV = m_vVert[nId].dV ; + return true ; +} + //---------------------------------------------------------------------------- int SurfTriMesh::GetFirstVertex( Point3d& ptP) const @@ -482,6 +499,13 @@ SurfTriMesh::GetFirstVertex( Point3d& ptP) const return GetNextVertex( SVT_NULL, ptP) ; } +//---------------------------------------------------------------------------- +int +SurfTriMesh::GetFirstVertexParam( int nId, double& dU, double& dV) const +{ + return GetNextVertexParam( SVT_NULL, dU, dV) ; +} + //---------------------------------------------------------------------------- int SurfTriMesh::GetNextVertex( int nId, Point3d& ptP) const @@ -499,6 +523,24 @@ SurfTriMesh::GetNextVertex( int nId, Point3d& ptP) const return nId ; } +//---------------------------------------------------------------------------- +int +SurfTriMesh::GetNextVertexParam( int nId, double& dU, double& dV) const +{ + // cerco il primo successivo valido + do { + nId ++ ; + } while ( nId < GetVertexSize() && m_vVert[nId].nIdTria == SVT_DEL) ; + // se oltrepassata fine + if ( nId >= GetVertexSize()) + return SVT_NULL ; + // recupero i dati + dU = m_vVert[nId].dU ; + dV = m_vVert[nId].dV ; + // ritorno indice triangolo corrente + return nId ; +} + //---------------------------------------------------------------------------- bool SurfTriMesh::GetTriangle( int nId, int nIdVert[3]) const diff --git a/SurfTriMesh.h b/SurfTriMesh.h index 6ae2946..9f8c8d1 100644 --- a/SurfTriMesh.h +++ b/SurfTriMesh.h @@ -28,11 +28,15 @@ class SurfFlatRegion ; class StmVert { public : - StmVert( void) : ptP(), nIdTria( SVT_NULL), nFlag( 0), nTemp( 0) {} - StmVert( const Point3d& ptQ) : ptP( ptQ), nIdTria( SVT_NULL), nFlag( 0), nTemp( 0) {} - StmVert( const Point3d& ptQ, int nIdT, int nF) : ptP( ptQ), nIdTria( nIdT), nFlag( nF), nTemp( 0) {} + StmVert( void) : ptP(), nIdTria( SVT_NULL), nFlag( 0), nTemp( 0), dU( -1), dV( -1) {} + StmVert( const Point3d& ptQ) : ptP( ptQ), nIdTria( SVT_NULL), nFlag( 0), nTemp( 0), dU( -1), dV( -1) {} + StmVert( const Point3d& ptQ, int nIdT, int nF) : ptP( ptQ), nIdTria( nIdT), nFlag( nF), nTemp( 0), dU( -1), dV( -1) {} public : Point3d ptP ; + double dU ; // parametro riferito alle coordinate del punto nello spazio parametrico ( nSpanU x nSpanV) + // della sup di Bezier // -1 se non definito + double dV ; // parametro riferito alle coordinate del punto nello spazio parametrico ( nSpanU x nSpanV) + // della sup di Bezier // -1 se non definito int nIdTria ; int nFlag ; mutable int nTemp ; @@ -215,7 +219,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW { m_dSmoothAng = std::max( dSmoothAngDeg, EPS_ANG_SMALL) ; m_dCosSmAng = cos( m_dSmoothAng * DEGTORAD) ; m_OGrMgr.Reset() ; } - int AddVertex( const Point3d& ptVert) override ; + int AddVertex( const Point3d& ptVert, const double dU = -1 , const double dV = -1) override ; bool MoveVertex( int nInd, const Point3d& ptNewVert) override ; int AddTriangle( const int nIdVert[3], int nTFlag = 0) override ; bool RemoveTriangle( int nId) override ; @@ -244,8 +248,11 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW double GetSmoothAngle( void) const override { return m_dSmoothAng ; } bool GetVertex( int nId, Point3d& ptP) const override ; + bool GetVertexParam( int nId, double& dU, double& dV) const override ; int GetFirstVertex( Point3d& ptP) const override ; + int GetFirstVertexParam( int nId, double& dU, double& dV) const override ; int GetNextVertex( int nId, Point3d& ptP) const override ; + int GetNextVertexParam( int nId, double& dU, double& dV) const override ; bool GetTriangle( int nId, int nIdVert[3]) const override ; int GetFirstTriangle( int nIdVert[3]) const override ; int GetNextTriangle( int nId, int nIdVert[3]) const override ; From b2bd8f7afe45d223fcf294e1bdbb23f923f9a3c9 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 18 Sep 2023 10:33:50 +0200 Subject: [PATCH 26/44] EgtGeomKernel : - correzione su coordinate U e V ai vertici delle TriMesh. --- StmFromTriangleSoup.cpp | 9 +++++---- SurfBezier.cpp | 5 ++++- SurfTriMesh.h | 4 ++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/StmFromTriangleSoup.cpp b/StmFromTriangleSoup.cpp index 8c55a74..87bae4e 100644 --- a/StmFromTriangleSoup.cpp +++ b/StmFromTriangleSoup.cpp @@ -76,18 +76,19 @@ StmFromTriangleSoup::AddTriangle( const Triangle3d& Tria) //---------------------------------------------------------------------------- bool -StmFromTriangleSoup::AddTriangle( const Point3d& ptP0, const Point3d& ptP1, const Point3d& ptP2) +StmFromTriangleSoup::AddTriangle( const Point3d& ptP0, const Point3d& ptP1, const Point3d& ptP2, + const double dU0, const double dV0,const double dU1, const double dV1,const double dU2, const double dV2) { // verifico inizializzazione if ( m_pSTM == nullptr) return false ; // ciclo sui tre vertici int nIdV[3] ; - if ( ( nIdV[0] = AddVertex( ptP0)) == SVT_NULL) + if ( ( nIdV[0] = AddVertex( ptP0, dU0, dV0)) == SVT_NULL) return false ; - if ( ( nIdV[1] = AddVertex( ptP1)) == SVT_NULL) + if ( ( nIdV[1] = AddVertex( ptP1, dU1, dV1)) == SVT_NULL) return false ; - if ( ( nIdV[2] = AddVertex( ptP2)) == SVT_NULL) + if ( ( nIdV[2] = AddVertex( ptP2, dU2, dV2)) == SVT_NULL) return false ; // se i vertici sono tutti diversi tra loro, inserisco il triangolo if ( nIdV[0] != nIdV[1] && nIdV[0] != nIdV[2] && nIdV[1] != nIdV[2]) { diff --git a/SurfBezier.cpp b/SurfBezier.cpp index bb2e591..ee7a99f 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -1535,7 +1535,10 @@ SurfBezier::GetAuxSurf( void) const } int nTria = int( vTria.size()) / 3 ; for ( int i = 0 ; i < nTria ; ++i) { - if ( ! stmSoup.AddTriangle( vPnt3d[vTria[3*i]], vPnt3d[vTria[3*i+1]], vPnt3d[vTria[3*i+2]])) + if ( ! stmSoup.AddTriangle( vPnt3d[vTria[3*i]], vPnt3d[vTria[3*i+1]], vPnt3d[vTria[3*i+2]], + vPnt[vTria[3*i]].x, vPnt[vTria[3*i]].y, + vPnt[vTria[3*i+1]].x, vPnt[vTria[3*i+1]].y, + vPnt[vTria[3*i+2]].x, vPnt[vTria[3*i+2]].y)) return nullptr ; } } diff --git a/SurfTriMesh.h b/SurfTriMesh.h index 9f8c8d1..69b8a8a 100644 --- a/SurfTriMesh.h +++ b/SurfTriMesh.h @@ -33,9 +33,9 @@ class StmVert StmVert( const Point3d& ptQ, int nIdT, int nF) : ptP( ptQ), nIdTria( nIdT), nFlag( nF), nTemp( 0), dU( -1), dV( -1) {} public : Point3d ptP ; - double dU ; // parametro riferito alle coordinate del punto nello spazio parametrico ( nSpanU x nSpanV) + double dU ; // parametro riferito alle coordinate del punto nello spazio parametrico ( nSpanU x 1000) ( nSpanV x 1000) // della sup di Bezier // -1 se non definito - double dV ; // parametro riferito alle coordinate del punto nello spazio parametrico ( nSpanU x nSpanV) + double dV ; // parametro riferito alle coordinate del punto nello spazio parametrico ( nSpanU x 1000) ( nSpanV x 1000) // della sup di Bezier // -1 se non definito int nIdTria ; int nFlag ; From 1ec38952ed939b4383d41b75836e74ca643a9890 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 19 Sep 2023 10:23:37 +0200 Subject: [PATCH 27/44] EgtGeomKernel : - correzione alla trasformazione NURBS to Bezier. --- SurfAux.cpp | 159 +++++++--------------------------------------------- 1 file changed, 21 insertions(+), 138 deletions(-) diff --git a/SurfAux.cpp b/SurfAux.cpp index 88db54c..b428b30 100644 --- a/SurfAux.cpp +++ b/SurfAux.cpp @@ -2,7 +2,7 @@ // EgalTech 2023-2023 //---------------------------------------------------------------------------- // File : SurfAux.cpp Data : 09.08.23 Versione : -// Contenuto : Implementazione di alcune funzioni di utilità per le Superfici. +// Contenuto : Implementazione di alcune funzioni di utilit? per le Superfici. // // // @@ -55,7 +55,7 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) if ( nU != int(cnData.vU.size()) || nV != int(cnData.vV.size())) { return nullptr ; } - + //// numero degli intervalli //int nInt = nU - 2 * cnData.nDeg + 1 ; // verifico le condizioni agli estremi sui nodi (i primi nDeg nodi e gli ultimi nDeg nodi devono essere uguali tra loro) @@ -81,7 +81,7 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) if ( ! bOk) return nullptr ; - //// se 1 solo intervallo, la Nurbs è già una curva di Bezier + //// se 1 solo intervallo, la Nurbs ? gi? una curva di Bezier //if ( nInt == 1) { // // creo la curva di Bezier // PtrOwner pCrvBez( CreateCurveBezier()) ; @@ -100,7 +100,7 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) // return nullptr ; // } // } - // // se non è una curva ma un punto, la invalido + // // se non ? una curva ma un punto, la invalido // if ( pCrvBez->IsAPoint()) // pCrvBez->Init( cnData.nDeg, cnData.bRat) ; // // restituisco la curva @@ -123,7 +123,7 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) vector vCPV( cnData.nCPV) ; vector< vector> mBC (cnData.nDegU + 1,vCPV ) ; vector< vector> mBC_next (cnData.nDegU - 1, vCPV) ; - vector< vector> mPC_strip(cnData.nDegU + 1, vCPV) ; // matrice che verrà ingrandita e conterrà la superficie metà bezier e metà NURBS + vector< vector> mPC_strip(cnData.nDegU + 1, vCPV) ; // matrice che verr? ingrandita e conterr? la superficie met? bezier e met? NURBS DBLVECTOR vV_W( cnData.nCPV) ; vector mW( cnData.nDegU + 1, vV_W) ; vector mW_next( cnData.nDegU - 1, vV_W) ; @@ -145,9 +145,13 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } } } - + bool bRef = false ; - while ( b < nU - 1) { // qui correggo un probabile errore, mettendo nU anziché nCPV, come indicato nell'algoritmo + // 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) ++ b ; @@ -212,7 +216,7 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } ++ nb ; // ho finito di definire la patch di Bezier attuale e passo alla successiva - + // aggiorno mBC con i valori della prossima pezza di Bezier // corrisponde a nb = nb + 1 if ( ! cnData.bRat){ for (int i = 0 ; i < cnData.nDegU - 1 ; ++ i) { @@ -248,7 +252,7 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } } - // se non ho raffinato allora tutti i nodi avevano già molteplicità massima. Converto direttamente in Bezier la dir U + // se non ho raffinato allora tutti i nodi avevano gi? molteplicit? massima. Converto direttamente in Bezier la dir U int nCPU_ref ; // numero dei punti di controllo in U dopo il raffinamento if ( ! bRef ) { nCPU_ref = cnData.nCPU ; @@ -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 From e5ed9efdd1b676b82dda96fb12c69f3f796d7d82 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 19 Sep 2023 12:36:11 +0200 Subject: [PATCH 28/44] EgtGeomKernel : - corretto un bug nella conversione surf NURBS to Bezier. --- SurfAux.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/SurfAux.cpp b/SurfAux.cpp index b428b30..b52568d 100644 --- a/SurfAux.cpp +++ b/SurfAux.cpp @@ -197,20 +197,20 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } } } - mPC_strip.resize( cnData.nDegU * ( nb + 1) + 1 , vCPV) ; - mW_strip.resize( cnData.nDegU * ( nb + 1) + 1, vV_W) ; - if ( ! cnData.bRat) - for ( int i = 0 ; i <= cnData.nDegU ; ++i) { - for ( int row = 0 ; row < cnData.nCPV ; ++row ) { - mPC_strip[i+ nb * cnData.nDegU][row] = mBC[i][row] ; - } + } + mPC_strip.resize( cnData.nDegU * ( nb + 1) + 1 , vCPV) ; + mW_strip.resize( cnData.nDegU * ( nb + 1) + 1, vV_W) ; + if ( ! cnData.bRat) + for ( int i = 0 ; i <= cnData.nDegU ; ++i) { + for ( int row = 0 ; row < cnData.nCPV ; ++row ) { + mPC_strip[i+ nb * cnData.nDegU][row] = mBC[i][row] ; } - else { - for ( int i = 0 ; i <= cnData.nDegU ; ++i) { - for ( int row = 0 ; row < cnData.nCPV ; ++row ) { - mPC_strip[i+ nb * cnData.nDegU][row] = mBC[i][row]/mW[i][row] ; - mW_strip[i+ nb * cnData.nDegU][row] = mW[i][row] ; - } + } + else { + for ( int i = 0 ; i <= cnData.nDegU ; ++i) { + for ( int row = 0 ; row < cnData.nCPV ; ++row ) { + mPC_strip[i+ nb * cnData.nDegU][row] = mBC[i][row]/mW[i][row] ; + mW_strip[i+ nb * cnData.nDegU][row] = mW[i][row] ; } } } From 381a137604b494aa71c4aab6ee9391c1aa73dcce Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Thu, 21 Sep 2023 14:38:22 +0200 Subject: [PATCH 29/44] EgtGeomKernel : - introduzione delle nurbs periodiche; da finire. --- CurveAux.cpp | 119 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 110 insertions(+), 9 deletions(-) diff --git a/CurveAux.cpp b/CurveAux.cpp index 795c6e4..7a7d0e2 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -510,14 +510,7 @@ CurveToArcsPerpExtrCurve( const ICurve* pCrv, double dLinTol, double dAngTolDeg) bool NurbsCurveCanonicalize( CNurbsData& cnData) { - // se periodica - if ( cnData.bPeriodic) { - // va trasformata in non-periodica (clamped) - // vedere The NurbsBook di Les Piegl e Tiller - // mancano esempi per testare - return false ; - } - // se con nodi extra + // se con nodi extra if ( cnData.bExtraKnotes) { int nKnotesNbr = int( cnData.vU.size()) ; if ( nKnotesNbr < 4) @@ -526,7 +519,91 @@ NurbsCurveCanonicalize( CNurbsData& cnData) for ( int i = 0 ; i < nKnotesNbr - 2 ; ++ i) cnData.vU[i] = cnData.vU[i+1] ; cnData.vU.resize( nKnotesNbr - 2) ; - return true ; + } + + // se periodica + if ( cnData.bPeriodic) { + CNurbsData cnData_clamped ; + // va trasformata in non-periodica (clamped) + // bisogna aumentare la molteplicità del primo e ultimo nodo fino ad arrivare al grado della nurbs + // e poi scartare nodi e punti fuori dalla regione clamped ( tra u_p e u_(m-p) ?) + + // comincio ad aumentare la molteplictià della fine della curva + int nCP = int( cnData.vCP.size()) ; + int nU = nCP + cnData.nDeg - 1 ; + 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[ cnData.nDeg - i] = cnData.vCP[nCP - 1 - i] ; + } + else { + for ( int i = 0 ; i <= cnData.nDeg ; ++ i) { + vBC[cnData.nDeg - i] = cnData.vCP[nCP - i] * cnData.vW[nCP - i] ; + vBW[cnData.nDeg - i] = cnData.vW[nCP - i] ; + } + } + + + double alpha ; + int b = nU - 1 ; + int a = b - 1 ; + int i = b ; + while ( abs( cnData.vU[b] - cnData.vU[b - 1]) < EPS_ZERO) + -- b ; + int mult = min( i - b + 1, cnData.nDeg) ; // mi aspetto che sia 1, ma comunque sarà < cnData.nDeg + int r = cnData.nDeg - mult ; + //// indice che si riferisce al vettore vCP + int c = nU - cnData.nDeg + 1 ; + // aggiusto a mano il vettore dei nodi ( aumento la molteplicità del primo valore fino a cnData.nDeg) + double dKnot = cnData.vU[ nU - 1] ; + cnData.vU.resize( nU + r) ; + for ( int t = 0 ; t < r ; ++t) { + cnData.vU[nU + t] = dKnot ; + } + + if ( mult < cnData.nDeg) { + // inserisco il nodo r volte + for ( int j = 1 ; j <= r ; ++ j) { + int L = b - cnData.nDeg + j ; + for ( int i = 0; i <= r - j ; ++i) { + alpha = (cnData.vU[b] - cnData.vU[L+i])/ ( cnData.vU[i+b+1] - cnData.vU[L+i]) ; + vBC[i] = alpha * vBC[i+1] + ( 1 - alpha) * vBC[i] ; + if ( cnData.bRat) { + vBW[i] = alpha * vBW[i+1] + ( 1 - alpha) * vBW[i] ; + } + } + cnData.vCP[L] = vBC[0] ; + //cnData.vCP[c+r-j-mult] = vBC[r-j] ; + if ( cnData.bRat ) { + cnData.vW[L] = vBW[0] ; + //cnData.vW[c+r-j-mult] = vBW[r-j] ; + } + } + } + // aggiungo i punti ottenuti alla curva. + cnData.vCP.resize( nCP + cnData.nDeg - mult) ; + for ( int p = 0 ; p < cnData.nDeg - mult ; ++p) { + cnData.vCP[ nCP + cnData.nDeg - mult - 1 - p] = vBC[cnData.nDeg - p] ; + } + if ( cnData.bRat ) { + cnData.vW.resize( nCP + cnData.nDeg - mult) ; + for ( int p = 0 ; p <= cnData.nDeg ; ++p) { + cnData.vW[ nCP + cnData.nDeg - mult - 1 - p] = vBW[cnData.nDeg - p] ; + } + } + + // aumento la molteplicità del primo punto + + // aggiusto a mano il vettore dei nodi ( aumento la molteplicità del primo valore fino a cnData.nDeg) + /// DA ADATTARE PER IL PRIMO + cnData.vU.resize( nU + cnData.nDeg - mult) ; + dKnot = cnData.vU[ nU] ; + for ( int t = nU - 1 ; t < cnData.nDeg - mult - 1 ; ++t) { + cnData.vU[t] = dKnot ; + } } return true ; @@ -710,6 +787,30 @@ NurbsToBezierCurve( const CNurbsData& cnData) } } + // se la curva ha grado 1, manca da aggiungere l'ultimo tratto + if ( cnData.nDeg == 1 ) { + // costruisco la curva di Bezier e la inserisco nella curva composita + PtrOwner pCrvBez( CreateCurveBezier()) ; + 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 ; + } + } + if ( ! pCrvBez->IsAPoint()) { + if ( ! pCrvCompo->AddCurve( Release( pCrvBez))) + return nullptr ; + } + } + // restituisco la curva composita return Release( pCrvCompo) ; } From d96ea77db79dcc52cfc186ce24e3a945e1c88b52 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 26 Sep 2023 12:22:32 +0200 Subject: [PATCH 30/44] EgtGeomKernel : - correzione su coordinate U e V dei vertici delle TriMesh. --- SurfTriMesh.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SurfTriMesh.h b/SurfTriMesh.h index 69b8a8a..dadd5ce 100644 --- a/SurfTriMesh.h +++ b/SurfTriMesh.h @@ -28,9 +28,9 @@ class SurfFlatRegion ; class StmVert { public : - StmVert( void) : ptP(), nIdTria( SVT_NULL), nFlag( 0), nTemp( 0), dU( -1), dV( -1) {} - StmVert( const Point3d& ptQ) : ptP( ptQ), nIdTria( SVT_NULL), nFlag( 0), nTemp( 0), dU( -1), dV( -1) {} - StmVert( const Point3d& ptQ, int nIdT, int nF) : ptP( ptQ), nIdTria( nIdT), nFlag( nF), nTemp( 0), dU( -1), dV( -1) {} + StmVert( void) : ptP(), dU( -1), dV( -1), nIdTria( SVT_NULL), nFlag( 0), nTemp( 0) {} + StmVert( const Point3d& ptQ) : ptP( ptQ), dU( -1), dV( -1), nIdTria( SVT_NULL), nFlag( 0), nTemp( 0) {} + StmVert( const Point3d& ptQ, int nIdT, int nF) : ptP( ptQ), dU( -1), dV( -1), nIdTria( nIdT), nFlag( nF), nTemp( 0) {} public : Point3d ptP ; double dU ; // parametro riferito alle coordinate del punto nello spazio parametrico ( nSpanU x 1000) ( nSpanV x 1000) From eccf683ef4efe385a146aa5464b1fd9347f26c6e Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 2 Oct 2023 14:55:04 +0200 Subject: [PATCH 31/44] EgtGeomKernel : - aggiunta delle coordintae U e V ai vertici delle TriMesh. --- StmFromTriangleSoup.cpp | 25 +++++++++---------- SurfTriMesh.cpp | 53 +++++++++++++++++++++++++++++++++++++---- SurfTriMesh.h | 27 +++++++++++++-------- 3 files changed, 78 insertions(+), 27 deletions(-) diff --git a/StmFromTriangleSoup.cpp b/StmFromTriangleSoup.cpp index 08db0c7..a1c7d04 100644 --- a/StmFromTriangleSoup.cpp +++ b/StmFromTriangleSoup.cpp @@ -76,37 +76,38 @@ StmFromTriangleSoup::AddTriangle( const Triangle3d& Tria) //---------------------------------------------------------------------------- bool -StmFromTriangleSoup::AddTriangle( const Point3d& ptP0, const Point3d& ptP1, const Point3d& ptP2) +StmFromTriangleSoup::AddTriangle( const Point3d& ptP0, const Point3d& ptP1, const Point3d& ptP2, + const double dU0, const double dV0,const double dU1, const double dV1,const double dU2, const double dV2) { - // verifico inizializzazione + // verifico inizializzazione if ( m_pSTM == nullptr) return false ; - // ciclo sui tre vertici + // ciclo sui tre vertici int nIdV[3] ; - if ( ( nIdV[0] = AddVertex( ptP0)) == SVT_NULL) + if ( ( nIdV[0] = AddVertex( ptP0, dU0, dV0)) == SVT_NULL) return false ; - if ( ( nIdV[1] = AddVertex( ptP1)) == SVT_NULL) + if ( ( nIdV[1] = AddVertex( ptP1, dU1, dV1)) == SVT_NULL) return false ; - if ( ( nIdV[2] = AddVertex( ptP2)) == SVT_NULL) + if ( ( nIdV[2] = AddVertex( ptP2, dU2, dV2)) == SVT_NULL) return false ; - // se i vertici sono tutti diversi tra loro, inserisco il triangolo + // se i vertici sono tutti diversi tra loro, inserisco il triangolo if ( nIdV[0] != nIdV[1] && nIdV[0] != nIdV[2] && nIdV[1] != nIdV[2]) { if ( m_pSTM->AddTriangle( nIdV) == SVT_NULL) - return false ; + return false ; } return true ; } //---------------------------------------------------------------------------- int -StmFromTriangleSoup::AddVertex( const Point3d& ptP) +StmFromTriangleSoup::AddVertex( const Point3d& ptP, const double dU, const double dV) { - // verifico se già presente + // verifico se già presente int nId ; if ( m_VertGrid.Find( ptP, 2 * EPS_SMALL, nId)) return nId ; - // aggiungo il vertice - if ( ( nId = m_pSTM->AddVertex( ptP)) == SVT_NULL) + // aggiungo il vertice + if ( ( nId = m_pSTM->AddVertex( ptP, dU, dV)) == SVT_NULL) return SVT_NULL ; m_VertGrid.InsertPoint( ptP, nId) ; return nId ; diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index 76ad9e9..f492645 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -107,18 +107,22 @@ SurfTriMesh::Clear( void) //---------------------------------------------------------------------------- int -SurfTriMesh::AddVertex( const Point3d& ptVert) +SurfTriMesh::AddVertex( const Point3d& ptVert, const double dU, const double dV) { - // imposto ricalcolo + // imposto ricalcolo m_nStatus = TO_VERIFY ; m_nParts = - 1 ; m_OGrMgr.Reset() ; ResetHashGrids3d() ; - // inserisco il vertice + // inserisco il vertice try { m_vVert.emplace_back( ptVert) ;} catch(...) { return SVT_NULL ;} - // ne determino l'indice - return int( m_vVert.size() - 1) ; + // ne determino l'indice + int nId = int( m_vVert.size() - 1) ; + // aggiugo le coordinate corrispondenti allo spazio parametrico + m_vVert[nId].dU = dU ; + m_vVert[nId].dV = dV ; + return nId ; } //---------------------------------------------------------------------------- @@ -475,6 +479,20 @@ SurfTriMesh::GetVertex( int nId, Point3d& ptP) const return true ; } +//---------------------------------------------------------------------------- +bool +SurfTriMesh::GetVertexParam( int nId, double& dU, double& dV) const +{ + // verifico esistenza del vertice + if ( nId < 0 || nId >= GetVertexSize() || m_vVert[nId].nIdTria == SVT_DEL) + return false ; + // recupero i dati + dU = m_vVert[nId].dU ; + dV = m_vVert[nId].dV ; + return true ; +} + + //---------------------------------------------------------------------------- int SurfTriMesh::GetFirstVertex( Point3d& ptP) const @@ -482,6 +500,13 @@ SurfTriMesh::GetFirstVertex( Point3d& ptP) const return GetNextVertex( SVT_NULL, ptP) ; } +//---------------------------------------------------------------------------- +int +SurfTriMesh::GetFirstVertexParam( int nId, double& dU, double& dV) const +{ + return GetNextVertexParam( SVT_NULL, dU, dV) ; +} + //---------------------------------------------------------------------------- int SurfTriMesh::GetNextVertex( int nId, Point3d& ptP) const @@ -499,6 +524,24 @@ SurfTriMesh::GetNextVertex( int nId, Point3d& ptP) const return nId ; } +//---------------------------------------------------------------------------- +int +SurfTriMesh::GetNextVertexParam( int nId, double& dU, double& dV) const +{ + // cerco il primo successivo valido + do { + nId ++ ; + } while ( nId < GetVertexSize() && m_vVert[nId].nIdTria == SVT_DEL) ; + // se oltrepassata fine + if ( nId >= GetVertexSize()) + return SVT_NULL ; + // recupero i dati + dU = m_vVert[nId].dU ; + dV = m_vVert[nId].dV ; + // ritorno indice triangolo corrente + return nId ; +} + //---------------------------------------------------------------------------- bool SurfTriMesh::GetTriangle( int nId, int nIdVert[3]) const diff --git a/SurfTriMesh.h b/SurfTriMesh.h index 6ae2946..eb4683e 100644 --- a/SurfTriMesh.h +++ b/SurfTriMesh.h @@ -27,15 +27,19 @@ class SurfFlatRegion ; // Classe Vertice class StmVert { - public : - StmVert( void) : ptP(), nIdTria( SVT_NULL), nFlag( 0), nTemp( 0) {} - StmVert( const Point3d& ptQ) : ptP( ptQ), nIdTria( SVT_NULL), nFlag( 0), nTemp( 0) {} - StmVert( const Point3d& ptQ, int nIdT, int nF) : ptP( ptQ), nIdTria( nIdT), nFlag( nF), nTemp( 0) {} - public : - Point3d ptP ; - int nIdTria ; - int nFlag ; - mutable int nTemp ; +public : + StmVert( void) : ptP(), dU( -1), dV( -1), nIdTria( SVT_NULL), nFlag( 0), nTemp( 0) {} + StmVert( const Point3d& ptQ) : ptP( ptQ), dU( -1), dV( -1), nIdTria( SVT_NULL), nFlag( 0), nTemp( 0) {} + StmVert( const Point3d& ptQ, int nIdT, int nF) : ptP( ptQ), dU( -1), dV( -1), nIdTria( nIdT), nFlag( nF), nTemp( 0) {} +public : + Point3d ptP ; + double dU ; // parametro riferito alle coordinate del punto nello spazio parametrico ( nSpanU x 1000) ( nSpanV x 1000) + // della sup di Bezier // -1 se non definito + double dV ; // parametro riferito alle coordinate del punto nello spazio parametrico ( nSpanU x 1000) ( nSpanV x 1000) + // della sup di Bezier // -1 se non definito + int nIdTria ; + int nFlag ; + mutable int nTemp ; } ; //---------------------------------------------------------------------------- @@ -215,7 +219,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW { m_dSmoothAng = std::max( dSmoothAngDeg, EPS_ANG_SMALL) ; m_dCosSmAng = cos( m_dSmoothAng * DEGTORAD) ; m_OGrMgr.Reset() ; } - int AddVertex( const Point3d& ptVert) override ; + int AddVertex( const Point3d& ptVert, const double dU = -1 , const double dV = -1) override ; bool MoveVertex( int nInd, const Point3d& ptNewVert) override ; int AddTriangle( const int nIdVert[3], int nTFlag = 0) override ; bool RemoveTriangle( int nId) override ; @@ -244,8 +248,11 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW double GetSmoothAngle( void) const override { return m_dSmoothAng ; } bool GetVertex( int nId, Point3d& ptP) const override ; + bool GetVertexParam( int nId, double& dU, double& dV) const override ; int GetFirstVertex( Point3d& ptP) const override ; + int GetFirstVertexParam( int nId, double& dU, double& dV) const override ; int GetNextVertex( int nId, Point3d& ptP) const override ; + int GetNextVertexParam( int nId, double& dU, double& dV) const override ; bool GetTriangle( int nId, int nIdVert[3]) const override ; int GetFirstTriangle( int nIdVert[3]) const override ; int GetNextTriangle( int nId, int nIdVert[3]) const override ; From 38146c6294a3cfe9e7a40a01f72c9b2ac506d924 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Wed, 4 Oct 2023 13:02:56 +0200 Subject: [PATCH 32/44] EgtGeomKernel : - corretto un errore nella ricerca info in un layer senza info. --- Attribs.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Attribs.cpp b/Attribs.cpp index a6552f0..61683f1 100644 --- a/Attribs.cpp +++ b/Attribs.cpp @@ -362,6 +362,8 @@ Attribs::GetAllInfo( STRVECTOR& vsInfo) const { // riservo spazio opportuno per il vettore delle stringhe vsInfo.clear() ; + if ( (int) m_slInfo.size() == 0) + return true ; vsInfo.reserve( m_slInfo.size()) ; // recupero tutte le info tranne il nome (se presente sempre al primo posto) auto iIter = m_slInfo.cbegin() ; From bf2a3f0e2241182f4d046a7f6ef32c1ea7152e02 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Wed, 4 Oct 2023 16:39:20 +0200 Subject: [PATCH 33/44] EgtGeomKernel : - implementazione delle nurbs periodiche; da sistemare. --- CurveAux.cpp | 225 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 179 insertions(+), 46 deletions(-) diff --git a/CurveAux.cpp b/CurveAux.cpp index 7a7d0e2..5e8051b 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -523,51 +523,61 @@ NurbsCurveCanonicalize( CNurbsData& cnData) // se periodica if ( cnData.bPeriodic) { - CNurbsData cnData_clamped ; // va trasformata in non-periodica (clamped) - // bisogna aumentare la molteplicità del primo e ultimo nodo fino ad arrivare al grado della nurbs - // e poi scartare nodi e punti fuori dalla regione clamped ( tra u_p e u_(m-p) ?) + // bisogna aumentare la molteplicità dei nodi u_p e u_(m-p) fino ad arrivare al grado della nurbs + // e poi scartare nodi e punti fuori dalla regione clamped ( al di fuori della regione u_p -> u_(m-p)) - // comincio ad aumentare la molteplictià della fine della curva + // comincio ad aumentare la molteplictià del nodo u_m-p int nCP = int( cnData.vCP.size()) ; int nU = nCP + cnData.nDeg - 1 ; + int nDeg = cnData.nDeg ; PNTVECTOR vBC ; - vBC.resize( cnData.nDeg + 1) ; + vBC.resize( nDeg + 1) ; DBLVECTOR vBW ; - vBW.resize( cnData.nDeg + 1) ; - if ( ! cnData.bRat) { - for ( int i = 0 ; i <= cnData.nDeg ; ++ i) - vBC[ cnData.nDeg - i] = cnData.vCP[nCP - 1 - i] ; - } - else { - for ( int i = 0 ; i <= cnData.nDeg ; ++ i) { - vBC[cnData.nDeg - i] = cnData.vCP[nCP - i] * cnData.vW[nCP - i] ; - vBW[cnData.nDeg - i] = cnData.vW[nCP - i] ; - } - } + vBW.resize( nDeg + 1) ; - - double alpha ; - int b = nU - 1 ; - int a = b - 1 ; + // trovo il nodo di cui aumentare la molteplicità e ne calcolo la molteplicità + int b = nU - nDeg - 1 ; int i = b ; while ( abs( cnData.vU[b] - cnData.vU[b - 1]) < EPS_ZERO) -- b ; - int mult = min( i - b + 1, cnData.nDeg) ; // mi aspetto che sia 1, ma comunque sarà < cnData.nDeg - int r = cnData.nDeg - mult ; - //// indice che si riferisce al vettore vCP - int c = nU - cnData.nDeg + 1 ; - // aggiusto a mano il vettore dei nodi ( aumento la molteplicità del primo valore fino a cnData.nDeg) - double dKnot = cnData.vU[ nU - 1] ; - cnData.vU.resize( nU + r) ; - for ( int t = 0 ; t < r ; ++t) { - cnData.vU[nU + t] = dKnot ; + int mult = min( i - b + 1, nDeg) ; // mi aspetto che sia 1, ma comunque sarà < cnData.nDeg + // recupero i punti da modificare + if ( ! cnData.bRat) { + for ( int i = 0 ; i <= nDeg - mult ; ++ i) + vBC[i] = cnData.vCP[b - nDeg + i] ; + } + else { + for ( int i = 0 ; i <= nDeg - mult ; ++ i) { + vBC[i] = cnData.vCP[b - nDeg + i] * cnData.vW[b - nDeg + i] ; + vBW[i] = cnData.vW[b - nDeg + i] ; + } } - if ( mult < cnData.nDeg) { + // salvo i punti inalterati + int r = nDeg - mult ; // numero di volte che dovrò inserire il nodo + cnData.vCP.resize( nCP + r) ; + for ( int p = b - mult ; p < nCP ; ++p) { + cnData.vCP[r + p] = cnData.vCP[p] ; + } + if ( cnData.bRat ) { + cnData.vW.resize( nCP + r) ; + for ( int p = b - mult ; p <= nCP ; ++p) { + cnData.vW[r + p] = cnData.vW[p] ; + } + } + + //DEBUG + PNTVECTOR vtPT = cnData.vCP ; + //DEBUG + + // procedo all'inserimento + int L = 0 ; + double alpha ; + if ( mult < nDeg) { // inserisco il nodo r volte for ( int j = 1 ; j <= r ; ++ j) { - int L = b - cnData.nDeg + j ; + L = b - nDeg + j ; for ( int i = 0; i <= r - j ; ++i) { alpha = (cnData.vU[b] - cnData.vU[L+i])/ ( cnData.vU[i+b+1] - cnData.vU[L+i]) ; vBC[i] = alpha * vBC[i+1] + ( 1 - alpha) * vBC[i] ; @@ -576,34 +586,157 @@ NurbsCurveCanonicalize( CNurbsData& cnData) } } cnData.vCP[L] = vBC[0] ; - //cnData.vCP[c+r-j-mult] = vBC[r-j] ; + cnData.vCP[b+r-j-mult] = vBC[r-j] ; if ( cnData.bRat ) { cnData.vW[L] = vBW[0] ; - //cnData.vW[c+r-j-mult] = vBW[r-j] ; + cnData.vW[b+r-j-mult] = vBW[r-j] ; } } } + + //DEBUG + PNTVECTOR vtPT_A = cnData.vCP ; + //DEBUG + // aggiungo i punti ottenuti alla curva. - cnData.vCP.resize( nCP + cnData.nDeg - mult) ; - for ( int p = 0 ; p < cnData.nDeg - mult ; ++p) { - cnData.vCP[ nCP + cnData.nDeg - mult - 1 - p] = vBC[cnData.nDeg - p] ; + for ( int p = L + 1 ; p < b - mult ; ++p) { + cnData.vCP[ b - nDeg + 1 + p] = vBC[p] ; } if ( cnData.bRat ) { - cnData.vW.resize( nCP + cnData.nDeg - mult) ; - for ( int p = 0 ; p <= cnData.nDeg ; ++p) { - cnData.vW[ nCP + cnData.nDeg - mult - 1 - p] = vBW[cnData.nDeg - p] ; + for ( int p = L + 1 ; p <= b - mult ; ++p) { + cnData.vW[ b - nDeg + 1 + p] = vBW[p] ; } } - // aumento la molteplicità del primo punto + //DEBUG + PNTVECTOR vtPT_B = cnData.vCP ; + //DEBUG - // aggiusto a mano il vettore dei nodi ( aumento la molteplicità del primo valore fino a cnData.nDeg) - /// DA ADATTARE PER IL PRIMO - cnData.vU.resize( nU + cnData.nDeg - mult) ; - dKnot = cnData.vU[ nU] ; - for ( int t = nU - 1 ; t < cnData.nDeg - mult - 1 ; ++t) { - cnData.vU[t] = dKnot ; + // allungo il vettore dei nodi e sposto gli ultimi nodi + cnData.vU.resize(nU + r) ; + for ( int p = nU - 1 ; p > b ; --p) + cnData.vU[p+r] = cnData.vU[p] ; + // aggiungo i nodi nuovi + for ( int p = 0 ; p < r ; ++p) + cnData.vU[b+1+p] = cnData.vU[b] ; + nU = nU + r ; + nCP = nCP + r ; + + //DEBUG + PNTVECTOR vtPT0 = cnData.vCP ; + //DEBUG + + // aumento la molteplicità del punto u_p + b = nDeg ; + i = b ; + while ( abs( cnData.vU[b] - cnData.vU[b - 1]) < EPS_ZERO) + -- b ; + mult = min( i - b + 1, nDeg) ; // mi aspetto che sia 1, ma comunque sarà < cnData.nDeg + // recupero i punti da modificare + if ( ! cnData.bRat) { + for ( int i = 0 ; i <= nDeg - mult ; ++ i) + vBC[i] = cnData.vCP[i] ; } + else { + for ( int i = 0 ; i <= nDeg - mult ; ++ i) { + vBC[i] = cnData.vCP[i] * cnData.vW[i] ; + vBW[i] = cnData.vW[i] ; + } + } + + r = nDeg - mult ; + // salvo i punti inalterati + cnData.vCP.resize( nCP + r) ; + for ( int p = b - mult ; p < nCP ; ++p) { + cnData.vCP[ r + p] = cnData.vCP[p] ; + } + if ( cnData.bRat ) { + cnData.vW.resize( nCP + r) ; + for ( int p = b - mult ; p <= nCP ; ++p) { + cnData.vW[ r + p] = cnData.vW[p] ; + } + } + + //DEBUG + PNTVECTOR vtPT1 = cnData.vCP ; + //DEBUG + + // procedo all'inserimento + L = 0 ; + if ( mult < nDeg) { + // inserisco il nodo r volte + for ( int j = 1 ; j <= r ; ++ j) { + L = b - nDeg + j ; + for ( int i = 0; i <= r - j ; ++i) { + alpha = (cnData.vU[b] - cnData.vU[L+i])/ ( cnData.vU[i+b+1] - cnData.vU[L+i]) ; + vBC[i] = alpha * vBC[i+1] + ( 1 - alpha) * vBC[i] ; + if ( cnData.bRat) { + vBW[i] = alpha * vBW[i+1] + ( 1 - alpha) * vBW[i] ; + } + } + cnData.vCP[L] = vBC[0] ; + cnData.vCP[b+r-j-mult] = vBC[r-j] ; + if ( cnData.bRat ) { + cnData.vW[L] = vBW[0] ; + cnData.vW[b+r-j-mult] = vBW[r-j] ; + } + } + } + + //DEBUG + PNTVECTOR vtPT2 = cnData.vCP ; + //DEBUG + + // aggiungo i punti ottenuti alla curva. + for ( int p = L + 1 ; p < b - mult ; ++p) { + cnData.vCP[ b - nDeg + 1 + p] = vBC[p] ; + } + if ( cnData.bRat ) { + for ( int p = L + 1 ; p <= b - mult ; ++p) { + cnData.vW[ b - nDeg + 1 + p] = vBW[p] ; + } + } + + //DEBUG + PNTVECTOR vtPT3 = cnData.vCP ; + //DEBUG + + // allungo il vettore dei nodi e sposto gli ultimi nodi + cnData.vU.resize(nU + r) ; + for ( int p = nU - 1 ; p > b ; --p) + cnData.vU[p+r] = cnData.vU[p] ; + // aggiungo i nodi nuovi + for ( int p = 0 ; p < r ; ++p) + cnData.vU[b+1+p] = cnData.vU[b] ; + nU = nU + r ; + nCP = nCP + r ; + + //DEBUG + PNTVECTOR vtPT4 = cnData.vCP ; + //DEBUG + + + // rendo la curva chiusa e non periodica eliminando i primi e gli ultimi nDeg punti e nodi + cnData.bPeriodic = false ; + nCP = nCP - 2 * nDeg; + nU = nU - 2 * nDeg ; + PNTVECTOR vCP_clamped ; + vCP_clamped.resize( nCP) ; + DBLVECTOR vU_clamped ; + vU_clamped.resize( nU) ; + for ( int i = 0 ; i < nCP ; ++i) { + vCP_clamped[i] = cnData.vCP[i + nDeg] ; + } + cnData.vCP = vCP_clamped ; + for ( int i = 0 ; i < nU ; ++i) { + vU_clamped[i] = cnData.vU[i + nDeg] ; + } + cnData.vU = vU_clamped ; + + //DEBUG + PNTVECTOR vtPT5 = cnData.vCP ; + //DEBUG + } return true ; From 10dd5828ce040132bfa09a084462e73c03cef161 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Thu, 5 Oct 2023 17:29:15 +0200 Subject: [PATCH 34/44] EgtGeomKernel : - corretti errori nel clamping delle nurbs periodiche. --- CurveAux.cpp | 50 +++++++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/CurveAux.cpp b/CurveAux.cpp index 5e8051b..bb0d084 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -527,7 +527,7 @@ NurbsCurveCanonicalize( CNurbsData& cnData) // bisogna aumentare la molteplicità dei nodi u_p e u_(m-p) fino ad arrivare al grado della nurbs // e poi scartare nodi e punti fuori dalla regione clamped ( al di fuori della regione u_p -> u_(m-p)) - // comincio ad aumentare la molteplictià del nodo u_m-p + // comincio ad aumentare la molteplictià del nodo u_m-p+1 int nCP = int( cnData.vCP.size()) ; int nU = nCP + cnData.nDeg - 1 ; int nDeg = cnData.nDeg ; @@ -537,7 +537,7 @@ NurbsCurveCanonicalize( CNurbsData& cnData) vBW.resize( nDeg + 1) ; // trovo il nodo di cui aumentare la molteplicità e ne calcolo la molteplicità - int b = nU - nDeg - 1 ; + int b = nU - nDeg - 1 +1; int i = b ; while ( abs( cnData.vU[b] - cnData.vU[b - 1]) < EPS_ZERO) -- b ; @@ -545,24 +545,28 @@ NurbsCurveCanonicalize( CNurbsData& cnData) // recupero i punti da modificare if ( ! cnData.bRat) { for ( int i = 0 ; i <= nDeg - mult ; ++ i) - vBC[i] = cnData.vCP[b - nDeg + i] ; + vBC[i] = cnData.vCP[b - nDeg + 1 + i] ; } else { for ( int i = 0 ; i <= nDeg - mult ; ++ i) { - vBC[i] = cnData.vCP[b - nDeg + i] * cnData.vW[b - nDeg + i] ; - vBW[i] = cnData.vW[b - nDeg + i] ; + vBC[i] = cnData.vCP[b - nDeg + 1 + i] * cnData.vW[b - nDeg + 1 + i] ; + vBW[i] = cnData.vW[b - nDeg + 1 + i] ; } } + //DEBUG + PNTVECTOR vtPT_0 = cnData.vCP ; + //DEBUG + // salvo i punti inalterati int r = nDeg - mult ; // numero di volte che dovrò inserire il nodo cnData.vCP.resize( nCP + r) ; - for ( int p = b - mult ; p < nCP ; ++p) { + for ( int p = nCP - 1 ; p >= b - mult ; --p) { cnData.vCP[r + p] = cnData.vCP[p] ; } if ( cnData.bRat ) { cnData.vW.resize( nCP + r) ; - for ( int p = b - mult ; p <= nCP ; ++p) { + for ( int p = nCP - 1 ; p >= b - mult ; --p) { cnData.vW[r + p] = cnData.vW[p] ; } } @@ -600,11 +604,13 @@ NurbsCurveCanonicalize( CNurbsData& cnData) // aggiungo i punti ottenuti alla curva. for ( int p = L + 1 ; p < b - mult ; ++p) { - cnData.vCP[ b - nDeg + 1 + p] = vBC[p] ; + //cnData.vCP[ b - nDeg + 1 + p] = vBC[p-L] ; + cnData.vCP[p] = vBC[p-L] ; } if ( cnData.bRat ) { for ( int p = L + 1 ; p <= b - mult ; ++p) { - cnData.vW[ b - nDeg + 1 + p] = vBW[p] ; + //cnData.vW[ b - nDeg + 1 + p] = vBW[p-L] ; + cnData.vW[p] = vBW[p-L] ; } } @@ -626,8 +632,8 @@ NurbsCurveCanonicalize( CNurbsData& cnData) PNTVECTOR vtPT0 = cnData.vCP ; //DEBUG - // aumento la molteplicità del punto u_p - b = nDeg ; + // aumento la molteplicità del punto u_p-1 + b = nDeg -1; i = b ; while ( abs( cnData.vU[b] - cnData.vU[b - 1]) < EPS_ZERO) -- b ; @@ -647,13 +653,13 @@ NurbsCurveCanonicalize( CNurbsData& cnData) r = nDeg - mult ; // salvo i punti inalterati cnData.vCP.resize( nCP + r) ; - for ( int p = b - mult ; p < nCP ; ++p) { - cnData.vCP[ r + p] = cnData.vCP[p] ; + for ( int p = nCP - 1 ; p >= b - mult ; --p) { + cnData.vCP[r + p] = cnData.vCP[p] ; } if ( cnData.bRat ) { cnData.vW.resize( nCP + r) ; - for ( int p = b - mult ; p <= nCP ; ++p) { - cnData.vW[ r + p] = cnData.vW[p] ; + for ( int p = nCP - 1 ; p >= b - mult ; --p) { + cnData.vW[r + p] = cnData.vW[p] ; } } @@ -689,11 +695,13 @@ NurbsCurveCanonicalize( CNurbsData& cnData) // aggiungo i punti ottenuti alla curva. for ( int p = L + 1 ; p < b - mult ; ++p) { - cnData.vCP[ b - nDeg + 1 + p] = vBC[p] ; + //cnData.vCP[ b - nDeg + 1 + p] = vBC[p-L] ; + cnData.vCP[p] = vBC[p-L] ; } if ( cnData.bRat ) { for ( int p = L + 1 ; p <= b - mult ; ++p) { - cnData.vW[ b - nDeg + 1 + p] = vBW[p] ; + //cnData.vW[ b - nDeg + 1 + p] = vBW[p-L] ; + cnData.vW[p] = vBW[p-L] ; } } @@ -718,18 +726,18 @@ NurbsCurveCanonicalize( CNurbsData& cnData) // rendo la curva chiusa e non periodica eliminando i primi e gli ultimi nDeg punti e nodi cnData.bPeriodic = false ; - nCP = nCP - 2 * nDeg; - nU = nU - 2 * nDeg ; + nCP = nCP - 2 * nDeg +2; + nU = nU - 2 * nDeg +2; PNTVECTOR vCP_clamped ; vCP_clamped.resize( nCP) ; DBLVECTOR vU_clamped ; vU_clamped.resize( nU) ; for ( int i = 0 ; i < nCP ; ++i) { - vCP_clamped[i] = cnData.vCP[i + nDeg] ; + vCP_clamped[i] = cnData.vCP[i + nDeg-1] ; } cnData.vCP = vCP_clamped ; for ( int i = 0 ; i < nU ; ++i) { - vU_clamped[i] = cnData.vU[i + nDeg] ; + vU_clamped[i] = cnData.vU[i + nDeg-1] ; } cnData.vU = vU_clamped ; From 9b34154a16f5f086a9b8c0cdd179724dcfd13bf7 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Fri, 6 Oct 2023 09:08:12 +0200 Subject: [PATCH 35/44] EgtGeomKernel : - corretti gli ultimi errori nel clamping delle curve periodiche. Manca : - estensione alle superfici. --- CurveAux.cpp | 107 ++++++++++++--------------------------------------- 1 file changed, 24 insertions(+), 83 deletions(-) diff --git a/CurveAux.cpp b/CurveAux.cpp index bb0d084..4dfefef 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -524,8 +524,11 @@ NurbsCurveCanonicalize( CNurbsData& cnData) // se periodica if ( cnData.bPeriodic) { // va trasformata in non-periodica (clamped) - // bisogna aumentare la molteplicità dei nodi u_p e u_(m-p) fino ad arrivare al grado della nurbs - // e poi scartare nodi e punti fuori dalla regione clamped ( al di fuori della regione u_p -> u_(m-p)) + // bisogna aumentare la molteplicità dei nodi u_p-1 e u_(m-p+1) fino ad arrivare al grado della nurbs + // e poi scartare nodi e punti fuori dalla regione clamped ( al di fuori della regione u_p-1 -> u_(m-p+1)) + + // l'agoritmo per l'inserimento dei nodi l' A5.1 del libro delle Nurbs ( Piegl e Tiller), con qualche modifica + // agli indici perché uso u_p-1 e u_(m-p+1), anziché u_p e u_m-p // comincio ad aumentare la molteplictià del nodo u_m-p+1 int nCP = int( cnData.vCP.size()) ; @@ -554,70 +557,45 @@ NurbsCurveCanonicalize( CNurbsData& cnData) } } - //DEBUG - PNTVECTOR vtPT_0 = cnData.vCP ; - //DEBUG - // salvo i punti inalterati int r = nDeg - mult ; // numero di volte che dovrò inserire il nodo cnData.vCP.resize( nCP + r) ; - for ( int p = nCP - 1 ; p >= b - mult ; --p) { + for ( int p = nCP - 1 ; p > b - mult ; --p) { cnData.vCP[r + p] = cnData.vCP[p] ; } if ( cnData.bRat ) { cnData.vW.resize( nCP + r) ; - for ( int p = nCP - 1 ; p >= b - mult ; --p) { + for ( int p = nCP - 1 ; p > b - mult ; --p) { cnData.vW[r + p] = cnData.vW[p] ; } } - //DEBUG - PNTVECTOR vtPT = cnData.vCP ; - //DEBUG - // procedo all'inserimento int L = 0 ; double alpha ; + double num, den ; if ( mult < nDeg) { // inserisco il nodo r volte for ( int j = 1 ; j <= r ; ++ j) { L = b - nDeg + j ; for ( int i = 0; i <= r - j ; ++i) { + num = (cnData.vU[b] - cnData.vU[L+i]) ; + den = ( cnData.vU[i+b+1] - cnData.vU[L+i]) ; alpha = (cnData.vU[b] - cnData.vU[L+i])/ ( cnData.vU[i+b+1] - cnData.vU[L+i]) ; vBC[i] = alpha * vBC[i+1] + ( 1 - alpha) * vBC[i] ; if ( cnData.bRat) { vBW[i] = alpha * vBW[i+1] + ( 1 - alpha) * vBW[i] ; } } - cnData.vCP[L] = vBC[0] ; - cnData.vCP[b+r-j-mult] = vBC[r-j] ; + cnData.vCP[L+1] = vBC[0] ; + cnData.vCP[b+nDeg-j-mult] = vBC[r-j] ; if ( cnData.bRat ) { - cnData.vW[L] = vBW[0] ; - cnData.vW[b+r-j-mult] = vBW[r-j] ; + cnData.vW[L+1] = vBW[0] ; + cnData.vW[b+nDeg-j-mult] = vBW[r-j] ; } } } - //DEBUG - PNTVECTOR vtPT_A = cnData.vCP ; - //DEBUG - - // aggiungo i punti ottenuti alla curva. - for ( int p = L + 1 ; p < b - mult ; ++p) { - //cnData.vCP[ b - nDeg + 1 + p] = vBC[p-L] ; - cnData.vCP[p] = vBC[p-L] ; - } - if ( cnData.bRat ) { - for ( int p = L + 1 ; p <= b - mult ; ++p) { - //cnData.vW[ b - nDeg + 1 + p] = vBW[p-L] ; - cnData.vW[p] = vBW[p-L] ; - } - } - - //DEBUG - PNTVECTOR vtPT_B = cnData.vCP ; - //DEBUG - // allungo il vettore dei nodi e sposto gli ultimi nodi cnData.vU.resize(nU + r) ; for ( int p = nU - 1 ; p > b ; --p) @@ -628,10 +606,6 @@ NurbsCurveCanonicalize( CNurbsData& cnData) nU = nU + r ; nCP = nCP + r ; - //DEBUG - PNTVECTOR vtPT0 = cnData.vCP ; - //DEBUG - // aumento la molteplicità del punto u_p-1 b = nDeg -1; i = b ; @@ -653,20 +627,16 @@ NurbsCurveCanonicalize( CNurbsData& cnData) r = nDeg - mult ; // salvo i punti inalterati cnData.vCP.resize( nCP + r) ; - for ( int p = nCP - 1 ; p >= b - mult ; --p) { + for ( int p = nCP - 1 ; p > b - mult ; --p) { cnData.vCP[r + p] = cnData.vCP[p] ; } if ( cnData.bRat ) { cnData.vW.resize( nCP + r) ; - for ( int p = nCP - 1 ; p >= b - mult ; --p) { + for ( int p = nCP - 1 ; p > b - mult ; --p) { cnData.vW[r + p] = cnData.vW[p] ; } } - //DEBUG - PNTVECTOR vtPT1 = cnData.vCP ; - //DEBUG - // procedo all'inserimento L = 0 ; if ( mult < nDeg) { @@ -680,35 +650,15 @@ NurbsCurveCanonicalize( CNurbsData& cnData) vBW[i] = alpha * vBW[i+1] + ( 1 - alpha) * vBW[i] ; } } - cnData.vCP[L] = vBC[0] ; - cnData.vCP[b+r-j-mult] = vBC[r-j] ; + cnData.vCP[L+1] = vBC[0] ; + cnData.vCP[b+nDeg-j-mult] = vBC[r-j] ; if ( cnData.bRat ) { - cnData.vW[L] = vBW[0] ; - cnData.vW[b+r-j-mult] = vBW[r-j] ; + cnData.vW[L+1] = vBW[0] ; + cnData.vW[b+nDeg-j-mult] = vBW[r-j] ; } } } - //DEBUG - PNTVECTOR vtPT2 = cnData.vCP ; - //DEBUG - - // aggiungo i punti ottenuti alla curva. - for ( int p = L + 1 ; p < b - mult ; ++p) { - //cnData.vCP[ b - nDeg + 1 + p] = vBC[p-L] ; - cnData.vCP[p] = vBC[p-L] ; - } - if ( cnData.bRat ) { - for ( int p = L + 1 ; p <= b - mult ; ++p) { - //cnData.vW[ b - nDeg + 1 + p] = vBW[p-L] ; - cnData.vW[p] = vBW[p-L] ; - } - } - - //DEBUG - PNTVECTOR vtPT3 = cnData.vCP ; - //DEBUG - // allungo il vettore dei nodi e sposto gli ultimi nodi cnData.vU.resize(nU + r) ; for ( int p = nU - 1 ; p > b ; --p) @@ -719,32 +669,23 @@ NurbsCurveCanonicalize( CNurbsData& cnData) nU = nU + r ; nCP = nCP + r ; - //DEBUG - PNTVECTOR vtPT4 = cnData.vCP ; - //DEBUG - - // rendo la curva chiusa e non periodica eliminando i primi e gli ultimi nDeg punti e nodi cnData.bPeriodic = false ; - nCP = nCP - 2 * nDeg +2; - nU = nU - 2 * nDeg +2; + nCP = nCP - 2 * ( nDeg - 1); + nU = nU - 2 * ( nDeg - 1); PNTVECTOR vCP_clamped ; vCP_clamped.resize( nCP) ; DBLVECTOR vU_clamped ; vU_clamped.resize( nU) ; for ( int i = 0 ; i < nCP ; ++i) { - vCP_clamped[i] = cnData.vCP[i + nDeg-1] ; + vCP_clamped[i] = cnData.vCP[i + nDeg - 1] ; } cnData.vCP = vCP_clamped ; for ( int i = 0 ; i < nU ; ++i) { - vU_clamped[i] = cnData.vU[i + nDeg-1] ; + vU_clamped[i] = cnData.vU[i + nDeg - 1] ; } cnData.vU = vU_clamped ; - //DEBUG - PNTVECTOR vtPT5 = cnData.vCP ; - //DEBUG - } return true ; From e44b08d669e90527b9278d0f8826a392569234b4 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 17 Oct 2023 10:02:08 +0200 Subject: [PATCH 36/44] EgtGeomKernel : - aggiunta la gestione delle superfici NURBS periodiche - correzione formattazione e nomi. --- CurveAux.cpp | 75 ++++++----- SurfAux.cpp | 373 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 267 insertions(+), 181 deletions(-) diff --git a/CurveAux.cpp b/CurveAux.cpp index 4dfefef..d32f60d 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -539,13 +539,13 @@ NurbsCurveCanonicalize( CNurbsData& cnData) DBLVECTOR vBW ; vBW.resize( nDeg + 1) ; - // trovo il nodo di cui aumentare la molteplicità e ne calcolo la molteplicità + // trovo il nodo di cui aumentare la molteplicità e ne calcolo la molteplicità int b = nU - nDeg - 1 +1; int i = b ; while ( abs( cnData.vU[b] - cnData.vU[b - 1]) < EPS_ZERO) -- b ; - int mult = min( i - b + 1, nDeg) ; // mi aspetto che sia 1, ma comunque sarà < cnData.nDeg - // recupero i punti da modificare + int mult = min( i - b + 1, nDeg) ; // mi aspetto che sia 1, ma comunque sarà < nDeg + // recupero i punti da modificare if ( ! cnData.bRat) { for ( int i = 0 ; i <= nDeg - mult ; ++ i) vBC[i] = cnData.vCP[b - nDeg + 1 + i] ; @@ -557,7 +557,7 @@ NurbsCurveCanonicalize( CNurbsData& cnData) } } - // salvo i punti inalterati + // salvo i punti inalterati int r = nDeg - mult ; // numero di volte che dovrò inserire il nodo cnData.vCP.resize( nCP + r) ; for ( int p = nCP - 1 ; p > b - mult ; --p) { @@ -570,49 +570,49 @@ NurbsCurveCanonicalize( CNurbsData& cnData) } } - // procedo all'inserimento + // procedo all'inserimento int L = 0 ; double alpha ; double num, den ; if ( mult < nDeg) { - // inserisco il nodo r volte + // inserisco il nodo r volte for ( int j = 1 ; j <= r ; ++ j) { L = b - nDeg + j ; for ( int i = 0; i <= r - j ; ++i) { - num = (cnData.vU[b] - cnData.vU[L+i]) ; - den = ( cnData.vU[i+b+1] - cnData.vU[L+i]) ; - alpha = (cnData.vU[b] - cnData.vU[L+i])/ ( cnData.vU[i+b+1] - cnData.vU[L+i]) ; - vBC[i] = alpha * vBC[i+1] + ( 1 - alpha) * vBC[i] ; + num = (cnData.vU[b] - cnData.vU[L + i]) ; + den = ( cnData.vU[i + b + 1] - cnData.vU[L + i]) ; + alpha = (cnData.vU[b] - cnData.vU[L + i])/ ( cnData.vU[i + b + 1] - cnData.vU[L + i]) ; + vBC[i] = alpha * vBC[i +1 ] + ( 1 - alpha) * vBC[i] ; if ( cnData.bRat) { - vBW[i] = alpha * vBW[i+1] + ( 1 - alpha) * vBW[i] ; + vBW[i] = alpha * vBW[i + 1] + ( 1 - alpha) * vBW[i] ; } } - cnData.vCP[L+1] = vBC[0] ; - cnData.vCP[b+nDeg-j-mult] = vBC[r-j] ; + cnData.vCP[L + 1] = vBC[0] ; + cnData.vCP[b + nDeg - j - mult] = vBC[r - j] ; if ( cnData.bRat ) { - cnData.vW[L+1] = vBW[0] ; - cnData.vW[b+nDeg-j-mult] = vBW[r-j] ; + cnData.vW[L + 1] = vBW[0] ; + cnData.vW[b + nDeg - j - mult] = vBW[r-j] ; } } } - // allungo il vettore dei nodi e sposto gli ultimi nodi + // allungo il vettore dei nodi e sposto gli ultimi nodi cnData.vU.resize(nU + r) ; for ( int p = nU - 1 ; p > b ; --p) - cnData.vU[p+r] = cnData.vU[p] ; - // aggiungo i nodi nuovi + cnData.vU[p + r] = cnData.vU[p] ; + // aggiungo i nodi nuovi for ( int p = 0 ; p < r ; ++p) - cnData.vU[b+1+p] = cnData.vU[b] ; + cnData.vU[b + 1 + p] = cnData.vU[b] ; nU = nU + r ; nCP = nCP + r ; - // aumento la molteplicità del punto u_p-1 + // aumento la molteplicità del punto u_p-1 b = nDeg -1; i = b ; while ( abs( cnData.vU[b] - cnData.vU[b - 1]) < EPS_ZERO) -- b ; mult = min( i - b + 1, nDeg) ; // mi aspetto che sia 1, ma comunque sarà < cnData.nDeg - // recupero i punti da modificare + // recupero i punti da modificare if ( ! cnData.bRat) { for ( int i = 0 ; i <= nDeg - mult ; ++ i) vBC[i] = cnData.vCP[i] ; @@ -625,7 +625,7 @@ NurbsCurveCanonicalize( CNurbsData& cnData) } r = nDeg - mult ; - // salvo i punti inalterati + // salvo i punti inalterati cnData.vCP.resize( nCP + r) ; for ( int p = nCP - 1 ; p > b - mult ; --p) { cnData.vCP[r + p] = cnData.vCP[p] ; @@ -637,39 +637,39 @@ NurbsCurveCanonicalize( CNurbsData& cnData) } } - // procedo all'inserimento + // procedo all'inserimento L = 0 ; if ( mult < nDeg) { - // inserisco il nodo r volte + // inserisco il nodo r volte for ( int j = 1 ; j <= r ; ++ j) { L = b - nDeg + j ; for ( int i = 0; i <= r - j ; ++i) { - alpha = (cnData.vU[b] - cnData.vU[L+i])/ ( cnData.vU[i+b+1] - cnData.vU[L+i]) ; - vBC[i] = alpha * vBC[i+1] + ( 1 - alpha) * vBC[i] ; + alpha = (cnData.vU[b] - cnData.vU[L + i])/ ( cnData.vU[i + b + 1] - cnData.vU[L + i]) ; + vBC[i] = alpha * vBC[i + 1] + ( 1 - alpha) * vBC[i] ; if ( cnData.bRat) { - vBW[i] = alpha * vBW[i+1] + ( 1 - alpha) * vBW[i] ; + vBW[i] = alpha * vBW[i + 1] + ( 1 - alpha) * vBW[i] ; } } - cnData.vCP[L+1] = vBC[0] ; - cnData.vCP[b+nDeg-j-mult] = vBC[r-j] ; + cnData.vCP[L + 1] = vBC[0] ; + cnData.vCP[b + nDeg - j - mult] = vBC[r - j] ; if ( cnData.bRat ) { - cnData.vW[L+1] = vBW[0] ; - cnData.vW[b+nDeg-j-mult] = vBW[r-j] ; + cnData.vW[L + 1] = vBW[0] ; + cnData.vW[b + nDeg - j - mult] = vBW[r - j] ; } } } - // allungo il vettore dei nodi e sposto gli ultimi nodi + // allungo il vettore dei nodi e sposto gli ultimi nodi cnData.vU.resize(nU + r) ; for ( int p = nU - 1 ; p > b ; --p) cnData.vU[p+r] = cnData.vU[p] ; - // aggiungo i nodi nuovi + // aggiungo i nodi nuovi for ( int p = 0 ; p < r ; ++p) - cnData.vU[b+1+p] = cnData.vU[b] ; + cnData.vU[b + 1 + p] = cnData.vU[b] ; nU = nU + r ; nCP = nCP + r ; - // rendo la curva chiusa e non periodica eliminando i primi e gli ultimi nDeg punti e nodi + // rendo la curva chiusa e non periodica eliminando i primi e gli ultimi nDeg punti e nodi cnData.bPeriodic = false ; nCP = nCP - 2 * ( nDeg - 1); nU = nU - 2 * ( nDeg - 1); @@ -678,7 +678,10 @@ NurbsCurveCanonicalize( CNurbsData& cnData) DBLVECTOR vU_clamped ; vU_clamped.resize( nU) ; for ( int i = 0 ; i < nCP ; ++i) { - vCP_clamped[i] = cnData.vCP[i + nDeg - 1] ; + if ( ! cnData.bRat) + vCP_clamped[i] = cnData.vCP[i + nDeg - 1] ; + else + vCP_clamped[i] = cnData.vCP[i + nDeg - 1] / cnData.vW[i + nDeg - 1] ; } cnData.vCP = vCP_clamped ; for ( int i = 0 ; i < nU ; ++i) { diff --git a/SurfAux.cpp b/SurfAux.cpp index b52568d..41ebeb5 100644 --- a/SurfAux.cpp +++ b/SurfAux.cpp @@ -26,9 +26,92 @@ using namespace std ; +bool +NurbsSurfaceCanonicalize( SNurbsSurfData& snData) +{ + // per rendere una superficie non periodica devo recuperare i punti di controllo, suddivisi in isoparametriche lungo una direzione + // e applicare la trasformazione ad ogni isoparametrica, sostituendola poi a quella originale. ( si mantiene il numero di punti) + if ( snData.bPeriodicU ) { + bool bIsRational = snData.bRat ; + // vettore dei nodi + DBLVECTOR vU ; + int nKnot = (int) snData.vU.size() ; + for ( int k = 0 ; k < nKnot ; ++k ) { + double dKnot = snData.vU[k] ; + vU.push_back( dKnot) ; + } + for( int j = 0 ; j < snData.nCPV ; ++j) { + CNurbsData nuCurve ; + nuCurve.bPeriodic = true ; + nuCurve.nDeg = snData.nDegU ; + nuCurve.vU = vU ; + // vettore dei punti di controllo + PNTVECTOR vPtCtrl ; + // vettore dei pesi + DBLVECTOR vWeCtrl ; + for ( int i = 0 ; i < snData.nCPU ; ++i ) { + if ( bIsRational) { + vPtCtrl.push_back( snData.mCP[i][j] / snData.mW[i][j]) ; + vWeCtrl.push_back( snData.mW[i][j]) ; + } + else + vPtCtrl.push_back( snData.mCP[i][j]) ; + } + nuCurve.vCP = vPtCtrl ; + nuCurve.vW = vWeCtrl ; + // i punti dell' oggetto nuCurve devono essere in forma non omogenea + NurbsCurveCanonicalize( nuCurve) ; + for ( int i = 0 ; i < snData.nCPU ; ++i) { + snData.mCP[i][j] = nuCurve.vCP[i] ; + } + snData.vU = nuCurve.vU ; + } + snData.bPeriodicU = false ; + } + if ( snData.bPeriodicV ) { + bool bIsRational = snData.bRat ; + // vettore dei nodi + DBLVECTOR vV ; + int nKnot = (int) snData.vV.size() ; + for ( int k = 0 ; k < nKnot ; ++k ) { + double dKnot = snData.vV[k] ; + vV.push_back( dKnot) ; + } + for( int i = 0 ; i < snData.nCPU ; ++i) { + CNurbsData nuCurve ; + nuCurve.bPeriodic = true ; + nuCurve.nDeg = snData.nDegV ; + nuCurve.vU = vV ; + // vettore dei punti di controllo + PNTVECTOR vPtCtrl ; + // vettore dei pesi + DBLVECTOR vWeCtrl ; + for ( int j = 0 ; j < snData.nCPV ; ++j ) { + if ( bIsRational) { + vPtCtrl.push_back( snData.mCP[i][j] / snData.mW[i][j]) ; + vWeCtrl.push_back( snData.mW[i][j]) ; + } + else + vPtCtrl.push_back( snData.mCP[i][j]) ; + } + nuCurve.vCP = vPtCtrl ; + nuCurve.vW = vWeCtrl ; + // i punti dell' oggetto nuCurve devono essere in forma non omogenea + NurbsCurveCanonicalize( nuCurve) ; + for ( int j = 0 ; j < snData.nCPV ; ++j ) { + snData.mCP[i][j] = nuCurve.vCP[j] ; + } + snData.vV = nuCurve.vU ; + } + snData.bPeriodicV = false ; + } + return true; +} + + //---------------------------------------------------------------------------- ISurf* -NurbsToBezierSurface(const CNurbsSurfData& cnData) +NurbsToBezierSurface(const SNurbsSurfData& snData) { //INTVECTOR vInt_sub( 10) ; //INTMATRIX vInt( 10, vInt_sub) ; @@ -45,37 +128,37 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) // la superficie Nurbs deve essere in forma canonica - if ( cnData.bPeriodicU || cnData.bPeriodicV || cnData.bExtraKnotes ) + if ( snData.bPeriodicU || snData.bPeriodicV || snData.bExtraKnotes ) return nullptr ; // controllo sul numero dei nodi - int nU = cnData.nCPU + cnData.nDegU - 1 ; - int nV = cnData.nCPV + cnData.nDegV - 1 ; + int nU = snData.nCPU + snData.nDegU - 1 ; + int nV = snData.nCPV + snData.nDegV - 1 ; // controllo nodi e punti di controllo - //if ( nU != int( cnData.vU.size()) || nV != int( cnData.vV.size()) || cnData.nCPU * cnData.nCPV != int( cnData.vCP.size())) - if ( nU != int(cnData.vU.size()) || nV != int(cnData.vV.size())) { + //if ( nU != int( snData.vU.size()) || nV != int( snData.vV.size()) || snData.nCPU * snData.nCPV != int( snData.vCP.size())) + if ( nU != int(snData.vU.size()) || nV != int(snData.vV.size())) { return nullptr ; } //// numero degli intervalli - //int nInt = nU - 2 * cnData.nDeg + 1 ; + //int nInt = nU - 2 * snData.nDeg + 1 ; // verifico le condizioni agli estremi sui nodi (i primi nDeg nodi e gli ultimi nDeg nodi devono essere uguali tra loro) bool bOk = true ; // direzione U - for ( int i = 1 ; i < cnData.nDegU ; ++ i) { - if ( abs( cnData.vU[i] - cnData.vU[0]) >= EPS_ZERO) + for ( int i = 1 ; i < snData.nDegU ; ++ i) { + if ( abs( snData.vU[i] - snData.vU[0]) >= EPS_ZERO) bOk = false ; } - for ( int i = 1 ; i < cnData.nDegU ; ++ i) { - if ( abs( cnData.vU[nU - 1 - i] - cnData.vU[nU - 1]) >= EPS_ZERO) + for ( int i = 1 ; i < snData.nDegU ; ++ i) { + if ( abs( snData.vU[nU - 1 - i] - snData.vU[nU - 1]) >= EPS_ZERO) bOk = false ; } // direzione V - for ( int i = 1 ; i < cnData.nDegV ; ++ i) { - if ( abs( cnData.vV[i] - cnData.vV[0]) >= EPS_ZERO) + for ( int i = 1 ; i < snData.nDegV ; ++ i) { + if ( abs( snData.vV[i] - snData.vV[0]) >= EPS_ZERO) bOk = false ; } - for ( int i = 1 ; i < cnData.nDegV ; ++ i) { - if ( abs( cnData.vV[nV - 1 - i] - cnData.vV[nV - 1]) >= EPS_ZERO) + for ( int i = 1 ; i < snData.nDegV ; ++ i) { + if ( abs( snData.vV[nV - 1 - i] - snData.vV[nV - 1]) >= EPS_ZERO) bOk = false ; } if ( ! bOk) @@ -88,21 +171,21 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) // if ( IsNull( pCrvBez)) // return nullptr ; // // la inizializzo - // if ( ! pCrvBez->Init( cnData.nDeg, cnData.bRat)) + // if ( ! pCrvBez->Init( snData.nDeg, snData.bRat)) // return nullptr ; - // for ( int i = 0 ; i <= cnData.nDeg ; ++ i) { - // if ( ! cnData.bRat) { - // if ( ! pCrvBez->SetControlPoint( i, cnData.vCP[i])) + // for ( int i = 0 ; i <= snData.nDeg ; ++ i) { + // if ( ! snData.bRat) { + // if ( ! pCrvBez->SetControlPoint( i, snData.vCP[i])) // return nullptr ; // } // else { - // if ( ! pCrvBez->SetControlPoint( i, cnData.vCP[i], cnData.vW[i])) + // if ( ! pCrvBez->SetControlPoint( i, snData.vCP[i], snData.vW[i])) // return nullptr ; // } // } // // se non ? una curva ma un punto, la invalido // if ( pCrvBez->IsAPoint()) - // pCrvBez->Init( cnData.nDeg, cnData.bRat) ; + // pCrvBez->Init( snData.nDeg, snData.bRat) ; // // restituisco la curva // return Release( pCrvBez) ; //} @@ -110,38 +193,38 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) // algoritmo 5.7 del libro "The NURBS book"////////////////////////////////////////////////////////////////////////////////////////////////////////////// // creazione delle strips nella direzione U ( trasformo le curve iso con U costante in bezier) - int a = cnData.nDegU - 1 ; - int b = cnData.nDegU ; + int a = snData.nDegU - 1 ; + int b = snData.nDegU ; int nb = 0 ; // numero di strisce in U ( lunghezza con U costante) //PNTVECTOR vBC ; - //vBC.resize( cnData.nCPV * cnData.nDegU) ; - //for (int row = 0 ; row < cnData.nCPV ; ++row ) { - // for ( int i = 0 ; i <= cnData.nDegU ; ++i ) { - // vBC[nDegU*row + i] = ( cnData.vCP[nCPU*row + i]) ; + //vBC.resize( snData.nCPV * snData.nDegU) ; + //for (int row = 0 ; row < snData.nCPV ; ++row ) { + // for ( int i = 0 ; i <= snData.nDegU ; ++i ) { + // vBC[nDegU*row + i] = ( snData.vCP[nCPU*row + i]) ; // } //} - vector vCPV( cnData.nCPV) ; - vector< vector> mBC (cnData.nDegU + 1,vCPV ) ; - vector< vector> mBC_next (cnData.nDegU - 1, vCPV) ; - vector< vector> mPC_strip(cnData.nDegU + 1, vCPV) ; // matrice che verr? ingrandita e conterr? la superficie met? bezier e met? NURBS - DBLVECTOR vV_W( cnData.nCPV) ; - vector mW( cnData.nDegU + 1, vV_W) ; - vector mW_next( cnData.nDegU - 1, vV_W) ; - vector mW_strip( cnData.nDegU + 1, vV_W) ; + vector vCPV( snData.nCPV) ; + vector< vector> mBC (snData.nDegU + 1,vCPV ) ; + vector< vector> mBC_next (snData.nDegU - 1, vCPV) ; + vector< vector> mPC_strip(snData.nDegU + 1, vCPV) ; // matrice che verr? ingrandita e conterr? la superficie met? bezier e met? NURBS + DBLVECTOR vV_W( snData.nCPV) ; + vector mW( snData.nDegU + 1, vV_W) ; + vector mW_next( snData.nDegU - 1, vV_W) ; + vector mW_strip( snData.nDegU + 1, vV_W) ; DBLVECTOR vAlpha ; - vAlpha.resize( cnData.nDegU - 1) ; - if ( ! cnData.bRat ) { - for ( int i = 0 ; i <= cnData.nDegU ; ++i ) { - for ( int row = 0 ; row < cnData.nCPV ; ++row ) { - mBC[i][row] = cnData.mCP[i][row] ; + vAlpha.resize( snData.nDegU - 1) ; + if ( ! snData.bRat ) { + for ( int i = 0 ; i <= snData.nDegU ; ++i ) { + for ( int row = 0 ; row < snData.nCPV ; ++row ) { + mBC[i][row] = snData.mCP[i][row] ; } } } else { - for ( int i = 0 ; i <= cnData.nDegU ; ++i ) { - for (int row = 0 ; row < cnData.nCPV ; ++ row) { - mW[i][row] = cnData.mW[i][row] ; - mBC[i][row] = cnData.mCP[i][row] * cnData.mW[i][row] ; + for ( int i = 0 ; i <= snData.nDegU ; ++i ) { + for (int row = 0 ; row < snData.nCPV ; ++ row) { + mW[i][row] = snData.mW[i][row] ; + mBC[i][row] = snData.mCP[i][row] * snData.mW[i][row] ; } } } @@ -153,34 +236,34 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } 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) + while ( b < nU - 1 && abs( snData.vU[b+1] - snData.vU[b]) < EPS_ZERO) ++ b ; int mult = b - i + 1 ; - if ( mult < cnData.nDegU ) { + if ( mult < snData.nDegU ) { bRef = true ; // calcolo numeratore e alpha - double numer = cnData.vU[b] - cnData.vU[a] ; - for ( int j = cnData.nDegU ; j > mult ; -- j) - vAlpha[j-mult-1] = numer / ( cnData.vU[a+j] - cnData.vU[a]) ; - int r = cnData.nDegU - mult ; - for ( int j = 1 ; j <= cnData.nDegU - mult ; ++j ) { + double numer = snData.vU[b] - snData.vU[a] ; + for ( int j = snData.nDegU ; j > mult ; -- j) + vAlpha[j-mult-1] = numer / ( snData.vU[a+j] - snData.vU[a]) ; + int r = snData.nDegU - mult ; + for ( int j = 1 ; j <= snData.nDegU - mult ; ++j ) { int save = r - j ; int s = mult + j ; - //for ( int row = 0 ; row < cnData.nCPV ; ++row) { - // for ( int k = cnData.nDegU ; k >= s ; --k ) { + //for ( int row = 0 ; row < snData.nCPV ; ++row) { + // for ( int k = snData.nDegU ; k >= s ; --k ) { // vBC[nCPU*row + k] = vAlpha[k-s]*vBC[nCPU*row + k] + ( 1 - vAlfa[k-s]) * vBC[nCPU*row + k - 1] // } //} - if ( ! cnData.bRat ) { - for ( int k = cnData.nDegU ; k >= s ; --k ) { - for ( int row = 0 ; row < cnData.nCPV ; ++row) { + if ( ! snData.bRat ) { + for ( int k = snData.nDegU ; k >= s ; --k ) { + for ( int row = 0 ; row < snData.nCPV ; ++row) { mBC[k][row] = vAlpha[k-s] * mBC[k][row] + ( 1 - vAlpha[k-s]) * mBC[k-1][row] ; } } } else { - for ( int k = cnData.nDegU ; k >= s ; --k ) { - for ( int row = 0 ; row < cnData.nCPV ; ++row) { + for ( int k = snData.nDegU ; k >= s ; --k ) { + for ( int row = 0 ; row < snData.nCPV ; ++row) { mBC[k][row] = vAlpha[k-s] * mBC[k][row] + ( 1 - vAlpha[k-s]) * mBC[k-1][row] ; mW[k][row] = vAlpha[k-s] * mW[k][row] + ( 1 - vAlpha[k-s]) * mW[k-1][row] ; } @@ -188,29 +271,29 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } if ( b < nU - 1 ) { - for ( int row = 0 ; row < cnData.nCPV ; ++row) { - mBC_next[save][row] = mBC[cnData.nDegU][row] ; + for ( int row = 0 ; row < snData.nCPV ; ++row) { + mBC_next[save][row] = mBC[snData.nDegU][row] ; } - if ( cnData.bRat ) - for ( int row = 0 ; row < cnData.nCPV ; ++row) { - mW_next[save][row] = mW[cnData.nDegU][row] ; + if ( snData.bRat ) + for ( int row = 0 ; row < snData.nCPV ; ++row) { + mW_next[save][row] = mW[snData.nDegU][row] ; } } } } - mPC_strip.resize( cnData.nDegU * ( nb + 1) + 1 , vCPV) ; - mW_strip.resize( cnData.nDegU * ( nb + 1) + 1, vV_W) ; - if ( ! cnData.bRat) - for ( int i = 0 ; i <= cnData.nDegU ; ++i) { - for ( int row = 0 ; row < cnData.nCPV ; ++row ) { - mPC_strip[i+ nb * cnData.nDegU][row] = mBC[i][row] ; + mPC_strip.resize( snData.nDegU * ( nb + 1) + 1 , vCPV) ; + mW_strip.resize( snData.nDegU * ( nb + 1) + 1, vV_W) ; + if ( ! snData.bRat) + for ( int i = 0 ; i <= snData.nDegU ; ++i) { + for ( int row = 0 ; row < snData.nCPV ; ++row ) { + mPC_strip[i+ nb * snData.nDegU][row] = mBC[i][row] ; } } else { - for ( int i = 0 ; i <= cnData.nDegU ; ++i) { - for ( int row = 0 ; row < cnData.nCPV ; ++row ) { - mPC_strip[i+ nb * cnData.nDegU][row] = mBC[i][row]/mW[i][row] ; - mW_strip[i+ nb * cnData.nDegU][row] = mW[i][row] ; + for ( int i = 0 ; i <= snData.nDegU ; ++i) { + for ( int row = 0 ; row < snData.nCPV ; ++row ) { + mPC_strip[i+ nb * snData.nDegU][row] = mBC[i][row]/mW[i][row] ; + mW_strip[i+ nb * snData.nDegU][row] = mW[i][row] ; } } } @@ -218,16 +301,16 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) // ho finito di definire la patch di Bezier attuale e passo alla successiva // aggiorno mBC con i valori della prossima pezza di Bezier // corrisponde a nb = nb + 1 - if ( ! cnData.bRat){ - for (int i = 0 ; i < cnData.nDegU - 1 ; ++ i) { - for ( int row = 0 ; row < cnData.nCPV ; ++row) { + if ( ! snData.bRat){ + for (int i = 0 ; i < snData.nDegU - 1 ; ++ i) { + for ( int row = 0 ; row < snData.nCPV ; ++row) { mBC[i][row] = mBC_next[i][row] ; } } } else { - for (int i = 0 ; i < cnData.nDegU - 1 ; ++ i) { - for ( int row = 0 ; row < cnData.nCPV ; ++row) { + for (int i = 0 ; i < snData.nDegU - 1 ; ++ i) { + for ( int row = 0 ; row < snData.nCPV ; ++row) { mBC[i][row] = mBC_next[i][row] ; mW[i][row] = mW_next[i][row] ; } @@ -235,15 +318,15 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } if ( b < nU - 1 ) { - for ( int i = cnData.nDegU - mult ; i <= cnData.nDegU ; ++ i) { - for (int row = 0 ; row < cnData.nCPV ; ++ row ) { - mBC[i][row] = cnData.mCP[b - cnData.nDegU + i + 1][row] ; + for ( int i = snData.nDegU - mult ; i <= snData.nDegU ; ++ i) { + for (int row = 0 ; row < snData.nCPV ; ++ row ) { + mBC[i][row] = snData.mCP[b - snData.nDegU + i + 1][row] ; } } - if ( cnData.bRat ) { - for ( int i = cnData.nDegU - mult ; i <= cnData.nDegU ; ++ i) { - for (int row = 0 ; row < cnData.nCPV ; ++ row ) { - mW[i][row] = cnData.mW[b - cnData.nDegU + i + 1][row] ; + if ( snData.bRat ) { + for ( int i = snData.nDegU - mult ; i <= snData.nDegU ; ++ i) { + for (int row = 0 ; row < snData.nCPV ; ++ row ) { + mW[i][row] = snData.mW[b - snData.nDegU + i + 1][row] ; } } } @@ -255,56 +338,56 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) // se non ho raffinato allora tutti i nodi avevano gi? molteplicit? massima. Converto direttamente in Bezier la dir U int nCPU_ref ; // numero dei punti di controllo in U dopo il raffinamento if ( ! bRef ) { - nCPU_ref = cnData.nCPU ; - mPC_strip.resize( cnData.nCPU, vCPV) ; - mW_strip.resize( cnData.nCPU, vV_W) ; - if ( ! cnData.bRat) { + nCPU_ref = snData.nCPU ; + mPC_strip.resize( snData.nCPU, vCPV) ; + mW_strip.resize( snData.nCPU, vV_W) ; + if ( ! snData.bRat) { for ( int i = 0 ; i < nCPU_ref ; ++i) { - for ( int row = 0 ; row < cnData.nCPV ; ++ row) { - mPC_strip[i][row] = cnData.mCP[i][row] ; + for ( int row = 0 ; row < snData.nCPV ; ++ row) { + mPC_strip[i][row] = snData.mCP[i][row] ; } } } else { for ( int i = 0 ; i < nCPU_ref ; ++i) { - for ( int row = 0 ; row < cnData.nCPV ; ++ row) { - mPC_strip[i][row] = cnData.mCP[i][row] ; - mW_strip[i][row] = cnData.mW[i][row] ; + for ( int row = 0 ; row < snData.nCPV ; ++ row) { + mPC_strip[i][row] = snData.mCP[i][row] ; + mW_strip[i][row] = snData.mW[i][row] ; } } } // devo vedere quante patch ci stanno prendendo i punti che ci sono - //nb = (cnData.nCPU - 1) / cnData.nDegU ; + //nb = (snData.nCPU - 1) / snData.nDegU ; } else - nCPU_ref = cnData.nDegU * nb + 1 ; // numero dei punti di controllo in U dopo il raffinamento + nCPU_ref = snData.nDegU * nb + 1 ; // numero dei punti di controllo in U dopo il raffinamento // ora ho ottenuto le strisce nDegU x nCPV // devo ripetere la procedura, sulla dir V, per ottenere le patch nDegU x nDegV - a = cnData.nDegV - 1 ; - b = cnData.nDegV ; + a = snData.nDegV - 1 ; + b = snData.nDegV ; int nc = 0 ; // numero di strisce in V ( lunghezza con V costante) - vector vDegV(cnData.nDegV + 1) ; - vector vDegV_1(cnData.nDegV - 1) ; + vector vDegV(snData.nDegV + 1) ; + vector vDegV_1(snData.nDegV - 1) ; vector< vector> m_BC1( nCPU_ref, vDegV) ; vector< vector> m_BC1_next( nCPU_ref, vDegV_1) ; - DBLVECTOR vV1_W(cnData.nDegV + 1) ; - DBLVECTOR vV2_W(cnData.nDegV - 1) ; + DBLVECTOR vV1_W(snData.nDegV + 1) ; + DBLVECTOR vV2_W(snData.nDegV - 1) ; vector mW1( nCPU_ref, vV1_W) ; vector mW1_next( nCPU_ref, vV2_W) ; - DBLVECTOR vAlpha1( cnData.nDegV - 1) ; + DBLVECTOR vAlpha1( snData.nDegV - 1) ; vector> mPC_tot( nCPU_ref, vDegV) ; vector mW_tot( nCPU_ref, vV1_W) ; - if ( ! cnData.bRat ) { + if ( ! snData.bRat ) { for ( int i = 0 ; i < nCPU_ref ; ++i ) { - for ( int row = 0 ; row <= cnData.nDegV ; ++row ) { + for ( int row = 0 ; row <= snData.nDegV ; ++row ) { m_BC1[i][row] = mPC_strip[i][row] ; } } } else { for ( int i = 0 ; i < nCPU_ref ; ++i ) { - for (int row = 0 ; row <= cnData.nDegV ; ++ row) { + for (int row = 0 ; row <= snData.nDegV ; ++ row) { mW1[i][row] = mW_strip[i][row] ; m_BC1[i][row] = mPC_strip[i][row] * mW_strip[i][row] ; } @@ -318,34 +401,34 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } while ( b < nV - 1) { int i = b ; - while ( b < nV - 1 && abs( cnData.vV[b+1] - cnData.vV[b]) < EPS_ZERO) + while ( b < nV - 1 && abs( snData.vV[b+1] - snData.vV[b]) < EPS_ZERO) ++ b ; int mult = b - i + 1 ; - if ( mult < cnData.nDegV ) { + if ( mult < snData.nDegV ) { bRef = true ; // calcolo numeratore e alpha - double numer = cnData.vV[b] - cnData.vV[a] ; - for ( int j = cnData.nDegV ; j > mult ; -- j) - vAlpha1[j-mult-1] = numer / ( cnData.vV[a+j] - cnData.vV[a]) ; - int r = cnData.nDegV - mult ; - for ( int j = 1 ; j <= cnData.nDegV - mult ; ++j ) { + double numer = snData.vV[b] - snData.vV[a] ; + for ( int j = snData.nDegV ; j > mult ; -- j) + vAlpha1[j-mult-1] = numer / ( snData.vV[a+j] - snData.vV[a]) ; + int r = snData.nDegV - mult ; + for ( int j = 1 ; j <= snData.nDegV - mult ; ++j ) { int save = r - j ; int s = mult + j ; - //for ( int row = 0 ; row < cnData.nCPV ; ++row) { - // for ( int k = cnData.nDegU ; k >= s ; --k ) { + //for ( int row = 0 ; row < snData.nCPV ; ++row) { + // for ( int k = snData.nDegU ; k >= s ; --k ) { // vBC[nCPU*row + k] = vAlpha1[k-s]*vBC[nCPU*row + k] + ( 1 - vAlpha1[k-s]) * vBC[nCPU*row + k - 1] // } //} - if ( ! cnData.bRat) { + if ( ! snData.bRat) { for ( int k = 0 ; k < nCPU_ref ; ++k) { - for ( int row = cnData.nDegV ; row >= s ; --row ) { + for ( int row = snData.nDegV ; row >= s ; --row ) { m_BC1[k][row] = vAlpha1[row-s] * m_BC1[k][row] + ( 1 - vAlpha1[row-s]) * m_BC1[k][row-1] ; } } } else { for ( int k = 0 ; k < nCPU_ref ; ++k) { - for ( int row = cnData.nDegV ; row >= s ; --row ) { + for ( int row = snData.nDegV ; row >= s ; --row ) { m_BC1[k][row] = vAlpha1[row-s] * m_BC1[k][row] + ( 1 - vAlpha1[row-s]) * m_BC1[k][row-1] ; mW1[k][row] = vAlpha1[row-s] * mW1[k][row] + ( 1 - vAlpha1[row-s]) * mW1[k][row-1] ; } @@ -353,36 +436,36 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } if ( b < nV - 1 ) { - if ( !cnData.bRat ){ + if ( !snData.bRat ){ for ( int i = 0 ; i < nCPU_ref ; ++i) { - m_BC1_next[i][save] = m_BC1[i][cnData.nDegV] ; + m_BC1_next[i][save] = m_BC1[i][snData.nDegV] ; } } else { for ( int i = 0 ; i < nCPU_ref ; ++i) { - m_BC1_next[i][save] = m_BC1[i][cnData.nDegV] ; - mW1_next[save] = mW1[cnData.nDegV] ; + m_BC1_next[i][save] = m_BC1[i][snData.nDegV] ; + mW1_next[save] = mW1[snData.nDegV] ; } } } } } - int nRef = cnData.nDegV * ( nc + 1) + 1 ; + int nRef = snData.nDegV * ( nc + 1) + 1 ; for ( int k = 0 ; k < nCPU_ref; ++k){ mPC_tot[k].resize( nRef) ; mW_tot[k].resize( nRef) ; } - if ( ! cnData.bRat) + if ( ! snData.bRat) for ( int i = 0 ; i < nCPU_ref ; ++i) { - for ( int row = 0 ; row <= cnData.nDegV ; ++row ) { - mPC_tot[i][row + nc * cnData.nDegV] = m_BC1[i][row] ; + for ( int row = 0 ; row <= snData.nDegV ; ++row ) { + mPC_tot[i][row + nc * snData.nDegV] = m_BC1[i][row] ; } } else { for ( int i = 0 ; i < nCPU_ref ; ++i) { - for ( int row = 0 ; row <= cnData.nDegV ; ++row ) { - mPC_tot[i][row + nc * cnData.nDegV] = m_BC1[i][row]/mW1[i][row] ; - mW_tot[i][row + nc * cnData.nDegV] = mW1[i][row] ; + for ( int row = 0 ; row <= snData.nDegV ; ++row ) { + mPC_tot[i][row + nc * snData.nDegV] = m_BC1[i][row]/mW1[i][row] ; + mW_tot[i][row + nc * snData.nDegV] = mW1[i][row] ; } } } @@ -390,16 +473,16 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) // ho finito di definire la patch di Bezier attuale e passo alla successiva // aggiorno mBC con i valori della prossima pezza di Bezier // corrisponde a nc = nc + 1 - if ( ! cnData.bRat){ + if ( ! snData.bRat){ for (int i = 0 ; i < nCPU_ref ; ++ i) { - for ( int row = 0 ; row < cnData.nDegV - 1 ; ++row) { + for ( int row = 0 ; row < snData.nDegV - 1 ; ++row) { m_BC1[i][row] = m_BC1_next[i][row] ; } } } else { for (int i = 0 ; i < nCPU_ref ; ++ i) { - for ( int row = 0 ; row < cnData.nDegV - 1 ; ++row) { + for ( int row = 0 ; row < snData.nDegV - 1 ; ++row) { m_BC1[i][row] = m_BC1_next[i][row] ; mW1[i][row] = mW1_next[i][row] ; } @@ -408,14 +491,14 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) if ( b < nV - 1) { for (int i = 0 ; i < nCPU_ref ; ++ i ) { - for ( int row = cnData.nDegV - mult ; row <= cnData.nDegV ; ++ row) { - m_BC1[i][row] = cnData.mCP[i][b - cnData.nDegV + row + 1] ; + for ( int row = snData.nDegV - mult ; row <= snData.nDegV ; ++ row) { + m_BC1[i][row] = snData.mCP[i][b - snData.nDegV + row + 1] ; } } - if ( cnData.bRat ) { + if ( snData.bRat ) { for (int i = 0 ; i < nCPU_ref ; ++ i ) { - for ( int row = cnData.nDegV - mult ; row <= cnData.nDegV ; ++ row) { - mW1[i][row] = cnData.mW[i][b - cnData.nDegV + row + 1] ; + for ( int row = snData.nDegV - mult ; row <= snData.nDegV ; ++ row) { + mW1[i][row] = snData.mW[i][b - snData.nDegV + row + 1] ; } } } @@ -427,12 +510,12 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) // se non ho raffinato allora aggiungo direttamente alle matrici della superficie totale int nCPV_ref ; // numero dei punti di controllo in V dopo il raffinamento if ( ! bRef) { - nCPV_ref = cnData.nCPV ; + nCPV_ref = snData.nCPV ; for ( int k = 0 ; k < nCPU_ref ; ++k){ - mPC_tot[k].resize( cnData.nCPV) ; - mW_tot[k].resize( cnData.nCPV) ; + mPC_tot[k].resize( snData.nCPV) ; + mW_tot[k].resize( snData.nCPV) ; } - if ( ! cnData.bRat) { + if ( ! snData.bRat) { for ( int i = 0 ; i < nCPU_ref ; ++i) { for ( int row = 0 ; row < nCPV_ref ; ++ row) { mPC_tot[i][row] = mPC_strip[i][row] ; @@ -448,17 +531,17 @@ NurbsToBezierSurface(const CNurbsSurfData& cnData) } } // devo vedere quante patch ci stanno prendendo i punti che ci sono - //nc = (cnData.nCPV - 1) / cnData.nDegV ; + //nc = (snData.nCPV - 1) / snData.nDegV ; } else - nCPV_ref = cnData.nDegV * nc + 1 ; + nCPV_ref = snData.nDegV * nc + 1 ; // finalmente setto la superficie di bezier totale divisa in nb patch in U e nc patch in V PtrOwner pSrfBz( CreateSurfBezier()) ; if ( IsNull( pSrfBz)) return nullptr ; - pSrfBz->Init(cnData.nDegU, cnData.nDegV, nb, nc, cnData.bRat) ; - if ( !cnData.bRat ) { + pSrfBz->Init(snData.nDegU, snData.nDegV, nb, nc, snData.bRat) ; + if ( !snData.bRat ) { for ( int i = 0 ; i < nCPU_ref; ++ i) { for (int j = 0 ; j < nCPV_ref; ++j) { pSrfBz->SetControlPoint( i + nCPU_ref * j, mPC_tot[i][j]) ; From e2eb219c5ab8c6f361a5b15fd243b811124bbe25 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 17 Oct 2023 11:23:08 +0200 Subject: [PATCH 37/44] EgtGeomKernel : - correzione alla conversione da sup Nurbs a Bezier. --- SurfAux.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/SurfAux.cpp b/SurfAux.cpp index 41ebeb5..67a2b09 100644 --- a/SurfAux.cpp +++ b/SurfAux.cpp @@ -492,13 +492,15 @@ NurbsToBezierSurface(const SNurbsSurfData& snData) if ( b < nV - 1) { for (int i = 0 ; i < nCPU_ref ; ++ i ) { for ( int row = snData.nDegV - mult ; row <= snData.nDegV ; ++ row) { - m_BC1[i][row] = snData.mCP[i][b - snData.nDegV + row + 1] ; + //m_BC1[i][row] = snData.mCP[i][b - snData.nDegV + row + 1] ; + m_BC1[i][row] = mPC_strip[i][b - snData.nDegV + row + 1] ; } } if ( snData.bRat ) { for (int i = 0 ; i < nCPU_ref ; ++ i ) { for ( int row = snData.nDegV - mult ; row <= snData.nDegV ; ++ row) { - mW1[i][row] = snData.mW[i][b - snData.nDegV + row + 1] ; + //mW1[i][row] = snData.mW[i][b - snData.nDegV + row + 1] ; + mW1[i][row] = mW_strip[i][b - snData.nDegV + row + 1] ; } } } From a5714cc85dbf90547ca3df522dee72df2f206b69 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Thu, 19 Oct 2023 12:44:31 +0200 Subject: [PATCH 38/44] EgtGeomKernel : - correzione alla conversione da sup NURBS a Bezier. --- SurfAux.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/SurfAux.cpp b/SurfAux.cpp index 10f835d..7b95a30 100644 --- a/SurfAux.cpp +++ b/SurfAux.cpp @@ -230,6 +230,10 @@ NurbsToBezierSurface(const SNurbsSurfData& snData) } 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( snData.vU[b+1] - snData.vU[b]) < EPS_ZERO) @@ -391,6 +395,10 @@ NurbsToBezierSurface(const SNurbsSurfData& snData) } bRef = false ; + // 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) { // qui correggo un probabile errore, mettendo nU anzich� nCPV, come indicato nell'algoritmo int i = b ; while ( b < nV - 1 && abs( snData.vV[b+1] - snData.vV[b]) < EPS_ZERO) From 5bb1fdaed30482aca7799dec0f14ab7f3b50e1c6 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Thu, 19 Oct 2023 12:45:48 +0200 Subject: [PATCH 39/44] EgtGeomKernel : - correzione bug nelle sup di Bezier chiuse. --- SurfBezier.cpp | 7 +- Tree.cpp | 210 ++++++++++++++++++++++++++++++++++++------------- Tree.h | 8 +- 3 files changed, 166 insertions(+), 59 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index ee7a99f..d14dead 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -1500,6 +1500,7 @@ SurfBezier::GetAuxSurf( void) const // costruttore della superficie vector vvPL ; + //POLYLINEVECTOR vPL ; // per usare i polygon basic Tree Tree( this, true) ; std::vector> vTrees ; Tree.GetIndependentTrees( vTrees) ; @@ -1507,10 +1508,12 @@ 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.BuildTree_test() ; // per debug + Tree.BuildTree( 5 * LIN_TOL_FINE, 0.1) ; Tree.GetPolygons( vvPL) ; + //Tree.GetPolygonsBasic( vPL) ; // per usare i polygon basic } + //vvPL.push_back( vPL) ; // per usare i polygon basic PtrOwner pSrfTm( CreateBasicSurfTriMesh()) ; StmFromTriangleSoup stmSoup ; diff --git a/Tree.cpp b/Tree.cpp index 4ae1f9c..9ff9ecd 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -29,7 +29,7 @@ //---------------------------------------------------------------------------- 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_bOnLeftEdge( false), + m_nChild1( -2), m_nChild2( -2), m_nFlag( -1), m_nFlag2( 0), m_nRightEdgeIn( -1), m_bOnLeftEdge( false), m_bOnTopEdge( false), m_ptPbl( ORIG), m_ptPtr(), m_bProcessed( false), m_bSplitVert( true) { Point3d ptTr ( 1 * SBZ_TREG_COEFF, 1 * SBZ_TREG_COEFF) ; @@ -40,7 +40,7 @@ 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_bOnLeftEdge( false), + m_nChild1( -2), m_nChild2( -2), m_nFlag( -1), m_nFlag2( 0), m_nRightEdgeIn( -1), m_bOnLeftEdge( false), m_bOnTopEdge( false), m_ptPbl( ptBL), m_ptPtr( ptTR), m_bProcessed( false), m_bSplitVert( true) {} @@ -72,7 +72,7 @@ Cell::IsLeaf ( void) const //---------------------------------------------------------------------------- Tree::Tree( void) - : m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosed( false), m_bSplitPatches( true) + : m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosedU( false), m_bClosedV( false), m_bSplitPatches( true) { Point3d ptBl( 0, 0), ptTr ( 1 * SBZ_TREG_COEFF, 1 * SBZ_TREG_COEFF) ; Cell cRoot( ptBl, ptTr) ; @@ -81,7 +81,7 @@ Tree::Tree( void) //---------------------------------------------------------------------------- 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) + : m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosedU( false), m_bClosedV( false), m_bSplitPatches( true) { SetSurf( pSrfBz, bSplitPatches, ptMin, ptMax) ; } @@ -208,11 +208,13 @@ Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches, const Point3d 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) { if ( i * SBZ_TREG_COEFF > ptMin.x && i * SBZ_TREG_COEFF < ptTop.x){ @@ -242,11 +244,12 @@ Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches, const Point3d // e sistemo le adiacenze if ( ( AreSamePointApprox( ptP00, ptP01) || AreSamePointApprox( ptP10, ptP11)) || ( AreSamePointApprox( ptP00, ptP10) || AreSamePointApprox( ptP01, ptP11))) { - m_bClosed = true ; + //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) ; @@ -276,6 +279,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches, const Point3d 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) ; @@ -1411,10 +1415,10 @@ Tree::GetPolygons( std::vector& vPolygons) { } // trimmata else { - if ( ! TraceLoopLabelCell()) - return false ; POLYLINEVECTOR vPolygonsBasic ; GetPolygonsBasic( vPolygonsBasic) ; + if ( ! TraceLoopLabelCell( vPolygonsBasic)) + return false ; // scorro sulle celle e costruisco i poligoni int nCells = (int)vPolygonsBasic.size() ; for ( int i = 0 ; i < nCells ; ++i) { @@ -1465,8 +1469,23 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons) if ( m_vPolygons.empty()) { PNTVECTOR vVertices ; INTVECTOR vNeigh ; + // setto le celle che sono sul LeftEdge e sul TopEdge + if ( m_bClosedU) { + GetRootNeigh( 1, vNeigh) ; + for ( int k : vNeigh) { + m_mTree[k].m_bOnLeftEdge = true ; + } + vNeigh.clear() ; + } + if ( m_bClosedV) { + GetRootNeigh( 0, vNeigh) ; + for ( int k : vNeigh) { + m_mTree[k].m_bOnTopEdge = true ; + } + } bool bBottomRight , bTopLeft ; - // scorro lungo tutte le celle leaves e oltre agli angoli della cella aggiungo alla polyline anche i vertici sui lati + // scorro lungo tutte le celle leaves e oltre agli angoli della cella aggiungo alla polyline della cella anche i vertici, delle celle adiacenti, + // che sono sui lati della cella corrente for ( int nId : m_vnLeaves) { vVertices.clear() ; vNeigh.clear() ; @@ -1474,8 +1493,18 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons) GetBottomNeigh( nId, vNeigh) ; // aggiungo i vertici che sono sul lato bottom, solo se ho più di un vicino bottom if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1){ - for ( int j : vNeigh) - vVertices.push_back( m_mTree.at( j).GetTopRight()) ; + // se la superficie è chiusa lungo il parametro V e le celle vicine bottom sono sul lato Top + // devo aggiungere i vertici tenendo conto della periodicità dello spazio parametrico. + if ( m_bClosedV && m_mTree.at(vNeigh[0]).m_bOnTopEdge) { + for ( int j : vNeigh) { + Point3d pt( m_mTree.at( j).GetTopRight().x, m_mTree.at( nId).GetBottomLeft().y) ; + vVertices.push_back( pt) ; + } + } + else { + for ( int j : vNeigh) + vVertices.push_back( m_mTree.at( j).GetTopRight()) ; + } bBottomRight = true ; } else @@ -1484,8 +1513,19 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons) GetRightNeigh ( nId, vNeigh) ; // aggiungo i vertici che sono sul lato right, solo se ho più di un vicino right if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1){ - for ( int j : vNeigh) - vVertices.push_back( m_mTree.at( j).GetBottomLeft()) ; + // 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. + 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) ; + vVertices.push_back( pt) ; + } + } + else { + for ( int j : vNeigh) + vVertices.push_back( m_mTree.at( j).GetBottomLeft()) ; + } + } // se non l'ho già aggiunto tramite i vicini bottom aggiungo il punto bottom right else if ( ! bBottomRight) { @@ -1498,8 +1538,18 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons) std::reverse( vNeigh.begin(), vNeigh.end()) ; // aggiungo i vertici che sono sul lato top, solo se ho più di un vicino top if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) { - for ( int j : vNeigh) - vVertices.push_back( m_mTree.at( j).GetBottomLeft()) ; + // se la superficie è chiusa lungo il parametro U e la cella è sul lato top + // devo aggiungere i vertici tenendo conto della periodicità dello spazio parametrico. + if ( m_bClosedU && m_mTree.at( nId).m_bOnTopEdge) { + for ( int j : vNeigh) { + Point3d pt( m_mTree.at( j).GetBottomLeft().x, m_mTree.at( nId).GetTopRight().y) ; + vVertices.push_back( pt) ; + } + } + else { + for ( int j : vNeigh) + vVertices.push_back( m_mTree.at( j).GetBottomLeft()) ; + } bTopLeft = true ; } else @@ -1509,8 +1559,18 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons) std::reverse( vNeigh.begin(), vNeigh.end()) ; // aggiungo i vertici che sono sul lato left, solo se ho più di un vicino left if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) { - for ( int j : vNeigh) - vVertices.push_back( m_mTree.at( j).GetTopRight()) ; + // 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. + 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) ; + vVertices.push_back( pt) ; + } + } + else { + for ( int j : vNeigh) + vVertices.push_back( m_mTree.at( j).GetTopRight()) ; + } } // se non l'ho già aggiunto tramite i vicini top aggiungo il punto top left else if ( ! bTopLeft) { @@ -1655,8 +1715,8 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& cl, INTVECTOR vCells INTVECTOR nCells ; int nId = -1 ; for ( int nCell : vCells) { - if ( ptIntersPlus.x >= m_mTree.at( nCell).GetBottomLeft().x && ptIntersPlus.x <= m_mTree.at( nCell).GetTopRight().x && - ptIntersPlus.y >= m_mTree.at( nCell).GetBottomLeft().y && ptIntersPlus.y <= m_mTree.at( nCell).GetTopRight().y) { + if ( ptIntersPlus.x > m_mTree.at( nCell).GetBottomLeft().x - EPS_ZERO && ptIntersPlus.x < m_mTree.at( nCell).GetTopRight().x + EPS_ZERO && + ptIntersPlus.y > m_mTree.at( nCell).GetBottomLeft().y - EPS_ZERO && ptIntersPlus.y < m_mTree.at( nCell).GetTopRight().y + EPS_ZERO) { nId = nCell ; nCells.push_back( nId) ; } @@ -1666,12 +1726,13 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& cl, INTVECTOR vCells //---------------------------------------------------------------------------- bool -Tree::TraceLoopLabelCell( void) +Tree::TraceLoopLabelCell( const POLYLINEVECTOR& vplPolygons) { + // l'idea è di seguire il loop di trim, passando di cella in cella, restando, quando possibile, a destra del loop. + // ( destra e sinistra sono determinate dal verso del loop). + // 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]) ; @@ -1855,7 +1916,7 @@ Tree::TraceLoopLabelCell( void) // ( e controllo che non sia una cella sul lato sinistro ( adiacenza in caso di superficie chiusa)) for ( int t: vNeigh) { if ( m_mTree[t].m_nFlag2 == 0 ) { - if ( ! m_bClosed) { + if ( ! m_bClosedU) { bDone = false ; break ; } @@ -1879,15 +1940,19 @@ Tree::TraceLoopLabelCell( void) // trovo il vicino a sinistra, già categorizzato, più basso vNeigh.clear() ; GetLeftNeigh( nCell, vNeigh) ; - for ( int p = 0 ; p < (int)vNeigh.size() ; ++ p) { - if ( m_mTree[vNeigh[p]].m_nFlag2 != 0) { - nCell = vNeigh[p] ; - break ; + // però se sono già sul lato sinistro non cerco di spostarmi ancora più a sinistra. + if ( ! m_mTree[nCell].m_bOnLeftEdge) { + for ( int p = 0 ; p < (int)vNeigh.size() ; ++ p) { + if ( m_mTree[vNeigh[p]].m_nFlag2 != 0) { + nCell = vNeigh[p] ; + break ; + } } } - 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()) { + if ( ! m_bClosedU) { + // se non ho vicini a sinistra sono tornato sul lato sinistro + // se questa cella non è processata devo procedere alla cella più bassa non processata sul lato sinistro + if ( vNeigh.empty() && m_mTree[nCell].IsProcessed()) { for ( int p = 0 ; p < (int)vFirst.size() ; ++ p) { if ( m_mTree[vFirst[p]].m_nFlag2 == 0) { nCell = vFirst[p] ; @@ -1902,7 +1967,7 @@ Tree::TraceLoopLabelCell( void) } 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) { + if ( m_mTree[nCell].m_bOnLeftEdge && m_mTree[nCell].IsProcessed()) { for ( int p = 0 ; p < (int) vFirst.size(); ++ p) { if ( nCell == vFirst[p] && nCell != nLastLeft) { nCell = vFirst[p + 1] ; @@ -1959,62 +2024,91 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool // -1 se la curva è sempre dentro la cella bool bIntersFound = false ; Point3d ptInters ; + 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) + if ( ptEnd.x < ptBL.x) { + nEdge2 = 1 ; clEdge2.Set( ptTl, ptBL) ; - else if ( AreSamePointExact( ptEnd, ptTl) && bFirstInters) { - nEdge = 4 ; - ptInters = ptTl ; - bIntersFound = true ; } + //else if ( AreSamePointExact( ptEnd, ptTl) && bFirstInters) { + // nEdge = 4 ; + // ptInters = ptTl ; + // bIntersFound = true ; + //} + //else if ( AreSamePointExact( ptEnd, ptTR) && bFirstInters) { + // nEdge = 7 ; + // ptInters = ptTR ; + // bIntersFound = true ; + //} } 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) + if ( ptEnd.y < ptBL.y) { + nEdge2 = 2 ; clEdge2.Set( ptBL, ptBr) ; - else if ( AreSamePointExact( ptEnd, ptBL) && bFirstInters) { - nEdge = 5 ; - ptInters = ptBL ; - bIntersFound = true ; } + //else if ( AreSamePointExact( ptEnd, ptBL) && bFirstInters) { + // nEdge = 5 ; + // ptInters = ptBL ; + // bIntersFound = true ; + //} + //else if ( AreSamePointExact( ptEnd, ptTl) && bFirstInters) { + // nEdge = 4 ; + // ptInters = ptTl ; + // bIntersFound = true ; + //} } 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) + if ( ptEnd.x > ptTR.x) { + nEdge2 = 3 ; clEdge2.Set( ptBr, ptTR) ; - else if ( AreSamePointExact( ptEnd, ptBr) && bFirstInters) { - nEdge = 6 ; - ptInters = ptBr ; - bIntersFound = true ; } + //else if ( AreSamePointExact( ptEnd, ptBr) && bFirstInters) { + // nEdge = 6 ; + // ptInters = ptBr ; + // bIntersFound = true ; + //} + //else if ( AreSamePointExact( ptEnd, ptBL) && bFirstInters) { + // nEdge = 5 ; + // ptInters = ptBL ; + // bIntersFound = true ; + //} } 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) + if ( ptEnd.y > ptTR.y) { + nEdge2 = 0 ; clEdge2.Set( ptTR, ptTl) ; - else if ( AreSamePointExact( ptEnd, ptTR) && bFirstInters) { - nEdge = 7 ; - ptInters = ptTR ; - bIntersFound = true ; } + //else if ( AreSamePointExact( ptEnd, ptTR) && bFirstInters) { + // nEdge = 7 ; + // ptInters = ptTR ; + // bIntersFound = true ; + //} + //else if ( AreSamePointExact( ptEnd, ptBr) && bFirstInters) { + // nEdge = 6 ; + // ptInters = ptBr ; + // bIntersFound = true ; + //} } else return false ; - + bool bIntersOn2Found = false ; if ( ! bIntersFound) { // intersezione e controlli IntersLineLine illExit( clTrim, clEdge, true) ; @@ -2045,6 +2139,7 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool } else { //// solo intersezione sul lato 2 + bIntersOn2Found = true ; if ( aInfo2.bOverlap && ! bFirstInters) ptInters = aInfo2.IciA[1].ptI ; else @@ -2052,9 +2147,12 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool } } else - ptInters = aInfo.IciA[0].ptI ; + ptInters = aInfo.IciA[0].ptI ; // qui devo mettere il controllo su prima o seconda intersezione? } - OnWhichEdge( nId, ptInters, nEdge) ; + if ( ! bIntersOn2Found) + OnWhichEdge( nId, ptInters, nEdge) ; + else + nEdge = nEdge2 ; m_mTree[nId].m_vInters.back().nOut = nEdge ; if ( (int)vptInters.size() == 0 || ! AreSamePointExact( ptInters , vptInters.back())) vptInters.push_back( ptInters) ; @@ -2069,7 +2167,11 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool m_mTree[nId].m_nFlag = 1 ; else if ( m_mTree[nId].m_nFlag == 2) m_mTree[nId].m_nFlag = 3 ; + // seleziono la cella successiva da analizzare + // + // se la superficie è chiusa su un parametro devo stare attento a considerare lo spazio parametrico come se non fosse periodico + // es: non posso saltare dal lato destro al lato sinistro anche se una cella sul lato sinistro risulta la RightNeigh di una cella sul lato destro! INTVECTOR vNeigh, vNeigh1 ; if ( nEdge == 0) { GetTopNeigh( nId, vNeigh) ; @@ -2331,7 +2433,7 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool } // ingresso in diagonale else { - if ( ! vNeigh.empty()) { + if ( ! vNeigh.empty() /*&& ! m_mTree[vNeigh[0]].m_bOnLeftEdge */) { // questa aggiunta in teoria non serve int nIdTemp = vNeigh.back() ; vNeigh.clear() ; GetTopNeigh( nIdTemp, vNeigh) ; diff --git a/Tree.h b/Tree.h index 90e42a5..3b194ab 100644 --- a/Tree.h +++ b/Tree.h @@ -119,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à - bool m_bOnLeftEdge ; // flag che indica se la cella è sul lato sinistro ( per superfici chiuse) + bool m_bOnLeftEdge ; // flag che indica se la cella è sul lato sinistro ( per superfici chiuse sul parametro U) + bool m_bOnTopEdge ; // flag che indica se la cella è sul lato top ( per superfici chiuse sul parametro V) 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 @@ -161,7 +162,7 @@ private : void ResetTree ( void) ; // resetto m_bProcessed a false per tutti i nodi dell'albero INTVECTOR FindCell ( const Point3d& ptToAssign, const CurveLine& cl) const ; // dato un punto, trova la cella foglia a cui appartiene INTVECTOR FindCell ( const Point3d& ptToAssign, const CurveLine& cl, INTVECTOR vCells) const ; // dato un punto, trova la cella foglia a cui appartiene - bool TraceLoopLabelCell( void) ; // tracing dei loop e labelling delle celle + bool TraceLoopLabelCell( const POLYLINEVECTOR& vplPolygons) ; // tracing dei loop e labelling delle celle bool FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool bFirstInters = true) ; // trova le intersezioni tra una cella e una linea di trim // resituisce l'id della cella verso cui la curva di trim esce e il vettore delle intersezioni per la cella successiva con il primo punto bool CreateCellPolygons ( const int& nLeafId, std::vector& vPolygons, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk, const PolyLine& plCell) ; @@ -188,7 +189,8 @@ private : std::vector> m_vPlApprox ; bool m_bBilinear ; // superficie bilineare bool m_bMulti ; // superficie multi-patch - bool m_bClosed ; // superficie chiusa + bool m_bClosedU ; // superficie chiusa lungo il parametro U + bool m_bClosedV ; // superficie chiusa lungo il parametro V bool m_bSplitPatches ; // flag che indica se le patches sono state divise prima della creazione dell'albero int m_nDegU ; // grado della superficie nel parametro U int m_nDegV ; // grado della superficie nel parametro V From 610bd48747aa5954f1746d362b78ccdfae0572e5 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 23 Oct 2023 11:28:14 +0200 Subject: [PATCH 40/44] EgtGeomKernel : - debug. --- SurfBezier.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index d14dead..79687d2 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -1500,7 +1500,7 @@ SurfBezier::GetAuxSurf( void) const // costruttore della superficie vector vvPL ; - //POLYLINEVECTOR vPL ; // per usare i polygon basic + POLYLINEVECTOR vPL ; // per usare i polygon basic Tree Tree( this, true) ; std::vector> vTrees ; Tree.GetIndependentTrees( vTrees) ; @@ -1509,11 +1509,16 @@ SurfBezier::GetAuxSurf( void) const Point3d ptMax = std::get<1>( vTrees[i]) ; Tree.SetSurf( this, true, ptMin, ptMax) ; //Tree.BuildTree_test() ; // per debug - Tree.BuildTree( 5 * LIN_TOL_FINE, 0.1) ; + Tree.BuildTree( 5 * LIN_TOL_FINE, 1) ; Tree.GetPolygons( vvPL) ; //Tree.GetPolygonsBasic( vPL) ; // per usare i polygon basic } - //vvPL.push_back( vPL) ; // per usare i polygon basic + //// per usare i polygon basic////////////////////// + //for (int k = 0 ; k < (int)vPL.size(); ++k) { + // vvPL.emplace_back() ; + // vvPL.back().push_back(vPL[k]) ; + //} + //// per usare i polygon basic/////////////////// PtrOwner pSrfTm( CreateBasicSurfTriMesh()) ; StmFromTriangleSoup stmSoup ; From c0c01573ca6c5dd62ef3b00598ad1dfb7127cd12 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 7 Nov 2023 12:34:41 +0100 Subject: [PATCH 41/44] EgtGeomKernel : - aggiunta la gestione delle superfici e curve NURBS unclamped. - correzioni al caso con una sola patch o casi senza raffinazione dei punti. --- CurveAux.cpp | 2 +- SurfAux.cpp | 95 ++++++++-------------------------------------------- 2 files changed, 15 insertions(+), 82 deletions(-) diff --git a/CurveAux.cpp b/CurveAux.cpp index 925127b..52b6b10 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -522,7 +522,7 @@ NurbsCurveCanonicalize( CNurbsData& cnData) } // se periodica - if ( cnData.bPeriodic) { + if ( cnData.bPeriodic || ! cnData.bClamped) { // va trasformata in non-periodica (clamped) // bisogna aumentare la molteplicità dei nodi u_p-1 e u_(m-p+1) fino ad arrivare al grado della nurbs // e poi scartare nodi e punti fuori dalla regione clamped ( al di fuori della regione u_p-1 -> u_(m-p+1)) diff --git a/SurfAux.cpp b/SurfAux.cpp index 7b95a30..49e1e24 100644 --- a/SurfAux.cpp +++ b/SurfAux.cpp @@ -31,7 +31,7 @@ NurbsSurfaceCanonicalize( SNurbsSurfData& snData) { // per rendere una superficie non periodica devo recuperare i punti di controllo, suddivisi in isoparametriche lungo una direzione // e applicare la trasformazione ad ogni isoparametrica, sostituendola poi a quella originale. ( si mantiene il numero di punti) - if ( snData.bPeriodicU ) { + if ( snData.bPeriodicU || ! snData.bClampedU) { bool bIsRational = snData.bRat ; // vettore dei nodi DBLVECTOR vU ; @@ -68,7 +68,7 @@ NurbsSurfaceCanonicalize( SNurbsSurfData& snData) } snData.bPeriodicU = false ; } - if ( snData.bPeriodicV ) { + if ( snData.bPeriodicV || ! snData.bClampedV) { bool bIsRational = snData.bRat ; // vettore dei nodi DBLVECTOR vV ; @@ -113,20 +113,6 @@ NurbsSurfaceCanonicalize( SNurbsSurfData& snData) ISurf* NurbsToBezierSurface(const SNurbsSurfData& snData) { - //INTVECTOR vInt_sub( 10) ; - //INTMATRIX vInt( 10, vInt_sub) ; - //for ( int i = 0 ; i < 10 ; ++i ) { - // for ( int j = 0 ; j < 10 ; ++j ) { - // vInt[i][j] = i + 10 * j ; - // } - //} - //vInt_sub.resize( 20) ; - //vInt[0].resize( 20) ; - - - - - // la superficie Nurbs deve essere in forma canonica if ( snData.bPeriodicU || snData.bPeriodicV || snData.bExtraKnotes ) return nullptr ; @@ -139,8 +125,6 @@ NurbsToBezierSurface(const SNurbsSurfData& snData) return nullptr ; } - //// numero degli intervalli - //int nInt = nU - 2 * snData.nDeg + 1 ; // verifico le condizioni agli estremi sui nodi (i primi nDeg nodi e gli ultimi nDeg nodi devono essere uguali tra loro) bool bOk = true ; // direzione U @@ -164,49 +148,15 @@ NurbsToBezierSurface(const SNurbsSurfData& snData) if ( ! bOk) return nullptr ; - //// se 1 solo intervallo, la Nurbs ? gi? una curva di Bezier - //if ( nInt == 1) { - // // creo la curva di Bezier - // PtrOwner pCrvBez( CreateCurveBezier()) ; - // if ( IsNull( pCrvBez)) - // return nullptr ; - // // la inizializzo - // if ( ! pCrvBez->Init( snData.nDeg, snData.bRat)) - // return nullptr ; - // for ( int i = 0 ; i <= snData.nDeg ; ++ i) { - // if ( ! snData.bRat) { - // if ( ! pCrvBez->SetControlPoint( i, snData.vCP[i])) - // return nullptr ; - // } - // else { - // if ( ! pCrvBez->SetControlPoint( i, snData.vCP[i], snData.vW[i])) - // return nullptr ; - // } - // } - // // se non ? una curva ma un punto, la invalido - // if ( pCrvBez->IsAPoint()) - // pCrvBez->Init( snData.nDeg, snData.bRat) ; - // // restituisco la curva - // return Release( pCrvBez) ; - //} - - // algoritmo 5.7 del libro "The NURBS book"////////////////////////////////////////////////////////////////////////////////////////////////////////////// // creazione delle strips nella direzione U ( trasformo le curve iso con U costante in bezier) int a = snData.nDegU - 1 ; int b = snData.nDegU ; int nb = 0 ; // numero di strisce in U ( lunghezza con U costante) - //PNTVECTOR vBC ; - //vBC.resize( snData.nCPV * snData.nDegU) ; - //for (int row = 0 ; row < snData.nCPV ; ++row ) { - // for ( int i = 0 ; i <= snData.nDegU ; ++i ) { - // vBC[nDegU*row + i] = ( snData.vCP[nCPU*row + i]) ; - // } - //} vector vCPV( snData.nCPV) ; vector< vector> mBC (snData.nDegU + 1,vCPV ) ; vector< vector> mBC_next (snData.nDegU - 1, vCPV) ; - vector< vector> mPC_strip(snData.nDegU + 1, vCPV) ; // matrice che verr? ingrandita e conterr? la superficie met? bezier e met? NURBS + vector< vector> mPC_strip(snData.nDegU + 1, vCPV) ; // matrice che verrà ingrandita e conterrà la superficie metà bezier e metà NURBS DBLVECTOR vV_W( snData.nCPV) ; vector mW( snData.nDegU + 1, vV_W) ; vector mW_next( snData.nDegU - 1, vV_W) ; @@ -230,11 +180,7 @@ NurbsToBezierSurface(const SNurbsSurfData& snData) } 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 + while ( snData.nDegU != 1 ? b < nU - 1 : b < nU) { // qui correggo un probabile errore, mettendo nU anziché nCPV, come indicato nell'algoritmo int i = b ; while ( b < nU - 1 && abs( snData.vU[b+1] - snData.vU[b]) < EPS_ZERO) ++ b ; @@ -249,11 +195,6 @@ NurbsToBezierSurface(const SNurbsSurfData& snData) for ( int j = 1 ; j <= snData.nDegU - mult ; ++j ) { int save = r - j ; int s = mult + j ; - //for ( int row = 0 ; row < snData.nCPV ; ++row) { - // for ( int k = snData.nDegU ; k >= s ; --k ) { - // vBC[nCPU*row + k] = vAlpha[k-s]*vBC[nCPU*row + k] + ( 1 - vAlfa[k-s]) * vBC[nCPU*row + k - 1] - // } - //} if ( ! snData.bRat ) { for ( int k = snData.nDegU ; k >= s ; --k ) { for ( int row = 0 ; row < snData.nCPV ; ++row) { @@ -333,6 +274,10 @@ NurbsToBezierSurface(const SNurbsSurfData& snData) a = b ; ++b ; } + else if ( snData.nDegU == 1 && b < nU) { + a = b ; + ++b ; + } } // se non ho raffinato allora tutti i nodi avevano gi? molteplicit? massima. Converto direttamente in Bezier la dir U @@ -356,8 +301,6 @@ NurbsToBezierSurface(const SNurbsSurfData& snData) } } } - // devo vedere quante patch ci stanno prendendo i punti che ci sono - //nb = (snData.nCPU - 1) / snData.nDegU ; } else nCPU_ref = snData.nDegU * nb + 1 ; // numero dei punti di controllo in U dopo il raffinamento @@ -395,11 +338,7 @@ NurbsToBezierSurface(const SNurbsSurfData& snData) } bRef = false ; - // 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) { // qui correggo un probabile errore, mettendo nU anzich� nCPV, come indicato nell'algoritmo + while ( snData.nDegV != 1 ? b < nV - 1 : b < nV) { // qui correggo un probabile errore, mettendo nU anziché nCPV, come indicato nell'algoritmo int i = b ; while ( b < nV - 1 && abs( snData.vV[b+1] - snData.vV[b]) < EPS_ZERO) ++ b ; @@ -414,11 +353,6 @@ NurbsToBezierSurface(const SNurbsSurfData& snData) for ( int j = 1 ; j <= snData.nDegV - mult ; ++j ) { int save = r - j ; int s = mult + j ; - //for ( int row = 0 ; row < snData.nCPV ; ++row) { - // for ( int k = snData.nDegU ; k >= s ; --k ) { - // vBC[nCPU*row + k] = vAlpha1[k-s]*vBC[nCPU*row + k] + ( 1 - vAlpha1[k-s]) * vBC[nCPU*row + k - 1] - // } - //} if ( ! snData.bRat) { for ( int k = 0 ; k < nCPU_ref ; ++k) { for ( int row = snData.nDegV ; row >= s ; --row ) { @@ -492,14 +426,12 @@ NurbsToBezierSurface(const SNurbsSurfData& snData) if ( b < nV - 1) { for (int i = 0 ; i < nCPU_ref ; ++ i ) { for ( int row = snData.nDegV - mult ; row <= snData.nDegV ; ++ row) { - //m_BC1[i][row] = snData.mCP[i][b - snData.nDegV + row + 1] ; m_BC1[i][row] = mPC_strip[i][b - snData.nDegV + row + 1] ; } } if ( snData.bRat ) { for (int i = 0 ; i < nCPU_ref ; ++ i ) { for ( int row = snData.nDegV - mult ; row <= snData.nDegV ; ++ row) { - //mW1[i][row] = snData.mW[i][b - snData.nDegV + row + 1] ; mW1[i][row] = mW_strip[i][b - snData.nDegV + row + 1] ; } } @@ -507,7 +439,10 @@ NurbsToBezierSurface(const SNurbsSurfData& snData) a = b ; ++b ; } - + else if ( snData.nDegV == 1 && b < nV) { + a = b ; + ++b ; + } } // se non ho raffinato allora aggiungo direttamente alle matrici della superficie totale int nCPV_ref ; // numero dei punti di controllo in V dopo il raffinamento @@ -532,8 +467,6 @@ NurbsToBezierSurface(const SNurbsSurfData& snData) } } } - // devo vedere quante patch ci stanno prendendo i punti che ci sono - //nc = (snData.nCPV - 1) / snData.nDegV ; } else nCPV_ref = snData.nDegV * nc + 1 ; @@ -553,7 +486,7 @@ NurbsToBezierSurface(const SNurbsSurfData& snData) else { for ( int i = 0 ; i < nCPU_ref; ++ i) { for (int j = 0 ; j < nCPV_ref; ++j) { - pSrfBz->SetControlPoint( i + nCPU_ref * j, mPC_tot[i][j] / mW_tot[i][j], mW_tot[i][j]) ; + pSrfBz->SetControlPoint( i + nCPU_ref * j, mPC_tot[i][j] /*/ mW_tot[i][j]*/, mW_tot[i][j]) ; } } } From a6e3c423408a80957bc307b6a7b57356f0748d5d Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 7 Nov 2023 12:39:49 +0100 Subject: [PATCH 42/44] EgtGeomKernel : - correzione di un errore numerico nel tracking delle curve di trim. --- Tree.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tree.cpp b/Tree.cpp index 9ff9ecd..116fc0c 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -1638,8 +1638,8 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& clTrim) const int nId = -1 ; // se fallisce ritorna un vettore vuoto // verifico che il punto sia all'interno dello spazio parametrico - if ( ptToAssign.x < m_mTree.at( -1).GetBottomLeft().x || ptToAssign.x > m_mTree.at( -1).GetTopRight().x || - ptToAssign.y < m_mTree.at( -1).GetBottomLeft().y || ptToAssign.y > m_mTree.at( -1).GetTopRight().y ) { + if ( ptToAssign.x < m_mTree.at( -1).GetBottomLeft().x - EPS_SMALL || ptToAssign.x > m_mTree.at( -1).GetTopRight().x + EPS_SMALL|| + ptToAssign.y < m_mTree.at( -1).GetBottomLeft().y - EPS_SMALL || ptToAssign.y > m_mTree.at( -1).GetTopRight().y + EPS_SMALL) { //nCells.push_back( - 2) ; return nCells ; } From 000712134028c11e100fef32059c12e9fd441e87 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 7 Nov 2023 17:38:47 +0100 Subject: [PATCH 43/44] EgtGeomKernel : - correzione alla conversione da NURBS a Bezier nel caso razionale. --- SurfAux.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/SurfAux.cpp b/SurfAux.cpp index 49e1e24..799a819 100644 --- a/SurfAux.cpp +++ b/SurfAux.cpp @@ -378,7 +378,7 @@ NurbsToBezierSurface(const SNurbsSurfData& snData) else { for ( int i = 0 ; i < nCPU_ref ; ++i) { m_BC1_next[i][save] = m_BC1[i][snData.nDegV] ; - mW1_next[save] = mW1[snData.nDegV] ; + mW1_next[i][save] = mW1[i][snData.nDegV] ; } } } @@ -424,14 +424,17 @@ NurbsToBezierSurface(const SNurbsSurfData& snData) } if ( b < nV - 1) { - for (int i = 0 ; i < nCPU_ref ; ++ i ) { - for ( int row = snData.nDegV - mult ; row <= snData.nDegV ; ++ row) { - m_BC1[i][row] = mPC_strip[i][b - snData.nDegV + row + 1] ; - } - } - if ( snData.bRat ) { + if ( ! snData.bRat) { for (int i = 0 ; i < nCPU_ref ; ++ i ) { for ( int row = snData.nDegV - mult ; row <= snData.nDegV ; ++ row) { + m_BC1[i][row] = mPC_strip[i][b - snData.nDegV + row + 1] ; + } + } + } + else { + for (int i = 0 ; i < nCPU_ref ; ++ i ) { + for ( int row = snData.nDegV - mult ; row <= snData.nDegV ; ++ row) { + m_BC1[i][row] = mPC_strip[i][b - snData.nDegV + row + 1] * mW_strip[i][b - snData.nDegV + row + 1] ; mW1[i][row] = mW_strip[i][b - snData.nDegV + row + 1] ; } } From 68d0198f3ffe105b0fbafab9edc480230ed005cb Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 7 Nov 2023 17:39:43 +0100 Subject: [PATCH 44/44] EgtGeomKernel : - debug. --- SurfBezier.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 79687d2..6ddb279 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -1509,7 +1509,8 @@ SurfBezier::GetAuxSurf( void) const Point3d ptMax = std::get<1>( vTrees[i]) ; Tree.SetSurf( this, true, ptMin, ptMax) ; //Tree.BuildTree_test() ; // per debug - Tree.BuildTree( 5 * LIN_TOL_FINE, 1) ; + //Tree.BuildTree( 5 * LIN_TOL_FINE, 1) ; + Tree.BuildTree( LIN_TOL_FINE, 0.1) ; Tree.GetPolygons( vvPL) ; //Tree.GetPolygonsBasic( vPL) ; // per usare i polygon basic } @@ -1572,7 +1573,8 @@ SurfBezier::GetLeaves( std::vector>& vLeaves) Point3d ptMax = std::get<1>( vTrees[i]) ; Tree.SetSurf( this, true, ptMin, ptMax) ; //Tree.BuildTree_test() ; - Tree.BuildTree( 5 * LIN_TOL_FINE, 1) ; + //Tree.BuildTree( 5 * LIN_TOL_FINE, 1) ; + Tree.BuildTree( LIN_TOL_FINE, 0.1) ; Tree.GetLeaves( vCells) ; for (int k = 0 ; k < (int)vCells.size(); ++ k ) { std::tuple tCell ;