From 6a3fc0fd97b7529d8f88183de78e8fbd20dd0711 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Wed, 3 May 2023 12:09:58 +0200 Subject: [PATCH] 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 } ; //-----------------------------------------------------------------------------