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:
@@ -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 ;
|
||||
|
||||
Reference in New Issue
Block a user