EgtGeomKernel :

- modifiche e migliorie calcoli per approssimazione di superfici di Bezier con trimesh
- aggiunte funzioni globali per impostare tolleranze di approssimazione delle superfici di Bezier
- eliminazione dell'uso della funzione pow (inefficiente) dove non necessaria
- utilizzo di Pow (efficiente) per potenze con esponente intero.
This commit is contained in:
Dario Sassi
2025-08-22 11:44:56 +02:00
parent 1b9738eace
commit f22ea484db
7 changed files with 479 additions and 637 deletions
+254 -435
View File
@@ -21,12 +21,13 @@
#include "SurfFlatRegion.h"
#include "IntersLineLine.h"
#include "AdjustLoops.h"
#include "/EgtDev/Include/EGkDistLineLine.h"
#include "/EgtDev/Include/EGkPolyLine.h"
#include "/EgtDev/Include/EGkDistPointCurve.h"
#include "/EgtDev/Include/EGkCurve.h"
#include "DistPointCrvComposite.h"
#include "/EgtDev/Include/EGkSfrCreate.h"
#include "/EgtDev/Include/EGkDistPointCurve.h"
#include "/EgtDev/Include/EGkDistLineLine.h"
#include "/EgtDev/Include/EGkDistPointTria.h"
#include "/EgtDev/Include/EGkStringUtils3d.h"
#include <algorithm>
#include <numeric>
@@ -34,8 +35,8 @@ using namespace std ;
//----------------------------------------------------------------------------
Tree::Tree( void)
: m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosedU( false), m_bClosedV( false), m_vbPole( { false, false, false, false}),
m_bSplitPatches( true), m_bTestMode( false)
: m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosedU( false), m_bClosedV( false),
m_vbPole{ false, false, false, false}
{
Point3d ptBl( 0, 0), ptTr ( 1 * SBZ_TREG_COEFF, 1 * SBZ_TREG_COEFF) ;
Cell cRoot( ptBl, ptTr) ;
@@ -49,8 +50,8 @@ Tree::~Tree( void)
//----------------------------------------------------------------------------
Tree::Tree( const Point3d ptBl, const Point3d ptTr)
: m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosedU( false), m_bClosedV( false), m_vbPole( { false, false, false, false}),
m_bSplitPatches( true), m_bTestMode( false)
: m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosedU( false), m_bClosedV( false),
m_vbPole{ false, false, false, false}
{
Cell cRoot( ptBl, ptTr) ;
m_mTree.insert( pair< int, Cell>( -1, cRoot)) ;
@@ -101,32 +102,40 @@ Tree::AdjustLoop( PolyLine& pl, POLYLINEVECTOR& vPl, BOOLVECTOR& vbOrientation)
}
//----------------------------------------------------------------------------
bool
Tree::GetPoint( double dU, double dV, Point3d& pt) const
static double
GetHalfKey( double dPar)
{
pair<int64_t, int64_t> key (static_cast<int64_t>(dU * pow(2,15)), static_cast<int64_t>(dV * pow(2,15))) ;
const int TWO_TO_15 = 32768 ;
return ( dPar * TWO_TO_15) ;
}
//----------------------------------------------------------------------------
bool
Tree::GetPoint( double dU, double dV, Point3d& ptP) const
{
pair<int64_t, int64_t> key( int64_t( GetHalfKey( dU)), int64_t( GetHalfKey( dV))) ;
bool bOk = true ;
if ( m_mPt3d.find( key) == m_mPt3d.end()) {
bOk = bOk && m_pSrfBz->GetPoint( dU / SBZ_TREG_COEFF, dV / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt) ;
m_mPt3d[key] = pt ;
bOk = bOk && m_pSrfBz->GetPoint( dU / SBZ_TREG_COEFF, dV / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP) ;
m_mPt3d[key] = ptP ;
}
pt = m_mPt3d[key] ;
ptP = m_mPt3d[key] ;
return bOk ;
}
//----------------------------------------------------------------------------
bool
Tree::SavePoint( double dU, double dV, Point3d& pt)
Tree::SavePoint( double dU, double dV, Point3d& ptP)
{
pair<int64_t, int64_t> key (static_cast<int64_t>(dU * pow(2,15)), static_cast<int64_t>(dV * pow(2,15))) ;
pair<int64_t, int64_t> key( int64_t( GetHalfKey( dU)), int64_t( GetHalfKey( dV))) ;
if ( m_mPt3d.find( key) == m_mPt3d.end())
m_mPt3d[key] = pt ;
m_mPt3d[key] = ptP ;
return true ;
}
//----------------------------------------------------------------------------
bool
Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMin, const Point3d& ptMax)
Tree::SetSurf( const SurfBezier* pSrfBz, const Point3d& ptMin, const Point3d& ptMax)
{
if ( pSrfBz == nullptr || ! pSrfBz->IsValid())
return false ;
@@ -140,7 +149,6 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi
m_vCCLoop2D.clear() ;
m_pSrfBz = pSrfBz ;
m_bSplitPatches = bSplitPatches ;
// le coordinate delle celle sono nello spazio parametrico
int nDegU, nDegV, nSpanU, nSpanV ;
bool bIsRat, bTrimmed ;
@@ -230,43 +238,52 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi
// se richiesto divido preliminarmente le patches
m_vnParents.clear() ;
bool bIsPlanar = m_pSrfBz->IsPlanar() ;
if( ! bIsPlanar || m_bMulti) {
// se la superficie è chiusa lungo il parametro U, sistemo le adiacenze al bordo
if ( AreSamePointApprox(ptP00, ptP10) && AreSamePointApprox(ptP01, ptP11) ) {
m_mTree[-1].m_nLeft = -1 ;
m_mTree[-1].m_nRight = -1 ;
m_bClosedU = true ;
if ( ! bIsPlanar || m_bMulti) {
// se la superficie è chiusa lungo il parametro U, sistemo le adiacenze al bordo
if ( AreSamePointApprox( ptP00, ptP10) && AreSamePointApprox( ptP01, ptP11) ) {
Point3d ptP0001 ;
GetPoint( ptMin.x, ( ptMin.y + ptTop.y) / 2, ptP0001) ;
Point3d ptP1011 ;
GetPoint( ptTop.x, ( ptMin.y + ptTop.y) / 2, ptP1011) ;
if ( AreSamePointApprox( ptP0001, ptP1011)) {
m_mTree[-1].m_nLeft = -1 ;
m_mTree[-1].m_nRight = -1 ;
m_bClosedU = true ;
}
}
// se la superficie è chiusa lungo il parametro V, sistemo le adiacenze al bordo
if ( ( AreSamePointApprox(ptP00, ptP01) && AreSamePointApprox(ptP10, ptP11) ) ) {
m_mTree[-1].m_nTop = -1 ;
m_mTree[-1].m_nBottom = -1 ;
m_bClosedV = true ;
// se la superficie è chiusa lungo il parametro V, sistemo le adiacenze al bordo
if ( ( AreSamePointApprox( ptP00, ptP01) && AreSamePointApprox( ptP10, ptP11) ) ) {
Point3d ptP0010 ;
GetPoint( ( ptMin.x + ptTop.x) / 2, ptMin.y, ptP0010) ;
Point3d ptP0111 ;
GetPoint( (ptMin.x + ptTop.x) / 2, ptTop.y, ptP0111) ;
if ( AreSamePointApprox( ptP0010, ptP0111)) {
m_mTree[-1].m_nTop = -1 ;
m_mTree[-1].m_nBottom = -1 ;
m_bClosedV = true ;
}
}
if ( (m_bSplitPatches && ( nSpanU > 1 || nSpanV > 1)) || m_bClosedU || m_bClosedV) {
if ( nSpanU > 1 || nSpanV > 1 || m_bClosedU || m_bClosedV) {
int nId = -1 ;
int nSplit = nSpanU ;
bool bSplitInHalf = false ;
// se la superficie è chiusa lungo un parametro la splitto lungo quel parametro almeno una volta
if( m_bClosedU && nSpanU == 1) {
// se la superficie è chiusa lungo un parametro la splitto lungo quel parametro almeno una volta
if ( m_bClosedU && nSpanU == 1) {
nSplit = 2 ;
bSplitInHalf = true ;
}
for ( int i = 1 ; i < nSplit ; ++i) {
m_mTree[nId].SetSplitDirVert( true) ;
double dSplit = bSplitInHalf ? i * SBZ_TREG_COEFF / 2 : i * SBZ_TREG_COEFF ;
if ( Split( nId, dSplit)) {
//++ nId ;
//++ nId ;
double dSplit = ( bSplitInHalf ? i * SBZ_TREG_COEFF / 2 : i * SBZ_TREG_COEFF) ;
if ( Split( nId, dSplit))
nId = m_mTree[nId].m_nChild2 ;
}
}
INTVECTOR vLeaves ;
GetHeightLeaves( -1, vLeaves) ;
nSplit = nSpanV - 1 ;
bSplitInHalf = false ;
// se la superficie è chiusa lungo un parametro la splitto lungo quel parametro almeno una volta
if( m_bClosedV && nSpanV == 1) {
// se la superficie è chiusa lungo un parametro la splitto lungo quel parametro almeno una volta
if ( m_bClosedV && nSpanV == 1) {
nSplit = 1 ;
bSplitInHalf = true ;
}
@@ -284,20 +301,8 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi
// se è chiusa e non ho già fatto split preliminare, splitto sul parametro su cui è chiusa
// e sistemo le adiacenze
if ( ( AreSamePointApprox( ptP00, ptP01) || AreSamePointApprox( ptP10, ptP11)) ||
( AreSamePointApprox( ptP00, ptP10) || AreSamePointApprox( ptP01, ptP11))) {
( AreSamePointApprox( ptP00, ptP10) || AreSamePointApprox( ptP01, ptP11))) {
if ( ( AreSamePointApprox( ptP00, ptP01) || AreSamePointApprox( ptP10, ptP11))) {
////questo in teoria non serve più perché lo faccio appena sopra
if( int( m_mTree.size()) == 1) {
if ( AreSamePointApprox( ptP00, ptP01) && AreSamePointApprox( ptP10, ptP11)) {
m_mTree[-1].m_nTop = -1 ;
m_mTree[-1].m_nBottom = -1 ;
m_bClosedV = true ;
}
m_mTree[-1].SetSplitDirVert( false) ;
Split( -1) ;
}
////////
// qui devo fare il controllo capped ( chiusura a semisfera)
// devo controllare se i punti ai parametri U=0 e U=1 sono tutti coincidenti
@@ -314,7 +319,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi
}
m_vbPole[1] = bPole0 ;
m_vbPole[3] = bPole1 ;
if ( bPole0 && bPole1 && int( m_mTree.size() == 3)) {
if ( bPole0 && bPole1 && m_mTree.size() == 3) {
m_mTree[0].SetSplitDirVert( true) ;
Split( 0) ;
m_mTree[1].SetSplitDirVert( true) ;
@@ -323,29 +328,16 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi
}
// nella condizione di questo if non controllo eventuali divisioni preliminari, perché ne tengo conto dopo
if ( AreSamePointApprox( ptP00, ptP10) || AreSamePointApprox( ptP01, ptP11)) {
//// questo in teoria non serve più perché lo faccio sopra
if ( m_mTree.size() == 1) {
if ( AreSamePointApprox( ptP00, ptP10) && AreSamePointApprox( ptP01, ptP11)) {
m_mTree[-1].m_nLeft = -1 ;
m_mTree[-1].m_nRight = -1 ;
m_bClosedU = true ;
}
m_mTree[-1].SetSplitDirVert( true) ;
Split( -1) ;
}
////////
// devo controllare se i punti ai parametri V=0 e V=1 sono tutti coincidenti
// in caso devo fare uno split nell'altra direzione
// devo controllare se i punti ai parametri V=0 e V=1 sono tutti coincidenti
// in caso devo fare uno split nell'altra direzione
bool bOk = false ;
bool bPole0 = true, bPole1 = true ;
Point3d ptV0, ptV1 ;
// controllo se tutti i punti sull'isoparametrica sono uguali
// controllo se tutti i punti sull'isoparametrica sono uguali
for ( int i = 1 ; i < nDegU * nSpanU + 1 ; ++ i) {
ptV0 = m_pSrfBz->GetControlPoint( i, &bOk) ;
Point3d ptV0 = m_pSrfBz->GetControlPoint( i, &bOk) ;
bPole0 = bPole0 && AreSamePointApprox( ptP00, ptV0) ;
ptV1 = m_pSrfBz->GetControlPoint( i + ( nDegU * nSpanU + 1) * ( nDegV * nSpanV), &bOk) ;
Point3d ptV1 = m_pSrfBz->GetControlPoint( i + ( nDegU * nSpanU + 1) * ( nDegV * nSpanV), &bOk) ;
bPole1 = bPole1 && AreSamePointApprox( ptP01, ptV1) ;
}
m_vbPole[0] = bPole1 ;
@@ -357,7 +349,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi
Split( 1) ;
}
// se ho fatto solo 1 split orizzontale e ho due celle foglie nId = 0 e nId = 1
if ( int( m_mTree.size() == 3) && ! m_mTree.at(-1).IsSplitVert()) {
if ( m_mTree.size() == 3 && ! m_mTree.at(-1).IsSplitVert()) {
m_mTree[0].m_nLeft = -1 ;
m_mTree[0].m_nRight = -1 ;
m_mTree[1].m_nLeft = -1 ;
@@ -370,41 +362,11 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi
}
}
}
// calcolo i parent che ho creato con le eventuali divisioni preliminari
// calcolo i parent che ho creato con le eventuali divisioni preliminari
INTVECTOR vLeaves ;
GetHeightLeaves( -1, vLeaves) ;
m_vnParents = vLeaves ;
// calcolo e salvo la lunghezza reale delle curve di bezier di bordo
PtrOwner<CurveComposite> pCrvV0( m_pSrfBz->GetCurveOnU( 0)) ;
PtrOwner<CurveComposite> pCrvV1( m_pSrfBz->GetCurveOnU( double(nSpanV))) ;
PtrOwner<CurveComposite> pCrvU0( m_pSrfBz->GetCurveOnV( 0)) ;
PtrOwner<CurveComposite> pCrvU1( m_pSrfBz->GetCurveOnV( double(nSpanU))) ;
double dLen0 ; pCrvV0->GetApproxLength( dLen0) ;
double dLen1 ; pCrvU1->GetApproxLength( dLen1) ;
double dLen2 ; pCrvV1->GetApproxLength( dLen2) ;
double dLen3 ; pCrvU0->GetApproxLength( dLen3) ;
if ( dLen0 < EPS_ZERO && dLen2 < EPS_ZERO ) {
PtrOwner<CurveComposite> pCrvV( m_pSrfBz->GetCurveOnU( double(nSpanV) / 2)) ;
pCrvV->GetApproxLength( dLen0) ;
if ( dLen0 < EPS_ZERO ) {
pCrvV.Set( m_pSrfBz->GetCurveOnU( double(nSpanV) / 4)) ;
pCrvV->GetApproxLength( dLen0) ;
}
}
if ( dLen1 < EPS_ZERO && dLen3 < EPS_ZERO ) {
PtrOwner<CurveComposite> pCrvU( m_pSrfBz->GetCurveOnV( double(nSpanU) / 2)) ;
pCrvU->GetApproxLength( dLen1) ;
if ( dLen1 < EPS_ZERO ) {
pCrvU.Set( m_pSrfBz->GetCurveOnV( double(nSpanU) / 4)) ;
pCrvU->GetApproxLength( dLen1) ;
}
}
m_vDim.clear() ;
m_vDim.push_back( ( dLen0 > EPS_ZERO ? dLen0 : 1)) ;
m_vDim.push_back( ( dLen1 > EPS_ZERO ? dLen1 : 1)) ;
m_vDim.push_back( ( dLen2 > EPS_ZERO ? dLen2 : 1)) ;
m_vDim.push_back( ( dLen3 > EPS_ZERO ? dLen3 : 1)) ;
return true ;
}
@@ -419,7 +381,7 @@ AddOrMergeBBox( const BBox3d& bBox3dA, vector<BBox3d>& vBBox, bool bAdd = true,
return true ;
}
bool bAdded = false ;
for ( int b = 0 ; b < (int)vBBox.size() ; ++b) {
for ( int b = 0 ; b < int( vBBox.size()) ; ++b) {
BBox3d bBox3dB = vBBox[b] ;
BBox3d b3Int ;
// se sono celle diverse e ho un'intersezione faccio il merge
@@ -565,7 +527,7 @@ bool
Tree::Split( int nId)
{
double dValue ;
Cell& cCell = m_mTree.at(nId) ;
Cell& cCell = m_mTree.at( nId) ;
if ( cCell.IsSplitVert())
dValue = ( cCell.GetBottomLeft().x + cCell.GetTopRight().x) / 2 ;
else
@@ -573,223 +535,44 @@ Tree::Split( int nId)
return Split( nId, dValue) ;
}
//----------------------------------------------------------------------------
bool
Tree::BuildTree_test( double dLinTol, double dSideMin, double dSideMax)
{
// per poter usare questa funzione, anziché quella normale, bisogna:
// - commentare la parte di funzione di SetSurf dove si fanno gli split preliminare
// - se si usa anche la funzione GetLeaves, bisogna anche lì usare BuildTree_test al posto di BuildTree
//celle 0,1
m_mTree[-1].SetSplitDirVert( true) ;
Split( -1) ;
//celle 2,3
m_mTree[0].SetSplitDirVert( false) ;
Split( 0) ;
//celle 4,5
m_mTree[2].SetSplitDirVert( false) ;
Split( 2) ;
//celle 6,7
m_mTree[3].SetSplitDirVert( true) ;
Split( 3) ;
//celle 8,9
m_mTree[1].SetSplitDirVert( false) ;
Split( 1) ;
//celle 10,11
m_mTree[8].SetSplitDirVert( true) ;
Split( 8) ;
//celle 12,13
m_mTree[9].SetSplitDirVert( false) ;
Split( 9) ;
m_vnLeaves.push_back( 4) ;
//m_vnLeaves.push_back( 5) ;
m_vnLeaves.push_back( 6) ;
//m_vnLeaves.push_back( 7) ;
//m_vnLeaves.push_back( 10) ;
m_vnLeaves.push_back( 11) ;
//m_vnLeaves.push_back( 12) ;
m_vnLeaves.push_back( 13) ;
// aggiunta di split
//celle 14,15
m_mTree[5].SetSplitDirVert( true) ;
Split( 5) ;
m_vnLeaves.push_back( 14) ;
m_vnLeaves.push_back( 15) ;
//celle 16,17
m_mTree[7].SetSplitDirVert( false) ;
Split( 7) ;
m_vnLeaves.push_back( 16) ;
m_vnLeaves.push_back( 17) ;
//celle 18,19
m_mTree[12].SetSplitDirVert( true) ;
Split( 12) ;
m_vnLeaves.push_back( 18) ;
m_vnLeaves.push_back( 19) ;
//celle 20,21
m_mTree[10].SetSplitDirVert( false) ;
Split( 10) ;
m_vnLeaves.push_back( 20) ;
m_vnLeaves.push_back( 21) ;
// riempio anche la lista dei parent delle celle
m_vnParents = m_vnLeaves ;
return true ;
}
//----------------------------------------------------------------------------
bool
Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax)
{
// suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri
// suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri
int nCToSplit = -1 ;
Cell* pcToSplit = &m_mTree[nCToSplit] ;
bool bIsPlanar = m_pSrfBz->IsPlanar() ;
if ( ! m_bBilinear) {
while ( nCToSplit != -2 && pcToSplit->IsProcessed() == false) {
// controllo che la cella non sia già stata preliminarmente splittata
while ( nCToSplit != -2 && ! pcToSplit->IsProcessed()) {
// se la pezza non è già stata preliminarmente splittata
if ( pcToSplit->IsLeaf()) {
// calcolo in quale direzione ho più curvatura
// ptP00P10 è un punto tra P00 e P10
double dCurvU = 0, dCurvV = 0 ;
// dimensioni parametriche della pezza
double dLenParU = ( pcToSplit->GetTopRight().x - pcToSplit->GetBottomLeft().x) / SBZ_TREG_COEFF ;
double dLenParV = ( pcToSplit->GetTopRight().y - pcToSplit->GetBottomLeft().y) / SBZ_TREG_COEFF ;
Point3d ptP00, ptP10, ptP11, ptP01 ;
// i vertici della cella
GetPoint(pcToSplit->GetBottomLeft().x, pcToSplit->GetBottomLeft().y, ptP00) ;
GetPoint(pcToSplit->GetTopRight().x, pcToSplit->GetBottomLeft().y, ptP10) ;
GetPoint(pcToSplit->GetTopRight().x, pcToSplit->GetTopRight().y, ptP11) ;
GetPoint(pcToSplit->GetBottomLeft().x, pcToSplit->GetTopRight().y, ptP01) ;
if ( dLenParU <= 1. / m_nDegV || dLenParV <= 1. / m_nDegU || Dist(ptP00, ptP11) < dSideMin * 2
|| Dist(ptP10, ptP01) < dSideMin * 2) {
double dU = ( pcToSplit->GetTopRight().x + pcToSplit->GetBottomLeft().x) / 2 ;
double dV = ( pcToSplit->GetTopRight().y + pcToSplit->GetBottomLeft().y) / 2 ;
double dULoc = 0.5, dVLoc = 0.5 ;
Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00 ;
GetPoint( dU, dV, ptPSrf) ;
GetPoint( dU, pcToSplit->GetBottomLeft().y, ptP00P10) ;
GetPoint( pcToSplit->GetTopRight().x, dV, ptP10P11) ;
GetPoint( dU, pcToSplit->GetTopRight().y, ptP11P01) ;
GetPoint( pcToSplit->GetBottomLeft().x, dV, ptP01P00) ;
Point3d ptV = ( 1 - dULoc) * ptP00P10 + dULoc * ptP11P01 ;
Point3d ptU = ( 1 - dVLoc) * ptP10P11 + dVLoc * ptP01P00 ;
dCurvV = Dist( ptV, ptPSrf) ;
dCurvU = Dist( ptU, ptPSrf) ;
}
// faccio un'analisi più fine della curvatura se almeno il grado di una curva di uno dei due parametri è alto e
// se sto ancora guardando una cella abbastanza grande
else{
Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00, ptPSrfMid ;
double dStep = 1. / ( m_nDegU * 2) ;
for ( double k = dStep ; k < 1 + EPS_SMALL ; k = k + dStep) {
double dU = ( k * pcToSplit->GetTopRight().x + ( 1 - k) * pcToSplit->GetBottomLeft().x) ;
double dV = ( pcToSplit->GetTopRight().y + pcToSplit->GetBottomLeft().y) / 2 ;
GetPoint( dU, dV, ptPSrf) ;
if ( k == 0.5)
ptPSrfMid = ptPSrf ;
GetPoint( dU, pcToSplit->GetBottomLeft().y, ptP00P10) ;
GetPoint( dU, pcToSplit->GetTopRight().y, ptP11P01) ;
CurveLine clV ;
clV.Set( ptP00P10, ptP11P01) ;
DistPointCurve dpc( ptPSrf, clV) ;
double dDist ;
dpc.GetDist( dDist) ;
dCurvV = max( dCurvV, dDist) ;
}
dStep = 1. / ( m_nDegV * 2) ;
for ( double k = dStep ; k < 1 + EPS_SMALL ; k = k + dStep) {
double dU = ( pcToSplit->GetTopRight().x + pcToSplit->GetBottomLeft().x) / 2 ;
double dV = ( k * pcToSplit->GetTopRight().y + ( 1 - k) * pcToSplit->GetBottomLeft().y) ;
if ( k == 0.5 && ! AreSamePointApprox( ORIG, ptPSrfMid))
ptPSrf = ptPSrfMid ;
else
GetPoint( dU, dV, ptPSrf) ;
GetPoint( pcToSplit->GetTopRight().x, dV, ptP10P11) ;
GetPoint( pcToSplit->GetBottomLeft().x, dV, ptP01P00) ;
CurveLine clU ;
clU.Set( ptP01P00, ptP10P11) ;
DistPointCurve dpc( ptPSrf, clU) ;
double dDist ;
dpc.GetDist( dDist) ;
dCurvU = max( dCurvU, dDist) ;
}
}
// devo calcolare anche il twist, in caso di bordi rettilinei ( superficie di grado maggiore di 1, ma che in realtà è una bilineare)
// NON posso guardare la distanza tra il punto medio delle diagonali e il punto centrale della cella ( uLoc = 0.5, vLoc = 0.5)
// posso guardare la distanza tra le due diagonali
bool bTwist = false ;
// serve una valutazione più fine, sennò approssimo la superficie in modo troppo grossolano
DistLineLine dll( ptP00, ptP11, ptP10, ptP01, true, true) ;
double dDist = 0 ; dll.GetDist( dDist) ;
if ( dDist > max(dCurvU, dCurvV) || dDist < 5 * EPS_SMALL) {
bool bFlat = false ;
// controllo se la cella è twistata di 180 gradi e quindi piatta
Triangle3d tria1, tria2 ;
tria1.Set( ptP00, ptP10, ptP11) ; tria1.Validate( true) ;
tria2.Set( ptP00, ptP11, ptP01) ; tria2.Validate( true) ;
if( AreOppositeVectorEpsilon(tria1.GetN(), tria2.GetN(), 5 * EPS_SMALL)) {
bTwist = true ;
bFlat = true ;
}
// controllo che la cella non sia piatta
if( ! bTwist) {
PolyLine plCell ;
plCell.AddUPoint(0,ptP00) ;
plCell.AddUPoint(1,ptP10) ;
plCell.AddUPoint(2,ptP11) ;
double dU = (pcToSplit->GetTopRight().x + pcToSplit->GetBottomLeft().x) / 2 ;
double dV = (pcToSplit->GetTopRight().y + pcToSplit->GetBottomLeft().y) / 2 ;
Point3d ptCen ; GetPoint( dU, dV, ptCen) ;
plCell.AddUPoint(3,ptCen) ;
plCell.AddUPoint(4,ptP01) ;
plCell.Close() ;
Plane3d plPlane ; double dArea = 0 ;
bFlat = plCell.IsClosedAndFlat( plPlane, dArea, 10 * EPS_SMALL) ;
}
if( ! bFlat && dDist > 5 * EPS_SMALL) {
bTwist = true ;
// devo decidere in quale direzione splittare
// dovrei capire in quale delle due direzioni è più torta la superficie
Vector3d vtU0 = ptP10 - ptP00 ;
Vector3d vtU1 = ptP11 - ptP01 ;
double dAngU ;
bool bDetU = false ;
vtU0.GetRotation( vtU1, vtU0 ^ vtU1, dAngU, bDetU) ;
Vector3d vtV0 = ptP01 - ptP00 ;
Vector3d vtV1 = ptP11 - ptP10 ;
double dAngV ;
bool bDetV = false ;
// faccio la get rotation tra le coppie vettori, usando come asse il loro prodotto vettoriale per ottenere la rotazione tra i due lati
// splitto nella direzione perpendicolare alla coppia di vettori più torti tra loro.
vtV0.GetRotation( vtV1, vtV0 ^ vtV1, dAngV, bDetV) ;
if ( dAngU > dAngV)
dCurvV = dDist ;
else
dCurvU = dDist ;
}
}
// vertici e centro della pezza
Point3d ptP00, ptP10, ptP11, ptP01, ptCen ;
GetPoint( pcToSplit->GetBottomLeft().x, pcToSplit->GetBottomLeft().y, ptP00) ;
GetPoint( pcToSplit->GetTopRight().x, pcToSplit->GetBottomLeft().y, ptP10) ;
GetPoint( pcToSplit->GetTopRight().x, pcToSplit->GetTopRight().y, ptP11) ;
GetPoint( pcToSplit->GetBottomLeft().x, pcToSplit->GetTopRight().y, ptP01) ;
GetPoint( pcToSplit->GetCenter().x, pcToSplit->GetCenter().y, ptCen) ;
//{ string sLog = "P00=" + ToString( ptP00, 3) + " P10=" + ToString( ptP10, 3) +
// " P11=" + ToString( ptP11, 3) + " P01=" + ToString( ptP01, 3) +
// " Cen=" + ToString( ptCen, 3);
// LOG_DBG_INFO( GetEGkLogger(), sLog.c_str())}
// per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza
// misura approssimativa della curvatura in una direzione
bool bVert ;
if ( dCurvV > dCurvU) {
// lungo la direzione V ho una curvatura maggiore
bVert = false ;
}
else {
// lungo la direzione U ho una curvatura maggiore
bVert = true ;
}
pcToSplit->SetSplitDirVert( bVert) ;
// distanza reale tra i vertici della cella
// distanze sul contorno tra i quattro vertici
double dLen0 = Dist( ptP00, ptP10) ;
double dLen1 = Dist( ptP10, ptP11) ;
double dLen2 = Dist( ptP01, ptP11) ;
double dLen3 = Dist( ptP00, ptP01) ;
// distanza reale tra i vertici della pezza
if ( dLen0 < EPS_ZERO && dLen2 < EPS_ZERO ) {
double dV = ( pcToSplit->GetBottomLeft().y + pcToSplit->GetTopRight().y) / 2 / SBZ_TREG_COEFF ;
double dV = pcToSplit->GetCenter().y / SBZ_TREG_COEFF ;
PtrOwner<CurveComposite> pCrvV( m_pSrfBz->GetCurveOnU( dV)) ;
double dLenU0, dLenU1 ;
pCrvV->GetLengthAtParam( pcToSplit->GetBottomLeft().x / SBZ_TREG_COEFF, dLenU0) ;
@@ -797,126 +580,177 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax)
dLen0 = abs( dLenU1 - dLenU0) ;
}
if ( dLen1 < EPS_ZERO && dLen3 < EPS_ZERO ) {
double dU = ( pcToSplit->GetBottomLeft().x + pcToSplit->GetTopRight().x) / 2 / SBZ_TREG_COEFF ;
double dU = pcToSplit->GetCenter().x / SBZ_TREG_COEFF ;
PtrOwner<CurveComposite> pCrvU( m_pSrfBz->GetCurveOnV( dU)) ;
double dLenV0, dLenV1 ;
pCrvU->GetLengthAtParam( pcToSplit->GetBottomLeft().y / SBZ_TREG_COEFF, dLenV0) ;
pCrvU->GetLengthAtParam( pcToSplit->GetTopRight().y / SBZ_TREG_COEFF, dLenV1) ;
dLen1 = abs( dLenV1 - dLenV0) ;
}
// calcolo massimo della freccia (sagitta)
double dSagU = 0, dSagV = 0 ;
// da distanza tra centro e triangoli di approssimazione
if ( dSagU < dLinTol && dSagV < dLinTol) {
// distanza del centro dai due triangoli con la prima diagonale
Triangle3d Tria1A, Tria1B ;
Tria1A.Set( ptP00, ptP10, ptP11) ; Tria1A.Validate( true) ;
Tria1B.Set( ptP00, ptP11, ptP01) ; Tria1B.Validate( true) ;
double dDist1A = NAN ;
DistPointTriangle( ptCen, Tria1A).GetDist( dDist1A) ;
double dDist1B = NAN ;
DistPointTriangle( ptCen, Tria1B).GetDist( dDist1B) ;
double dDist1 = min( dDist1A, dDist1B) ;
// distanza del centro dai due triangoli con la seconda diagonale
Triangle3d Tria2A, Tria2B ;
Tria2A.Set( ptP10, ptP11, ptP01) ; Tria2A.Validate( true) ;
Tria2B.Set( ptP10, ptP01, ptP00) ; Tria2B.Validate( true) ;
double dDist2A = NAN ;
DistPointTriangle( ptCen, Tria2A).GetDist( dDist2A) ;
double dDist2B = NAN ;
DistPointTriangle( ptCen, Tria2B).GetDist( dDist2B) ;
double dDist2 = min( dDist2A, dDist2B) ;
// prendo la minore delle due distanze
double dDist = min( dDist1, dDist2) ;
// se maggiore della tolleranza, imposto come freccia
if ( isfinite( dDist) && dDist > dLinTol) {
// divido in base alle distanze tra i vertici dei lati
if ( max( dLen0, dLen2) >= max( dLen1, dLen3))
dSagU = dDist ;
else
dSagV = dDist ;
//{ string sLog = " Da triangoli : FrecciaU=" + ToString( dSagU, 3) + " FrecciaV=" + ToString( dSagV, 3) ;
// LOG_DBG_INFO( GetEGkLogger(), sLog.c_str())}
}
}
// su isoparametriche in U e V
if ( dSagU < dLinTol && dSagV < dLinTol) {
// step di verifica in U e in V
int nStepU = ( dLenParU > 1. / m_nDegU ? m_nDegU + 1 : 2) ;
int nStepV = ( dLenParV > 1. / m_nDegV ? m_nDegV + 1 : 2) ;
// verifico lungo curve in U
for ( int i = 0 ; i <= nStepU ; ++ i) {
// parametro U in analisi
double dCoeffU = double( i) / nStepU ;
double dU = ( 1 - dCoeffU) * pcToSplit->GetBottomLeft().x + dCoeffU * pcToSplit->GetTopRight().x ;
// linea tra gli estremi a questa U (ptP00P10 è un punto tra P00 e P10 e così via)
Point3d ptP00P10 ;
GetPoint( dU, pcToSplit->GetBottomLeft().y, ptP00P10) ;
Point3d ptP11P01 ;
GetPoint( dU, pcToSplit->GetTopRight().y, ptP11P01) ;
CurveLine clV ;
clV.Set( ptP00P10, ptP11P01) ;
// verifico alcuni punti intermedi in V
for ( int j = 1 ; j < nStepV ; ++ j) {
// parametro in V
double dCoeffV = double( j) / nStepV ;
double dV = ( 1 - dCoeffV) * pcToSplit->GetBottomLeft().y + dCoeffV * pcToSplit->GetTopRight().y ;
// punto a U, V
Point3d ptPSrf ;
GetPoint( dU, dV, ptPSrf) ;
// distanza del punto dalla precedente linea
DistPointCurve dpc( ptPSrf, clV) ;
double dDist ;
dpc.GetDist( dDist) ;
dSagV = max( dSagV, dDist) ;
}
}
// verifico lungo curve in V
for ( int i = 0 ; i <= nStepV ; ++ i) {
// parametro in V in analisi
double dCoeffV = double( i) / nStepV ;
double dV = ( 1 - dCoeffV) * pcToSplit->GetBottomLeft().y + dCoeffV * pcToSplit->GetTopRight().y ;
// linea tra gli estremi a questa V
Point3d ptP10P11 ;
GetPoint( pcToSplit->GetTopRight().x, dV, ptP10P11) ;
Point3d ptP01P00 ;
GetPoint( pcToSplit->GetBottomLeft().x, dV, ptP01P00) ;
CurveLine clU ;
clU.Set( ptP01P00, ptP10P11) ;
// verifico alcuni punti intermedi in U
for ( int j = 1 ; j < nStepU ; ++ j) {
// parametro U
double dCoeffU = double( j) / nStepU ;
double dU = ( 1 - dCoeffU) * pcToSplit->GetBottomLeft().x + dCoeffU * pcToSplit->GetTopRight().x ;
// punto a U, V
Point3d ptPSrf ;
GetPoint( dU, dV, ptPSrf) ;
// distanza del punto dalla precedente linea
DistPointCurve dpc( ptPSrf, clU) ;
double dDist ;
dpc.GetDist( dDist) ;
dSagU = max( dSagU, dDist) ;
}
}
//{ string sLog = " Da Isoparam : FrecciaU=" + ToString( dSagU, 3) + " FrecciaV=" + ToString( dSagV, 3) ;
// LOG_DBG_INFO( GetEGkLogger(), sLog.c_str())}
}
// per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza
// misura approssimativa della curvatura in una direzione
bool bVert ;
if ( max( dLen0, dLen2) > 5 * max( dLen1, dLen3))
bVert = true ;
else if ( max( dLen1, dLen3) > 5 * max( dLen0, dLen2))
bVert = false ;
else
bVert = ( dSagV <= dSagU) ;
pcToSplit->SetSplitDirVert( bVert) ;
// verifico che la cella sia da splittare e che eventualmente sia abbastanza grande da poterlo fare
double dSideMinVal = 0, dSideMaxVal = 0 ;
double dSideMinVal = 0 ;
double dLengMinVal = 0 ;
if ( bVert) {
if ( dLen0 > EPS_ZERO && dLen2 > EPS_ZERO)
dSideMinVal = min( dLen0, dLen2) ;
else
dSideMinVal = max( dLen0, dLen2) ;
if ( dLen1 > EPS_ZERO && dLen3 > EPS_ZERO)
dLengMinVal = min( dLen1, dLen3) ;
else
dLengMinVal = max( dLen1, dLen3) ;
}
else {
if ( dLen1 > EPS_ZERO && dLen3 > EPS_ZERO)
dSideMinVal = min( dLen1, dLen3) ;
else
dSideMinVal = max( dLen1, dLen3) ;
if ( dLen0 > EPS_ZERO && dLen2 > EPS_ZERO)
dLengMinVal = min( dLen0, dLen2) ;
else
dLengMinVal = max( dLen0, dLen2) ;
}
// calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella
dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ;
// calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella
double dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ;
// se la cella è abbastanza grande da poter essere divisa ancora, calcolo l'errore di approssimazione
// se la cella è abbastanza grande da poter essere divisa ancora, calcolo l'errore di approssimazione
// ( dSideMinVal è zero se entrambi i lati da splittare sono collassati in un punto, controllo dLengMinVal)
bool bSplit = false ;
// dSideMinVal potrebbe essere zero se entrambi i lati che dovrei splittare sono collassati in un punto, ma questo non vuol
// dire che non dovrei eseguire lo split
if ( ! bTwist && (dSideMinVal / 2 >= dSideMin || dSideMinVal < EPS_SMALL) && dSideMaxVal < dSideMax && ( dCurvV > dLinTol || dCurvU > dLinTol)) {
CurveLine cl0010, cl0001, cl1011, cl0111 ;
// V=0
cl0010.Set( ptP00, ptP10) ;
// V=1
cl0111.Set( ptP01, ptP11) ;
Point3d pt0010, pt0111, ptBz0, ptBz1, ptBzV ;
int nFlag ;
CurveLine clV ;
// determino quanti Step fare per ogni direzione parametrica
double dDimU = ( dLen0 >= dLen2 ? dLen0 / m_vDim[0] : dLen2 / m_vDim[2]) ;
dDimU = ( dDimU > 1 ? 1 : dDimU) ;
double dDimV = ( dLen1 >= dLen3 ? dLen1 / m_vDim[1] : dLen3 / m_vDim[3]) ;
dDimV = ( dDimV > 1 ? 1 : dDimV) ;
// numero di Step per campionare la superficie nelle due direzioni parametriche
int nStepsU = int( 51 * dDimU + 5 * ( 1 - dDimU)) ;
int nStepsV = int( 51 * dDimV + 5 * ( 1 - dDimV)) ;
for ( int u = 0 ; u < nStepsU && ! bSplit ; ++ u) {
double dU = double ( u) / double ( nStepsU - 1) ;
double dULoc = ( ( 1 - dU) * pcToSplit->GetBottomLeft().x + dU * pcToSplit->GetTopRight().x) ;
if ( ! GetPoint( dULoc, pcToSplit->GetBottomLeft().y, ptBz0) ||
! GetPoint( dULoc, pcToSplit->GetTopRight().y, ptBz1))
return false ;
// verifico che la cella non sia uno spicchio in verticale, cioè con ptP00 == ptP01 && ptP10 == ptP11
// ( vedi disegno sotto per uno spicchio verticale)
// sennò i punti che cerco sono semplicemente i vertici
if ( cl0010.IsValid()) {
DistPointCurve dpc0010( ptBz0, cl0010) ;
dpc0010.GetMinDistPoint( 0, pt0010, nFlag) ;
}
else
pt0010 = ptP00 ;
if ( cl0111.IsValid()) {
DistPointCurve dpc0111( ptBz1, cl0111) ;
dpc0111.GetMinDistPoint( 0, pt0111, nFlag) ;
}
else
pt0111 = ptP01 ;
// curva a parametro U fisso, con V che scorre
clV.Set( pt0010, pt0111) ;
for ( int v = 0 ; v < nStepsV ; ++ v) {
double dV = double ( v) / double ( nStepsV - 1) ;
double dVLoc = ( ( 1 - dV) * pcToSplit->GetBottomLeft().y + dV * pcToSplit->GetTopRight().y) ;
if ( ! GetPoint( dULoc, dVLoc, ptBzV))
return false ;
DistPointCurve dpc( ptBzV, clV) ;
// distanza di approssimazione locale
double dDist ;
dpc.GetDist( dDist) ;
// se la cella è uno spicchio, quindi con due lati collassati, devo calcolare in modo diverso dist
// ptP00 == ptP01
// / \
// / \
// / \
// ( )
// \ /
// \ /
// \ /
// ptP10 == ptP11
if ( ! clV.IsValid() && AreSamePointApprox( ptP00, ptP01) && AreSamePointApprox( ptP10, ptP11)) {
DistPointCurve dpcSlice( ptBzV, cl0010) ;
dpcSlice.GetDist( dDist) ;
}
if ( dDist > dLinTol) {
bSplit = true ;
break ;
}
}
}
bool bDimOk = ( dSideMinVal / 2 >= dSideMin || ( dSideMinVal < EPS_SMALL && dLengMinVal / 2 >= dSideMin)) ;
if ( dSideMaxVal > dSideMax) {
bSplit = true ;
//LOG_DBG_INFO( GetEGkLogger(), " Split by SideMax")
}
else if ( bTwist ) {
// se la cella è twistata allora l'errore lo calcolo come nelle bilineari
//double dErr = 1. / 4. * ( ( ptP00 - ptP01) + ( ptP11 - ptP10)).Len() ;
double dErr = ( ( ptP00 - ptP01) + ( ptP11 - ptP10)).Len() / 20 ;
if ( dErr > dLinTol)
bSplit = true ;
else if ( dSagV > dLinTol || dSagU > dLinTol) {
bSplit = bDimOk ;
//if ( bSplit)
// LOG_DBG_INFO( GetEGkLogger(), " Split by SagittaUV")
}
if ( bSplit || dSideMaxVal > dSideMax) {
if ( bSplit) {
pcToSplit->SetSplitDirVert( bVert) ;
// effettuo lo split
// effettuo lo split
Split( nCToSplit) ;
// procedo con lo split del Child1
// procedo con lo split del Child1
nCToSplit = pcToSplit->m_nChild1 ;
pcToSplit = &m_mTree[nCToSplit] ;
}
else {
// sono arrivato ad una cella Leaf, quindi salvo la cella
// sono arrivato ad una cella Leaf, quindi salvo la cella
m_vnLeaves.push_back( nCToSplit) ;
pcToSplit->SetProcessed() ;
// risalgo i parent finché non trovo il primo Child2 da processare
// risalgo i parent finché non trovo il primo Child2 da processare
nCToSplit = pcToSplit->m_nParent ;
pcToSplit = &m_mTree[nCToSplit] ;
if ( nCToSplit == -2)
@@ -942,26 +776,26 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax)
pcToSplit = &m_mTree[nCToSplit] ;
}
}
Balance() ; // da implementare quando dividerò ad un parametro a scelta e non a metà // probabilmente mi servirà salvare nella cella il livello di profondità
}
// bilineare
// bilineare
else {
while ( nCToSplit != -2 && pcToSplit->IsProcessed() == false) {
if ( pcToSplit->IsLeaf()) {
// vertici della cella
// vertici della cella
Point3d ptP00, ptP10, ptP11, ptP01 ;
GetPoint(pcToSplit->GetBottomLeft().x, pcToSplit->GetBottomLeft().y, ptP00) ;
GetPoint(pcToSplit->GetTopRight().x, pcToSplit->GetBottomLeft().y, ptP10) ;
GetPoint(pcToSplit->GetTopRight().x, pcToSplit->GetTopRight().y, ptP11) ;
GetPoint(pcToSplit->GetBottomLeft().x, pcToSplit->GetTopRight().y, ptP01) ;
// distanza reale tra i vertici della cella
// distanza reale tra i vertici della cella
double dLen0 = Dist( ptP00, ptP10) ;
double dLen1 = Dist( ptP10, ptP11) ;
double dLen2 = Dist( ptP01, ptP11) ;
double dLen3 = Dist( ptP00, ptP01) ;
bool bVert = false ;
///per capire in quale direzione splittare devo guardare quale coppia di lati opposti è più sghemba
// per capire in quale direzione splittare devo guardare quale coppia di lati opposti è più sghemba
Vector3d vtU0 = ptP01 - ptP00 ;
Vector3d vtU1 = ptP11 - ptP10 ;
double dLU0, dFU0, dTU0, dLU1, dFU1, dTU1 ;
@@ -974,7 +808,7 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax)
vtV0.ToSpherical( &dLV0, &dFV0, &dTV0) ;
vtV1.ToSpherical( &dLV1, &dFV1, &dTV1) ;
double dSkewnessU = abs( dFV1 - dFV0) + abs( dTV1 - dTV0) ;
if( dSkewnessU > dSkewnessV)
if ( dSkewnessU > dSkewnessV)
bVert = false ;
else
bVert = true ;
@@ -1005,25 +839,24 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax)
}
}
}
else if ( ! bIsPlanar){
dErr = 1. / 4. * ( ( ptP00 - ptP01) + ( ptP11 - ptP10)).Len() ;
//int dErr2 = 1. / 4. * ( ( ptP10 - ptP01) + ( ptP11 - ptP00)).Len() ; //correzione che mi verrebbe intuitiva, ma che fa dividere la superficie molto di più ( probabilmente troppo)!! quindi probabilmente sbagliata
else if ( ! bIsPlanar) {
dErr = ( ( ptP00 - ptP01) + ( ptP11 - ptP10)).Len() / 4 ;
}
// se la cella è abbastanza grande da poter essere divisa ancora e devo approssimare meglio, la divido
// se la cella è abbastanza grande da poter essere divisa ancora e devo approssimare meglio, la divido
if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && dErr > dLinTol) {
pcToSplit->SetSplitDirVert( bVert) ;
// effettuo lo split
// effettuo lo split
Split( nCToSplit) ;
// procedo con lo split del Child1
// procedo con lo split del Child1
nCToSplit = pcToSplit->m_nChild1 ;
pcToSplit = &m_mTree[nCToSplit] ;
}
else {
// sono arrivato ad una cella Leaf, quindi salvo la cella
// sono arrivato ad una cella Leaf, quindi salvo la cella
m_vnLeaves.push_back( nCToSplit) ;
pcToSplit->SetProcessed() ;
// risalgo i parent finché non trovo il primo Child2 da processare
// risalgo i parent finché non trovo il primo Child2 da processare
nCToSplit = pcToSplit->m_nParent ;
pcToSplit = &m_mTree[nCToSplit] ;
if ( nCToSplit == -2)
@@ -1050,22 +883,10 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax)
}
}
}
return true ;
}
//----------------------------------------------------------------------------
void
Tree::Balance()
{
//for ( int i : vCheck) {
// // non ancora implementato
// // rendo il tree balanced : ogni foglia deve avere una profondità di +- 1 rispetto alle foglie adiacenti.
//}
// al momento il problema viene bypassato in fase di generazione dei poligoni, considerando per ogni cella, oltre ai propri vertici
// i vertici dei vicini che giacciono sui suoi lati
}
//----------------------------------------------------------------------------
void
Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) const
@@ -1546,8 +1367,8 @@ Tree::GetPolygons( POLYLINEMATRIX& vvPolygons, POLYLINEMATRIX& vvPolygons3d, vec
else {
// vettore in cui salvo il chunk di appartenenza di ogni loop che attraversa la cella
INTVECTOR vnParentChunk ;
// vettore in cui salvo i loop che non appartengono al poligono che sto cotruendo nel ciclo attuale e da cui ripasserò dopo
INTVECTOR vToCheck( (int) m_mTree[nId].m_vInters.size()) ;
// vettore in cui salvo i loop che non appartengono al poligono che sto costruendo nel ciclo attuale e da cui ripasserò dopo
INTVECTOR vToCheck( m_mTree[nId].m_vInters.size()) ;
iota( vToCheck.begin(), vToCheck.end(), 0) ;
// numero di poligoni aggiunti
int nPoly = 0 ;
@@ -1942,23 +1763,20 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& clTrim, bool bRecurs
// se fallisce ritorna un vettore vuoto
// verifico che il punto sia all'interno dello spazio parametrico
// allargo i bordi in modo da tenere anche i punti sul bordo dello spazio parametrico
if ( ptToAssign.x < m_mTree.at( -1).GetBottomLeft().x - EPS_SMALL || ptToAssign.x > m_mTree.at( -1).GetTopRight().x + EPS_SMALL||
ptToAssign.y < m_mTree.at( -1).GetBottomLeft().y - EPS_SMALL || ptToAssign.y > m_mTree.at( -1).GetTopRight().y + EPS_SMALL) {
//nCells.push_back( - 2) ;
if ( ptToAssign.x < m_mTree.at( -1).GetBottomLeft().x - EPS_SMALL ||
ptToAssign.x > m_mTree.at( -1).GetTopRight().x + EPS_SMALL ||
ptToAssign.y < m_mTree.at( -1).GetBottomLeft().y - EPS_SMALL ||
ptToAssign.y > m_mTree.at( -1).GetTopRight().y + EPS_SMALL) {
return nCells ;
}
// se ho diviso preliminarmente le patches e in uno dei due parametri ho un numero dispari di patches devo individuare a mano la cella parent
// in cui individuare la foglia giusta
if ( (m_bSplitPatches && ( m_nSpanU > 1 || m_nSpanV > 1)) || m_bTestMode) {
if ( m_nSpanU > 1 || m_nSpanV > 1) {
INTVECTOR nParents = FindCell( ptToAssign, clTrim, m_vnParents) ;
if ( nParents.empty())
return nCells ;
nId = nParents.back() ;
if ( m_bTestMode ) {
nCells.push_back(nId) ;
return nCells ;
}
}
// individuo la foglia in cui ho lo start del loop
while ( ! m_mTree.at( nId).IsLeaf()) {
@@ -1988,8 +1806,7 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& clTrim, bool bRecurs
Point3d ptBr( m_mTree.at( nId).GetTopRight().x , m_mTree.at( nId).GetBottomLeft().y) ;
Point3d ptTl( m_mTree.at( nId).GetBottomLeft().x , m_mTree.at( nId).GetTopRight().y) ;
if ( abs( ptToAssign.x - ptTl.x) < EPS_SMALL || abs( ptToAssign.x - ptBr.x) < EPS_SMALL ||
abs( ptToAssign.y - ptTl.y) < EPS_SMALL || abs( ptToAssign.y - ptBr.y) < EPS_SMALL)
{
abs( ptToAssign.y - ptTl.y) < EPS_SMALL || abs( ptToAssign.y - ptBr.y) < EPS_SMALL) {
Vector3d vtDir ;
clTrim.GetStartDir( vtDir) ;
// proseguo lungo la curva di trim di EPS_SMALL
@@ -1999,8 +1816,10 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& clTrim, bool bRecurs
Vector3d vtDirDX = vtDir ; vtDirDX.Rotate( Z_AX, 90) ;
ptToAssignPlus = ptToAssignPlus + vtDir * EPS_SMALL ;
// controllo di non essere uscito dallo spazio parametrico ed eventualmente giro a sinistra
if ( ptToAssignPlus.x < m_mTree.at( -1).GetBottomLeft().x - EPS_SMALL || ptToAssignPlus.x > m_mTree.at( -1).GetTopRight().x + EPS_SMALL||
ptToAssignPlus.y < m_mTree.at( -1).GetBottomLeft().y - EPS_SMALL || ptToAssignPlus.y > m_mTree.at( -1).GetTopRight().y + EPS_SMALL) {
if ( ptToAssignPlus.x < m_mTree.at( -1).GetBottomLeft().x - EPS_SMALL ||
ptToAssignPlus.x > m_mTree.at( -1).GetTopRight().x + EPS_SMALL ||
ptToAssignPlus.y < m_mTree.at( -1).GetBottomLeft().y - EPS_SMALL ||
ptToAssignPlus.y > m_mTree.at( -1).GetTopRight().y + EPS_SMALL) {
// rispetto al punto di partenza avanzo lungo la curva di trim
ptToAssignPlus = ptToAssign + vtDir * EPS_SMALL ;
Vector3d vtDirSX = vtDir ; vtDirSX.Rotate( Z_AX, -90) ;
@@ -4340,7 +4159,7 @@ Tree::CreateCellContour( POLYLINEMATRIX& vPolygons)
int nRoot = -1 ;
// preparo tutto per poter chiamare la createCellPolygon
m_vnLeaves.push_back( nRoot) ;
INTVECTOR vToCheck( (int) m_mTree.at(nRoot).m_vInters.size()) ;
INTVECTOR vToCheck( m_mTree.at(nRoot).m_vInters.size()) ;
iota( vToCheck.begin(), vToCheck.end(), 0) ;
int nPoly = 0 ;
INTVECTOR vnParentChunk ;