EgtGeomKernel :

- implementazione delle classi KdTree e Cell
- problemi : bilanciamento albero e uso puntatori
This commit is contained in:
Daniele Bariletti
2023-05-03 12:09:58 +02:00
parent 13b02f51a3
commit 6a3fc0fd97
6 changed files with 562 additions and 52 deletions
+2
View File
@@ -339,6 +339,7 @@ copy $(TargetPath) \EgtProg\Dll64</Command>
<ClCompile Include="IntersPlaneTria.cpp" />
<ClCompile Include="IntersSurfTmSurfTm.cpp" />
<ClCompile Include="IntersTriaTria.cpp" />
<ClCompile Include="KdTree.cpp" />
<ClCompile Include="MedialAxis.cpp" />
<ClCompile Include="OffsetCurve.cpp" />
<ClCompile Include="DistPointArc.cpp" />
@@ -603,6 +604,7 @@ copy $(TargetPath) \EgtProg\Dll64</Command>
<ClInclude Include="IntersLineSurfStd.h" />
<ClInclude Include="IntersLineTria.h" />
<ClInclude Include="IterManager.h" />
<ClInclude Include="KdTree.h" />
<ClInclude Include="Material.h" />
<ClInclude Include="FontNfe.h" />
<ClInclude Include="MC_Tables.h" />
+6
View File
@@ -471,6 +471,9 @@
<ClCompile Include="MedialAxis.cpp">
<Filter>File di origine\GeoOffset</Filter>
</ClCompile>
<ClCompile Include="KdTree.cpp">
<Filter>File di origine\Base</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
@@ -1103,6 +1106,9 @@
<ClInclude Include="CDeCapsTria.h">
<Filter>File di intestazione</Filter>
</ClInclude>
<ClInclude Include="KdTree.h">
<Filter>File di intestazione</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="EgtGeomKernel.rc">
+286
View File
@@ -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<Cell> 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<Cell>() ;
//m_cChild2 = &cChild2 ;
//m_cParent = &cParent ;
//m_cTop = &cTop ;
//m_cBottom = &cBottom ;
//m_cLeft = &cLeft ;
//m_cRight = &cRight ;
m_cChild2 = make_shared<Cell>() ;
//m_cParent = make_shared<Cell>() ;
//m_cTop = make_shared<Cell>() ;
//m_cBottom = make_shared<Cell>() ;
//m_cLeft = make_shared<Cell>() ;
//m_cRight = make_shared<Cell>() ;
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<Cell>(*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<Cell>(*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<Cell>(*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<Cell>(*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<Cell>())
{}
//----------------------------------------------------------------------------
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<Cell>() ;
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<Cell>() ;
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<Cell> cToSplit = make_shared<Cell>(&m_cRoot) ;
shared_ptr<Cell> 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 ;
}
+73
View File
@@ -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<Cell> 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<Cell> 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<Cell> m_cTop ; // cella adiacente al lato top
std::shared_ptr<Cell> m_cBottom ; // cella adiacente al lato bottom
std::shared_ptr<Cell> m_cLeft ; // cella adiacente al lato left
std::shared_ptr<Cell> m_cRight ; // cella adiacente al lato right
std::shared_ptr<Cell> m_cParent ; // cella genitore
std::shared_ptr<Cell> m_cChild1 ; // prima cella figlio
std::shared_ptr<Cell> 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<Cell> m_cRoot ; // cella base
const SurfBezier* m_pSrfBz ; // root
POLYLINEVECTOR m_vPolygons ; // vettore dei poligoni del kd-tree
} ;
+194 -51
View File
@@ -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<SurfTriMesh> 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 ;
}
+1 -1
View File
@@ -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
} ;
//-----------------------------------------------------------------------------