From 2d83c860f24be8ab4700b3de6712ca18999b47c9 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 8 May 2023 17:02:02 +0200 Subject: [PATCH] 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