7cf933ec48
- risolti i problemi di trim su superfici di bezier Problemi noti: - mancano ancora delle celle - si formano delle crack
3141 lines
130 KiB
C++
3141 lines
130 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2023
|
|
//----------------------------------------------------------------------------
|
|
// File : Tree.cpp Data : 21.04.23 Versione :
|
|
// Contenuto : Implementazione della classe Tree.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 21.04.23 DB Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
#include "stdafx.h"
|
|
#include <algorithm>
|
|
#include "Tree.h"
|
|
#include "SurfBezier.h"
|
|
#include "GeoConst.h"
|
|
#include "CurveLine.h"
|
|
#include "CurveComposite.h"
|
|
#include "SurfFlatRegion.h"
|
|
#include "IntersLineLine.h"
|
|
#include "/EgtDev/Include/EGkPolyLine.h"
|
|
#include "/EgtDev/Include/EGkDistPointCurve.h"
|
|
#include "/EgtDev/Include/EGkCurve.h"
|
|
|
|
//----------------------------------------------------------------------------
|
|
Cell::Cell( void)
|
|
: m_nId( -1),m_nTop ( -2), m_nBottom( -2), m_nLeft( -2), m_nRight ( -2), m_nParent( -2), m_nDepth( 0),
|
|
m_nChild1( -2), m_nChild2( -2), m_nFlag( -1), m_nFlag2( 0), m_nRightEdgeIn( -1), m_ptPbl(ORIG), m_ptPtr(), m_bProcessed(false), m_bSplitVert(true)
|
|
{
|
|
Point3d ptTr ( 1, 1) ;
|
|
m_ptPtr = ptTr ;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
Cell::Cell( Point3d& ptBL, Point3d& ptTR)
|
|
: m_nId( -1),m_nTop ( -2), m_nBottom( -2), m_nLeft( -2), m_nRight ( -2), m_nParent( -2), m_nDepth( 0),
|
|
m_nChild1( -2), m_nChild2( -2), m_nFlag( -1), m_nFlag2( 0), m_nRightEdgeIn( -1), m_ptPbl(ptBL), m_ptPtr(ptTR), m_bProcessed(false), m_bSplitVert(true)
|
|
{}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
Cell::~Cell( void)
|
|
{
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
Cell::IsSame( const Cell& cOtherCell) const
|
|
{
|
|
if ( m_nId == cOtherCell.m_nId)
|
|
return true ;
|
|
else
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Cell::IsLeaf ( void) const
|
|
{
|
|
if( m_nChild1 == -2 && m_nChild2 == -2)
|
|
return true ;
|
|
else
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
Tree::Tree( void)
|
|
: m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosed( false)
|
|
{
|
|
Point3d ptBl( 0, 0), ptTr ( 1, 1) ;
|
|
Cell cRoot( ptBl, ptTr) ;
|
|
m_mTree.insert( std::pair< int, Cell>( -1, cRoot)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
Tree::Tree( const SurfBezier* pSrfBz, bool bSplitPatches)
|
|
: m_bBilinear( false), m_bMulti( false), m_bClosed( false)
|
|
{
|
|
SetSurf( pSrfBz, bSplitPatches) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
Tree::~Tree( void)
|
|
{
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches)
|
|
{
|
|
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) ;
|
|
m_bTrimmed = bTrimmed ;
|
|
m_nDegU = nDegU ;
|
|
m_nDegV = nDegV ;
|
|
if ( nDegU == 1 && nDegV == 1)
|
|
m_bBilinear = true ;
|
|
if ( nSpanU * nSpanV != 1)
|
|
m_bMulti = true ;
|
|
// recupero i loop di trim e li divido per chunk
|
|
if ( m_bTrimmed) {
|
|
int nLoop = 0 ;
|
|
INTVECTOR vChunk ;
|
|
// dalla superficie recupero un vettore con i loop di trim
|
|
//
|
|
//PtrOwner<CurveComposite> pLoop( GetBasicCurveComposite( m_pSrfBz->GetLoop( nLoop))) ;
|
|
//while ( ! IsNull( pLoop) && pLoop->IsValid()) {
|
|
// if ( nLoop == 0) {
|
|
// m_vLoop.push_back( Release( pLoop)) ;
|
|
// vChunck.push_back( nLoop) ;
|
|
// ++ nLoop ;
|
|
// }
|
|
// else {
|
|
// // se il loop corrente è contenuto nel precedente e sono girati in verso opposto, allora lo aggiungo allo stesso chunk
|
|
// if ( ) {
|
|
|
|
// }
|
|
// // salvo il precedente chunk e creo un nuovo chunk
|
|
// else {
|
|
// m_vChunk.push_back( vChunk) ;
|
|
// vChunk.clear() ;
|
|
// vChunk.push_back( nLoop) ;
|
|
// }
|
|
// ++ nLoop ;
|
|
// PtrOwner<CurveComposite> pLoop( GetBasicCurveComposite( m_pSrfBz->GetLoop( nLoop))) ;
|
|
// }
|
|
//}
|
|
|
|
// recupero la superficie di trim per avere accesso diretto ai loop e mantenendo le informazioni sui chunk
|
|
|
|
Frame3d frSurf ;
|
|
//const SurfFlatRegion* pTrimReg_( m_pSrfBz->GetTrimRegion()) ;
|
|
//PtrOwner<SurfFlatRegion> pTrimReg( pTrimReg_->Clone()) ;
|
|
PtrOwner<SurfFlatRegion> pTrimReg( m_pSrfBz->GetTrimRegion()->Clone()) ;
|
|
for ( int i = 0 ; i < pTrimReg->GetChunkCount() ; ++ i) {
|
|
PtrOwner<SurfFlatRegion> pChunk( pTrimReg->CloneChunk( i)) ;
|
|
pChunk->Scale( frSurf, 1./ SBZ_TREG_COEFF, 1./ SBZ_TREG_COEFF, 1) ;
|
|
for ( int j = 0 ; j < pChunk->GetLoopCount( 0) ; ++ j) {
|
|
vChunk.push_back( nLoop) ;
|
|
// i chunk della superficie orignale non possono avere dei sub chunk
|
|
PtrOwner<ICurve> pLoop (pChunk->GetLoop(0, j)) ;
|
|
m_vLoop.emplace_back( Release( pLoop )) ;
|
|
m_mChunk[nLoop] = i ;
|
|
++ nLoop ;
|
|
}
|
|
m_vChunk.push_back( vChunk) ;
|
|
vChunk.clear() ;
|
|
}
|
|
}
|
|
// salvo i vertici 3d della cella root
|
|
Point3d ptBottom ( 0, 0) ;
|
|
Point3d ptTop( nSpanU, nSpanV) ;
|
|
Cell cRoot( ptBottom, ptTop) ;
|
|
m_mTree.insert( std::pair< int, Cell>( -1, cRoot)) ;
|
|
Point3d ptP00, ptP10, ptP11, ptP01 ;
|
|
bool bOk = false ;
|
|
PNTVECTOR vVert ;
|
|
ptP00 = m_pSrfBz->GetControlPoint( 0, &bOk);
|
|
vVert.push_back( ptP00) ;
|
|
ptP10 = m_pSrfBz->GetControlPoint( nDegU * nSpanU, &bOk) ;
|
|
vVert.push_back( ptP10) ;
|
|
ptP11 = m_pSrfBz->GetControlPoint( ( nDegU * nSpanU + 1) * ( nDegV * nSpanV + 1) - 1, &bOk) ;
|
|
vVert.push_back( ptP11) ;
|
|
ptP01 = m_pSrfBz->GetControlPoint( ( nDegU * nSpanU + 1 ) * ( nDegV * nSpanV), &bOk) ;
|
|
vVert.push_back( ptP01) ;
|
|
m_mVert.insert( std::pair<int, PNTVECTOR>( -1, vVert)) ;
|
|
// se richiesto divido preliminarmente le patches
|
|
if ( bSplitPatches && ( nSpanU > 1 || nSpanV > 1)) {
|
|
int nId = -1 ;
|
|
for ( int i = 1 ; i < nSpanU ; ++i) {
|
|
m_mTree[nId].SetSplitDirVert( true) ;
|
|
Split( nId, i) ;
|
|
++ nId ;
|
|
++ nId ;
|
|
}
|
|
INTVECTOR vLeaves ;
|
|
GetHeightLeaves( -1, vLeaves) ;
|
|
for ( int nId : vLeaves) {
|
|
for ( int j = nSpanV - 1 ; j > 0 ; --j ) {
|
|
m_mTree[nId].SetSplitDirVert( false) ;
|
|
Split( nId, j) ;
|
|
nId = m_mTree[nId].m_nChild2 ;
|
|
}
|
|
}
|
|
// split preliminari per dividere le patch in modo da triangolarle indipendentemente////////////////////////////////////////////////////////
|
|
}
|
|
// se non ho già splittato le patches, controllo se la superficie è chiusa. In tal caso la splitto sul parametro su cui è chiusa
|
|
else {
|
|
// verifico se la superficie è chiusa ed eventualmente sistemo le adiacenze
|
|
if ( ( AreSamePointApprox( ptP00, ptP01) && AreSamePointApprox( ptP10, ptP11)) ||
|
|
( AreSamePointApprox( ptP00, ptP10) && AreSamePointApprox( ptP01, ptP11))) {
|
|
m_bClosed = true ;
|
|
if ( AreSamePointApprox(ptP00, ptP01)) {
|
|
m_mTree[-1].m_nTop = -1 ;
|
|
m_mTree[-1].m_nBottom = -1 ;
|
|
m_mTree[-1].SetSplitDirVert( false) ;
|
|
Split(-1) ;
|
|
// qui devo fare il controllo capped
|
|
// devo controllare se i punti ai parametri U=0 e U=1 sono tutti coincidenti
|
|
// in caso devo fare uno split nell'altra direzione
|
|
bool bOk = false ;
|
|
bool bCapped0 = true, bCapped1 = true ;
|
|
Point3d ptV0, ptV1 ;
|
|
// controllo se tutti i punti sull'isoparametrica sono uguali
|
|
for ( int i = 1 ; i < nDegV * nSpanV + 1 ; ++ i) {
|
|
ptV0 = m_pSrfBz->GetControlPoint( i * ( nDegU * nSpanU + 1), &bOk) ;
|
|
bCapped0 = bCapped0 && AreSamePointApprox( ptP00, ptV0) ;
|
|
ptV1 = m_pSrfBz->GetControlPoint( ( i + 1) * ( nDegU * nSpanU + 1) - 1, &bOk) ;
|
|
bCapped1 = bCapped1 && AreSamePointApprox( ptP10, ptV1) ;
|
|
}
|
|
if ( bCapped0 && bCapped1) {
|
|
m_mTree[0].SetSplitDirVert( true) ;
|
|
Split( 0) ;
|
|
m_mTree[1].SetSplitDirVert( true) ;
|
|
Split( 1) ;
|
|
}
|
|
}
|
|
if ( AreSamePointApprox(ptP00, ptP10)) {
|
|
if( (int) m_mTree.size() == 1) {
|
|
m_mTree[-1].m_nLeft = -1 ;
|
|
m_mTree[-1].m_nRight = -1 ;
|
|
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
|
|
bool bOk = false ;
|
|
bool bCapped0 = true, bCapped1 = true ;
|
|
Point3d ptU0, ptU1 ;
|
|
// controllo se tutti i punti sull'isoparametrica sono uguali
|
|
for ( int i = 1 ; i < nDegU * nSpanU + 1 ; ++ i) {
|
|
ptU0 = m_pSrfBz->GetControlPoint( i, &bOk) ;
|
|
bCapped0 = bCapped0 && AreSamePointApprox( ptP00, ptU0) ;
|
|
ptU1 = m_pSrfBz->GetControlPoint( i + ( nDegU * nSpanU + 1 ) * ( nDegV * nSpanV), &bOk) ;
|
|
bCapped1 = bCapped1 && AreSamePointApprox( ptP01, ptU1) ;
|
|
}
|
|
if ( bCapped0 && bCapped1) {
|
|
m_mTree[0].SetSplitDirVert( false) ;
|
|
Split( 0) ;
|
|
m_mTree[1].SetSplitDirVert( false) ;
|
|
Split( 1) ;
|
|
}
|
|
}
|
|
else if ( (int) m_mTree.size() > 1 && (int) m_mTree.size() < 4) {
|
|
m_mTree[0].m_nLeft = -1 ;
|
|
m_mTree[0].m_nRight = -1 ;
|
|
m_mTree[1].m_nLeft = -1 ;
|
|
m_mTree[1].m_nRight = -1 ;
|
|
m_mTree[0].SetSplitDirVert( true) ;
|
|
Split( 0) ;
|
|
m_mTree[1].SetSplitDirVert( true) ;
|
|
Split( 1) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// calcolo e salvo la distanza reale tra i vertici della cella root
|
|
double dLen0 = Dist( ptP00, ptP10) ;
|
|
double dLen1 = Dist( ptP10, ptP11) ;
|
|
double dLen2 = Dist( ptP01, ptP11) ;
|
|
double dLen3 = Dist( ptP00, ptP01) ;
|
|
m_vDim.push_back( ( dLen0 != 0 ? dLen0 : 1)) ;
|
|
m_vDim.push_back( ( dLen1 != 0 ? dLen1 : 1)) ;
|
|
m_vDim.push_back( ( dLen2 != 0 ? dLen2 : 1)) ;
|
|
m_vDim.push_back( ( dLen3 != 0 ? dLen3 : 1)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
Tree::Split( int nId, double dSplitValue)
|
|
{
|
|
// controllo che lo split non venga fatto sul lato della cella
|
|
if ( ( m_mTree[nId].IsSplitVert() && dSplitValue > m_mTree[nId].GetBottomLeft().x + EPS_SMALL && dSplitValue < m_mTree[nId].GetTopRight().x - EPS_SMALL) ||
|
|
( ! m_mTree[nId].IsSplitVert() && dSplitValue > m_mTree[nId].GetBottomLeft().y + EPS_SMALL && dSplitValue < m_mTree[nId].GetTopRight().y - EPS_SMALL)) {
|
|
// per lo split a parametro libero dovrò impedire che si facciano split troppo vicini al bordo!!!!!!!!!!!!!!!!!!!
|
|
m_mTree[nId].m_dSplit = dSplitValue ;
|
|
Cell cChild1, cChild2 ;
|
|
cChild1.m_nDepth = m_mTree[nId].m_nDepth + 1 ;
|
|
cChild2.m_nDepth = m_mTree[nId].m_nDepth + 1 ;
|
|
int nNodes = (int) m_mTree.size() ;
|
|
cChild1.m_nId = nNodes - 1 ;
|
|
m_mTree[nId].m_nChild1 = nNodes - 1 ;
|
|
cChild2.m_nId = nNodes ;
|
|
m_mTree[nId].m_nChild2 = nNodes ;
|
|
m_mTree.insert( std::pair<int, Cell>( nNodes - 1, cChild1)) ;
|
|
m_mTree.insert( std::pair<int, Cell>( nNodes, cChild2)) ;
|
|
Point3d ptVert1, ptVert2 ;
|
|
PNTVECTOR vVert ;
|
|
m_mVert.insert( std::pair<int, PNTVECTOR>( nNodes - 1, vVert)) ;
|
|
m_mVert.insert( std::pair<int, PNTVECTOR>( nNodes, vVert)) ;
|
|
if ( ! m_mTree[nId].IsSplitVert())
|
|
{
|
|
// la cella figlio 1 è quella sopra
|
|
Point3d ptBL( m_mTree[nId].GetBottomLeft().x, dSplitValue) ;
|
|
m_mTree[m_mTree[nId].m_nChild1].SetBottomLeft( ptBL) ;
|
|
m_mTree[m_mTree[nId].m_nChild1].SetTopRight( m_mTree[nId].GetTopRight()) ;
|
|
m_mTree[m_mTree[nId].m_nChild1].m_nTop = m_mTree[nId].m_nTop ;
|
|
m_mTree[m_mTree[nId].m_nChild1].m_nBottom = m_mTree[nId].m_nChild2 ;
|
|
m_mTree[m_mTree[nId].m_nChild1].m_nLeft = m_mTree[nId].m_nLeft ;
|
|
m_mTree[m_mTree[nId].m_nChild1].m_nRight = m_mTree[nId].m_nRight ;
|
|
Point3d ptTR( m_mTree[nId].GetTopRight().x, dSplitValue) ;
|
|
m_mTree[m_mTree[nId].m_nChild2].SetBottomLeft( m_mTree[nId].GetBottomLeft()) ;
|
|
m_mTree[m_mTree[nId].m_nChild2].SetTopRight( ptTR) ;
|
|
m_mTree[m_mTree[nId].m_nChild2].m_nTop = m_mTree[nId].m_nChild1 ;
|
|
m_mTree[m_mTree[nId].m_nChild2].m_nBottom = m_mTree[nId].m_nBottom ;
|
|
m_mTree[m_mTree[nId].m_nChild2].m_nLeft = m_mTree[nId].m_nLeft ;
|
|
m_mTree[m_mTree[nId].m_nChild2].m_nRight = m_mTree[nId].m_nRight ;
|
|
// metto i corrispondenti 3d dei punti dello split nella mappa m_mVert
|
|
// per ogni cella i punti devono essere nell'ordine ptP00, ptP10, ptP11, ptP01
|
|
m_pSrfBz->GetPointD1D2( m_mTree[nId].GetBottomLeft().x, dSplitValue, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert1) ;
|
|
m_pSrfBz->GetPointD1D2( m_mTree[nId].GetTopRight().x, dSplitValue, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert2) ;
|
|
m_mVert[nNodes - 1].push_back( ptVert1) ;
|
|
m_mVert[nNodes - 1].push_back( ptVert2) ;
|
|
m_mVert[nNodes - 1].push_back( m_mVert[nId][2]) ;
|
|
m_mVert[nNodes - 1].push_back( m_mVert[nId][3]) ;
|
|
m_mVert[nNodes].push_back( m_mVert[nId][0]) ;
|
|
m_mVert[nNodes].push_back( m_mVert[nId][1]) ;
|
|
m_mVert[nNodes].push_back( ptVert2) ;
|
|
m_mVert[nNodes].push_back( ptVert1) ;
|
|
}
|
|
else {
|
|
// la cella figlio 1 è quella di sinistra
|
|
Point3d ptTR( dSplitValue, m_mTree[nId].GetTopRight().y) ;
|
|
m_mTree[m_mTree[nId].m_nChild1].SetBottomLeft( m_mTree[nId].GetBottomLeft()) ;
|
|
m_mTree[m_mTree[nId].m_nChild1].SetTopRight( ptTR) ;
|
|
m_mTree[m_mTree[nId].m_nChild1].m_nTop = m_mTree[nId].m_nTop ;
|
|
m_mTree[m_mTree[nId].m_nChild1].m_nBottom = m_mTree[nId].m_nBottom ;
|
|
m_mTree[m_mTree[nId].m_nChild1].m_nLeft = m_mTree[nId].m_nLeft ;
|
|
m_mTree[m_mTree[nId].m_nChild1].m_nRight = m_mTree[nId].m_nChild2 ;
|
|
Point3d ptBL( dSplitValue, m_mTree[nId].GetBottomLeft().y) ;
|
|
m_mTree[m_mTree[nId].m_nChild2].SetBottomLeft( ptBL) ;
|
|
m_mTree[m_mTree[nId].m_nChild2].SetTopRight( m_mTree[nId].GetTopRight()) ;
|
|
m_mTree[m_mTree[nId].m_nChild2].m_nTop = m_mTree[nId].m_nTop ;
|
|
m_mTree[m_mTree[nId].m_nChild2].m_nBottom = m_mTree[nId].m_nBottom ;
|
|
m_mTree[m_mTree[nId].m_nChild2].m_nLeft = m_mTree[nId].m_nChild1 ;
|
|
m_mTree[m_mTree[nId].m_nChild2].m_nRight = m_mTree[nId].m_nRight ;
|
|
// metto i corrispondenti 3d dei punti dello split nella mappa m_mVert
|
|
// per ogni cella i punti devono essere nell'ordine ptP00, ptP10, ptP11, ptP01
|
|
m_pSrfBz->GetPointD1D2( dSplitValue, m_mTree[nId].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert2) ;
|
|
m_pSrfBz->GetPointD1D2( dSplitValue, m_mTree[nId].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert1) ;
|
|
m_mVert[nNodes - 1].push_back( m_mVert[nId][0]) ;
|
|
m_mVert[nNodes - 1].push_back( ptVert2) ;
|
|
m_mVert[nNodes - 1].push_back( ptVert1) ;
|
|
m_mVert[nNodes - 1].push_back( m_mVert[nId][3]) ;
|
|
m_mVert[nNodes].push_back( ptVert2) ;
|
|
m_mVert[nNodes].push_back( m_mVert[nId][1]) ;
|
|
m_mVert[nNodes].push_back( m_mVert[nId][2]) ;
|
|
m_mVert[nNodes].push_back( ptVert1) ;
|
|
}
|
|
m_mTree[m_mTree[nId].m_nChild1].SetParent( nId) ;
|
|
m_mTree[m_mTree[nId].m_nChild2].SetParent( nId) ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
Tree::Split( int nId)
|
|
{
|
|
double dValue ;
|
|
if ( m_mTree[nId].IsSplitVert())
|
|
dValue = ( m_mTree[nId].GetBottomLeft().x + m_mTree[nId].GetTopRight().x) / 2 ;
|
|
else
|
|
dValue = ( m_mTree[nId].GetBottomLeft().y + m_mTree[nId].GetTopRight().y) / 2 ;
|
|
Split( nId, dValue) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Tree::BuildTree_test( double dLinTol_, double dSideMin, double dSideMax)
|
|
{
|
|
//int nCToSplit = -1 ;
|
|
//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) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax)
|
|
{
|
|
// suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri
|
|
int nCToSplit = -1 ;
|
|
double dLinTol = 0.2 ;
|
|
//double dSideMin = 1 ;
|
|
if ( ! m_bTrimmed || m_bTrimmed) {
|
|
if ( ! m_bBilinear) {
|
|
while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) {
|
|
// controllo che la cella non sia già stata preliminarmente splittata
|
|
if ( m_mTree[nCToSplit].IsLeaf()) {
|
|
// calcolo in quale direzione ho più curvatura
|
|
// ptP00P10 è un punto tra P00 e P10
|
|
double dCurvU = 0, dCurvV = 0 ;
|
|
double dLenParU = m_mTree[nCToSplit].GetTopRight().x - m_mTree[nCToSplit].GetBottomLeft().x ;
|
|
double dLenParV = m_mTree[nCToSplit].GetTopRight().y - m_mTree[nCToSplit].GetBottomLeft().y ;
|
|
if ( dLenParU <= 1. / m_nDegV || dLenParV <= 1. / m_nDegU) {
|
|
double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ;
|
|
double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ;
|
|
double dULoc = 0.5, dVLoc = 0.5 ;
|
|
Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00 ;
|
|
m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ;
|
|
m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ;
|
|
m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ;
|
|
m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ;
|
|
m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, 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 ;
|
|
for ( double k = dStep ; k < 1 ; k = k + dStep) {
|
|
double dU = k * m_mTree[nCToSplit].GetTopRight().x + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().x ;
|
|
double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ;
|
|
m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ;
|
|
if ( k == 0.5)
|
|
ptPSrfMid = ptPSrf ;
|
|
m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ;
|
|
m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ;
|
|
CurveLine clV ;
|
|
clV.Set( ptP00P10, ptP11P01) ;
|
|
DistPointCurve dpc( ptPSrf, clV) ;
|
|
double dDist ;
|
|
dpc.GetDist( dDist) ;
|
|
dCurvV = std::max( dCurvV, dDist) ;
|
|
}
|
|
dStep = 1. / m_nDegV ;
|
|
for ( double k = dStep ; k < 1 ; k = k + dStep) {
|
|
double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ;
|
|
double dV = k * m_mTree[nCToSplit].GetTopRight().y + ( 1 - k) * m_mTree[nCToSplit].GetBottomLeft().y ;
|
|
if ( k == 0.5)
|
|
ptPSrf = ptPSrfMid ;
|
|
else
|
|
m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ;
|
|
m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ;
|
|
m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ;
|
|
CurveLine clU ;
|
|
clU.Set( ptP01P00, ptP10P11) ;
|
|
DistPointCurve dpc( ptPSrf, clU) ;
|
|
double dDist ;
|
|
dpc.GetDist( dDist) ;
|
|
dCurvU = std::max( dCurvU, dDist) ;
|
|
}
|
|
}
|
|
|
|
// 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 ;
|
|
}
|
|
m_mTree[nCToSplit].SetSplitDirVert( bVert) ;
|
|
Point3d ptP00, ptP10, ptP11, ptP01 ;
|
|
// distanza reale tra i vertici della cella
|
|
ptP00 = m_mVert[nCToSplit][0] ;
|
|
ptP10 = m_mVert[nCToSplit][1] ;
|
|
ptP11 = m_mVert[nCToSplit][2] ;
|
|
ptP01 = m_mVert[nCToSplit][3] ;
|
|
double dLen0 = Dist( ptP00, ptP10) ;
|
|
double dLen1 = Dist( ptP10, ptP11) ;
|
|
double dLen2 = Dist( ptP01, ptP11) ;
|
|
double dLen3 = Dist( ptP00, ptP01) ;
|
|
// verifico che la cella sia da splittare e che eventualmente sia abbastanza grande da poterlo fare
|
|
double dSideMinVal = 0, dSideMaxVal = 0 ;
|
|
if ( bVert) {
|
|
if ( dLen0 != 0 && dLen2 != 0)
|
|
dSideMinVal = std::max( dLen0, dLen2) ;
|
|
else
|
|
dSideMinVal = std::max( dLen0, dLen2) ;
|
|
}
|
|
else {
|
|
if ( dLen1 != 0 && dLen3 != 0)
|
|
dSideMinVal = std::max( dLen1, dLen3) ;
|
|
else
|
|
dSideMinVal = std::max( dLen1, dLen3) ;
|
|
}
|
|
// calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella
|
|
dSideMaxVal = std::max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ;
|
|
|
|
// se la cella è abbastanza grande da poter essere divisa ancora, calcolo l'errore di approssimazione
|
|
bool bSplit = false ;
|
|
if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && ( dCurvV > dLinTol || dCurvU > dLinTol)) {
|
|
CurveLine cl0010, cl0001, cl1011, cl0111 ;
|
|
// U=0
|
|
cl0010.Set( ptP00, ptP10) ;
|
|
// U=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) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x ;
|
|
if ( ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz0) ||
|
|
! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz1))
|
|
return false ;
|
|
DistPointCurve dpc0010( ptBz0, cl0010) ;
|
|
DistPointCurve dpc0111( ptBz1, cl0111) ;
|
|
dpc0010.GetMinDistPoint( 0, pt0010, nFlag) ;
|
|
dpc0111.GetMinDistPoint( 0, pt0111, nFlag) ;
|
|
clV.Set( pt0010, pt0111) ;
|
|
for ( int v = 0 ; v < nStepsV ; ++ v) {
|
|
double dV = double ( v) / double ( nStepsV - 1) ;
|
|
double dVLoc = ( 1 - dV) * m_mTree[nCToSplit].GetBottomLeft().y + dV * m_mTree[nCToSplit].GetTopRight().y ;
|
|
if ( ! m_pSrfBz->GetPointD1D2( dULoc, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBzV))
|
|
return false ;
|
|
DistPointCurve dpc( ptBzV, clV) ;
|
|
// distanza di approssimazione locale
|
|
double dDist ;
|
|
dpc.GetDist( dDist) ;
|
|
if ( dDist > dLinTol) {
|
|
bSplit = true ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( bSplit || dSideMaxVal > dSideMax) {
|
|
m_mTree[nCToSplit].SetSplitDirVert( bVert) ;
|
|
// effettuo lo split
|
|
Split( nCToSplit) ;
|
|
|
|
// procedo con lo split del Child1
|
|
nCToSplit = m_mTree[nCToSplit].m_nChild1 ;
|
|
}
|
|
else {
|
|
// sono arrivato ad una cella Leaf, quindi salvo la cella
|
|
m_vnLeaves.push_back( nCToSplit) ;
|
|
m_mTree[nCToSplit].SetProcessed() ;
|
|
// risalgo i parent finché non trovo il primo Child2 da processare
|
|
nCToSplit = m_mTree[nCToSplit].m_nParent ;
|
|
if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed())
|
|
m_mTree[nCToSplit].SetProcessed() ;
|
|
while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) {
|
|
if ( m_mTree[nCToSplit].m_nParent != -2)
|
|
nCToSplit = m_mTree[nCToSplit].m_nParent ;
|
|
if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed())
|
|
m_mTree[nCToSplit].SetProcessed() ;
|
|
if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed())
|
|
break ;
|
|
}
|
|
nCToSplit = m_mTree[nCToSplit].m_nChild2 ;
|
|
}
|
|
}
|
|
else {
|
|
nCToSplit = m_mTree[nCToSplit].m_nChild1 ;
|
|
}
|
|
}
|
|
Balance() ; // da implementare quando dividerò ad un parametro a scelta e non a metà
|
|
}
|
|
// bilineare
|
|
else {
|
|
while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) {
|
|
if ( m_mTree[nCToSplit].IsLeaf()) {
|
|
// vertici della cella
|
|
Point3d ptP00, ptP10, ptP11, ptP01 ;
|
|
ptP00 = m_mVert[nCToSplit][0] ;
|
|
ptP10 = m_mVert[nCToSplit][1] ;
|
|
ptP11 = m_mVert[nCToSplit][2] ;
|
|
ptP01 = m_mVert[nCToSplit][3] ;
|
|
// 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 ;
|
|
// calcolo in quale direzione è meglio dividere in base allo stretch
|
|
Point3d ptPSrfU, ptPSrfV ;
|
|
double dU = 0, dV = 0 ;
|
|
double dDistU = 0, dDistV = 0 ;
|
|
PNTVECTOR vPtU, vPtV ;
|
|
if ( ! m_bMulti) {
|
|
if ( std::max(dLen0, dLen2) > std::max(dLen1, dLen3)) {
|
|
bVert = true ;
|
|
}
|
|
else {
|
|
bVert = false ;
|
|
}
|
|
}
|
|
else {
|
|
for ( double i = 0.25 ; i < 1 ; i = i + 0.25 ) {
|
|
dU = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().x + i * m_mTree[nCToSplit].GetTopRight().x ;
|
|
dV = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().y + i * m_mTree[nCToSplit].GetTopRight().y ;
|
|
double dVLoc = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 ;
|
|
double dULoc = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 ;
|
|
m_pSrfBz->GetPointD1D2( dU, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfU) ;
|
|
m_pSrfBz->GetPointD1D2( dULoc, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfV) ;
|
|
vPtU.push_back( ptPSrfU) ;
|
|
vPtV.push_back( ptPSrfV) ;
|
|
}
|
|
// devo guardare se i tre punti in vPtU e vPtV sono allineati
|
|
CurveLine clU, clV;
|
|
clU.Set(vPtU[0], vPtU[1]) ;
|
|
clV.Set(vPtV[0], vPtV[1]) ;
|
|
DistPointCurve dpcU( vPtU[2], clU, false) ;
|
|
DistPointCurve dpcV( vPtV[2], clV, false) ;
|
|
dpcU.GetDist( dDistU) ;
|
|
dpcV.GetDist( dDistV) ;
|
|
if ( dDistU > dDistV) {
|
|
bVert = true ;
|
|
}
|
|
else {
|
|
bVert = false ;
|
|
}
|
|
}
|
|
|
|
// verifico che la cella sia abbastanza grande da poter essere splittata
|
|
double dSideMinVal = 0, dSideMaxVal = 0 ;
|
|
if ( bVert) {
|
|
if ( dLen0 != 0 && dLen2 != 0)
|
|
dSideMinVal = std::max( dLen0, dLen2) ;
|
|
else
|
|
dSideMinVal = std::max( dLen0, dLen2) ;
|
|
}
|
|
else {
|
|
if ( dLen1 != 0 && dLen3 != 0)
|
|
dSideMinVal = std::max( dLen1, dLen3) ;
|
|
else
|
|
dSideMinVal = std::max( dLen1, dLen3) ;
|
|
}
|
|
// calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella
|
|
dSideMaxVal = std::max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ;
|
|
|
|
|
|
double dErr = 0 ;
|
|
if ( m_bMulti) {
|
|
Point3d ptPSrf ;
|
|
Plane3d plAppr ;
|
|
if ( ! AreSamePointApprox( ptP00, ptP10) && ! AreSamePointApprox( ptP00, ptP01))
|
|
plAppr.Set( ptP00, ( ptP00 - ptP01) ^ ( ptP00 - ptP10)) ;
|
|
else if ( AreSamePointApprox( ptP00, ptP10)) {
|
|
plAppr.Set( ptP01, ( ptP00 - ptP01) ^ ( ptP01 - ptP11)) ;
|
|
}
|
|
else if ( AreSamePointApprox( ptP00, ptP01)) {
|
|
plAppr.Set( ptP10, ( ptP10 - ptP11) ^ ( ptP00 - ptP10)) ;
|
|
}
|
|
for ( double i = 0.25 ; i < 1 ; i = i + 0.25) {
|
|
for ( double j = 0.25 ; j < 1 ; j = j + 0.25) {
|
|
double dU = ( 1 - i) * m_mTree[nCToSplit].GetTopRight().x + i * m_mTree[nCToSplit].GetBottomLeft().x ;
|
|
double dV = ( 1 - j) * m_mTree[nCToSplit].GetTopRight().y + j * m_mTree[nCToSplit].GetBottomLeft().y ;
|
|
m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ;
|
|
dErr = std::max( abs( DistPointPlane( ptPSrf, plAppr)), dErr) ;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
dErr = 1. / 4. * ( (ptP00 - ptP01) + (ptP11 - ptP10)).Len() ;
|
|
}
|
|
// se la cella è abbastanza grande da poter essere divisa ancora e devo approssimare meglio, la divido
|
|
if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && dErr > dLinTol) {
|
|
m_mTree[nCToSplit].SetSplitDirVert( bVert) ;
|
|
// effettuo lo split
|
|
Split( nCToSplit) ;
|
|
|
|
// procedo con lo split del Child1
|
|
nCToSplit = m_mTree[nCToSplit].m_nChild1 ;
|
|
}
|
|
else {
|
|
// sono arrivato ad una cella Leaf, quindi salvo la cella
|
|
m_vnLeaves.push_back( nCToSplit) ;
|
|
m_mTree[nCToSplit].SetProcessed() ;
|
|
// risalgo i parent finché non trovo il primo Child2 da processare
|
|
nCToSplit = m_mTree[nCToSplit].m_nParent ;
|
|
if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed())
|
|
m_mTree[nCToSplit].SetProcessed() ;
|
|
while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) {
|
|
if ( m_mTree[nCToSplit].m_nParent != -2)
|
|
nCToSplit = m_mTree[nCToSplit].m_nParent ;
|
|
if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed())
|
|
m_mTree[nCToSplit].SetProcessed() ;
|
|
if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed())
|
|
break ;
|
|
}
|
|
nCToSplit = m_mTree[nCToSplit].m_nChild2 ;
|
|
}
|
|
}
|
|
else {
|
|
nCToSplit = m_mTree[nCToSplit].m_nChild1 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// NON IMPLEMENTATO
|
|
// se la superficie è trimmata creo l'albero solo all'interno dei bbox delle curve di trim ( se ho solo trim CW allora tengo il bordo)
|
|
else {
|
|
SurfFlatRegion sfrTrimReg ;
|
|
}
|
|
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
|
|
{
|
|
if ( (int) vTopNeighs.size() == 0) {
|
|
if ( m_mTree.at(nId).m_nTop == -2)
|
|
return ;
|
|
if ( m_mTree.at(m_mTree.at(nId).m_nTop).IsLeaf())
|
|
vTopNeighs.push_back( m_mTree.at(nId).m_nTop) ;
|
|
else {
|
|
if ( m_mTree.at(m_mTree.at(nId).m_nTop).IsSplitVert()) {
|
|
// se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima
|
|
if ( m_mTree.at(m_mTree.at(nId).m_nTop).GetTopRight().x - m_mTree.at(m_mTree.at(nId).m_nTop).GetBottomLeft().x <=
|
|
m_mTree.at(nId).GetTopRight().x - m_mTree.at(nId).GetBottomLeft().x) {
|
|
vTopNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild1) ;
|
|
vTopNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild2) ;
|
|
}
|
|
// altrimenti solo uno dei figli lo sarà
|
|
else{
|
|
if ( m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild1).GetTopRight().x <= m_mTree.at(nId).GetBottomLeft().x ||
|
|
m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild1).GetBottomLeft().x >= m_mTree.at(nId).GetTopRight().x )
|
|
vTopNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild2) ;
|
|
else
|
|
vTopNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild1) ;
|
|
}
|
|
}
|
|
else {
|
|
vTopNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nTop).m_nChild2) ;
|
|
}
|
|
}
|
|
bool bAllLeaves = true ;
|
|
for ( int i : vTopNeighs ) {
|
|
if ( ! m_mTree.at(i).IsLeaf())
|
|
bAllLeaves = false ;
|
|
}
|
|
if ( ! bAllLeaves )
|
|
// almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child
|
|
GetTopNeigh( nId, vTopNeighs) ;
|
|
}
|
|
else {
|
|
for ( int j = 0 ; j != (int) vTopNeighs.size() ; ++ j) {
|
|
int i = vTopNeighs.at(j) ;
|
|
if ( m_mTree.at(i).IsLeaf())
|
|
continue;
|
|
else {
|
|
// se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child
|
|
vTopNeighs.erase( remove( vTopNeighs.begin(),vTopNeighs.end(),i)) ;
|
|
-- j ;
|
|
if ( m_mTree.at(i).IsSplitVert() ) {
|
|
// se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima
|
|
if ( m_mTree.at(i).GetTopRight().x - m_mTree.at(i).GetBottomLeft().x <=
|
|
m_mTree.at(nId).GetTopRight().x - m_mTree.at(nId).GetBottomLeft().x) {
|
|
vTopNeighs.push_back( m_mTree.at(i).m_nChild1) ;
|
|
vTopNeighs.push_back( m_mTree.at(i).m_nChild2) ;
|
|
}
|
|
// altrimenti solo uno dei figli lo sarà
|
|
else {
|
|
if ( m_mTree.at(m_mTree.at(i).m_nChild1).GetTopRight().x <= m_mTree.at(nId).GetBottomLeft().x ||
|
|
m_mTree.at(m_mTree.at(i).m_nChild1).GetBottomLeft().x >= m_mTree.at(nId).GetTopRight().x )
|
|
vTopNeighs.push_back( m_mTree.at(i).m_nChild2) ;
|
|
else
|
|
vTopNeighs.push_back( m_mTree.at(i).m_nChild1) ;
|
|
}
|
|
}
|
|
else {
|
|
vTopNeighs.push_back( m_mTree.at(i).m_nChild2) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
std::vector<Cell> vCells ;
|
|
for ( int k : vTopNeighs)
|
|
vCells.push_back( m_mTree.at(k)) ;
|
|
std::sort( vCells.begin(), vCells.end(), Cell::minorX) ;
|
|
vTopNeighs.clear() ;
|
|
for ( Cell c : vCells)
|
|
vTopNeighs.push_back( c.m_nId) ;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) const
|
|
{
|
|
if ( (int) vBottomNeighs.size() == 0) {
|
|
if ( m_mTree.at(nId).m_nBottom == -2)
|
|
return ;
|
|
if ( m_mTree.at(m_mTree.at(nId).m_nBottom).IsLeaf())
|
|
vBottomNeighs.push_back( m_mTree.at(nId).m_nBottom) ;
|
|
else {
|
|
if ( m_mTree.at(m_mTree.at(nId).m_nBottom).IsSplitVert()) {
|
|
// se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima
|
|
if ( m_mTree.at(m_mTree.at(nId).m_nBottom).GetTopRight().x - m_mTree.at(m_mTree.at(nId).m_nBottom).GetBottomLeft().x <=
|
|
m_mTree.at(nId).GetTopRight().x - m_mTree.at(nId).GetBottomLeft().x) {
|
|
vBottomNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild1) ;
|
|
vBottomNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild2) ;
|
|
}
|
|
// altrimenti solo uno dei figli lo sarà
|
|
else{
|
|
if ( m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild1).GetTopRight().x <= m_mTree.at(nId).GetBottomLeft().x ||
|
|
m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild1).GetBottomLeft().x >= m_mTree.at(nId).GetTopRight().x )
|
|
vBottomNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild2) ;
|
|
else
|
|
vBottomNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild1) ;
|
|
}
|
|
}
|
|
else {
|
|
vBottomNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nBottom).m_nChild1) ;
|
|
}
|
|
}
|
|
bool bAllLeaves = true ;
|
|
for ( int i : vBottomNeighs) {
|
|
if ( ! m_mTree.at(i).IsLeaf())
|
|
bAllLeaves = false ;
|
|
}
|
|
if ( ! bAllLeaves )
|
|
// almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child
|
|
GetBottomNeigh( nId, vBottomNeighs) ;
|
|
}
|
|
else {
|
|
for ( int j = 0 ; j != (int) vBottomNeighs.size() ; ++ j) {
|
|
int i = vBottomNeighs.at(j) ;
|
|
if ( m_mTree.at(i).IsLeaf())
|
|
continue;
|
|
else {
|
|
// se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child
|
|
vBottomNeighs.erase( remove( vBottomNeighs.begin(),vBottomNeighs.end(),i)) ;
|
|
-- j ;
|
|
if ( m_mTree.at(i).IsSplitVert()) {
|
|
// se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima
|
|
if ( m_mTree.at(i).GetTopRight().x - m_mTree.at(i).GetBottomLeft().x <=
|
|
m_mTree.at(nId).GetTopRight().x - m_mTree.at(nId).GetBottomLeft().x) {
|
|
vBottomNeighs.push_back( m_mTree.at(i).m_nChild1) ;
|
|
vBottomNeighs.push_back( m_mTree.at(i).m_nChild2) ;
|
|
}
|
|
// altrimenti solo uno dei figli lo sarà
|
|
else {
|
|
if ( m_mTree.at(m_mTree.at(i).m_nChild1).GetTopRight().x <= m_mTree.at(nId).GetBottomLeft().x ||
|
|
m_mTree.at(m_mTree.at(i).m_nChild1).GetBottomLeft().x >= m_mTree.at(nId).GetTopRight().x)
|
|
vBottomNeighs.push_back( m_mTree.at(i).m_nChild2) ;
|
|
else
|
|
vBottomNeighs.push_back( m_mTree.at(i).m_nChild1) ;
|
|
}
|
|
}
|
|
else {
|
|
vBottomNeighs.push_back( m_mTree.at(i).m_nChild1) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
std::vector<Cell> vCells ;
|
|
for ( int k : vBottomNeighs)
|
|
vCells.push_back( m_mTree.at(k)) ;
|
|
std::sort( vCells.begin(), vCells.end(), Cell::minorX) ;
|
|
vBottomNeighs.clear() ;
|
|
for ( Cell c : vCells)
|
|
vBottomNeighs.push_back( c.m_nId) ;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) const
|
|
{
|
|
if ( (int) vLeftNeighs.size() == 0) {
|
|
if ( m_mTree.at(nId).m_nLeft == -2)
|
|
return ;
|
|
if ( m_mTree.at(m_mTree.at(nId).m_nLeft).IsLeaf())
|
|
vLeftNeighs.push_back( m_mTree.at(nId).m_nLeft) ;
|
|
else {
|
|
if ( ! m_mTree.at(m_mTree.at(nId).m_nLeft).IsSplitVert()) {
|
|
// se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima
|
|
if ( m_mTree.at(m_mTree.at(nId).m_nLeft).GetTopRight().y - m_mTree.at(m_mTree.at(nId).m_nLeft).GetBottomLeft().y <=
|
|
m_mTree.at(nId).GetTopRight().y - m_mTree.at(nId).GetBottomLeft().y) {
|
|
vLeftNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild1) ;
|
|
vLeftNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild2) ;
|
|
}
|
|
// altrimenti solo uno dei figli lo sarà
|
|
else{
|
|
if ( m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild1).GetTopRight().y <= m_mTree.at(nId).GetBottomLeft().y ||
|
|
m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild1).GetBottomLeft().y >= m_mTree.at(nId).GetTopRight().y)
|
|
vLeftNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild2) ;
|
|
else
|
|
vLeftNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild1) ;
|
|
}
|
|
}
|
|
else {
|
|
vLeftNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nLeft).m_nChild2) ;
|
|
}
|
|
}
|
|
bool bAllLeaves = true ;
|
|
for ( int i : vLeftNeighs) {
|
|
if ( ! m_mTree.at(i).IsLeaf())
|
|
bAllLeaves = false ;
|
|
}
|
|
if ( ! bAllLeaves )
|
|
// almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child
|
|
GetLeftNeigh( nId, vLeftNeighs) ;
|
|
}
|
|
else {
|
|
for ( int j = 0 ; j != (int) vLeftNeighs.size() ; ++ j) {
|
|
int i = vLeftNeighs.at(j) ;
|
|
if ( m_mTree.at(i).IsLeaf())
|
|
continue;
|
|
else {
|
|
// se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child
|
|
vLeftNeighs.erase( remove( vLeftNeighs.begin(),vLeftNeighs.end(),i)) ;
|
|
-- j ;
|
|
if ( ! m_mTree.at(i).IsSplitVert()) {
|
|
// se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima
|
|
if ( m_mTree.at(i).GetTopRight().y - m_mTree.at(i).GetBottomLeft().y <=
|
|
m_mTree.at(nId).GetTopRight().y - m_mTree.at(nId).GetBottomLeft().y) {
|
|
vLeftNeighs.push_back( m_mTree.at(i).m_nChild1) ;
|
|
vLeftNeighs.push_back( m_mTree.at(i).m_nChild2) ;
|
|
}
|
|
// altrimenti solo uno dei figli lo sarà
|
|
else {
|
|
if ( m_mTree.at(m_mTree.at(i).m_nChild1).GetTopRight().y <= m_mTree.at(nId).GetBottomLeft().y ||
|
|
m_mTree.at(m_mTree.at(i).m_nChild1).GetBottomLeft().y >= m_mTree.at(nId).GetTopRight().y)
|
|
vLeftNeighs.push_back( m_mTree.at(i).m_nChild2) ;
|
|
else
|
|
vLeftNeighs.push_back( m_mTree.at(i).m_nChild1) ;
|
|
}
|
|
}
|
|
else {
|
|
vLeftNeighs.push_back( m_mTree.at(i).m_nChild2) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
std::vector<Cell> vCells ;
|
|
for ( int k : vLeftNeighs)
|
|
vCells.push_back( m_mTree.at(k)) ;
|
|
std::sort( vCells.begin(), vCells.end(), Cell::minorY) ;
|
|
vLeftNeighs.clear() ;
|
|
for ( Cell c : vCells)
|
|
vLeftNeighs.push_back( c.m_nId) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) const
|
|
{
|
|
if ( (int) vRightNeighs.size() == 0) {
|
|
if ( m_mTree.at(nId).m_nRight == -2)
|
|
return ;
|
|
if ( m_mTree.at(m_mTree.at(nId).m_nRight).IsLeaf())
|
|
vRightNeighs.push_back( m_mTree.at(nId).m_nRight) ;
|
|
else {
|
|
if ( ! m_mTree.at(m_mTree.at(nId).m_nRight).IsSplitVert()) {
|
|
// se la cella vicina è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima
|
|
if ( m_mTree.at(m_mTree.at(nId).m_nRight).GetTopRight().y - m_mTree.at(m_mTree.at(nId).m_nRight).GetBottomLeft().y <=
|
|
m_mTree.at(nId).GetTopRight().y - m_mTree.at(nId).GetBottomLeft().y) {
|
|
vRightNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild1) ;
|
|
vRightNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild2) ;
|
|
}
|
|
// altrimenti solo uno dei figli lo sarà
|
|
else{
|
|
if ( m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild1).GetTopRight().y <= m_mTree.at(nId).GetBottomLeft().y ||
|
|
m_mTree.at(m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild1).GetBottomLeft().y >= m_mTree.at(nId).GetTopRight().y)
|
|
vRightNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild2) ;
|
|
else
|
|
vRightNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild1) ;
|
|
}
|
|
}
|
|
else {
|
|
vRightNeighs.push_back( m_mTree.at(m_mTree.at(nId).m_nRight).m_nChild1) ;
|
|
}
|
|
}
|
|
bool bAllLeaves = true ;
|
|
for ( int i : vRightNeighs) {
|
|
if ( ! m_mTree.at(i).IsLeaf())
|
|
bAllLeaves = false ;
|
|
}
|
|
if ( ! bAllLeaves )
|
|
// almeno una cella tra i vicini trovati non è leaf quindi devo richiamare ricorsivamente questa funzione per trovare i suoi child
|
|
GetRightNeigh( nId, vRightNeighs) ;
|
|
}
|
|
else {
|
|
for ( int j = 0 ; j != (int) vRightNeighs.size() ; ++ j) {
|
|
int i = vRightNeighs.at(j) ;
|
|
if ( m_mTree.at(i).IsLeaf())
|
|
continue;
|
|
else {
|
|
// se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child
|
|
vRightNeighs.erase( remove( vRightNeighs.begin(),vRightNeighs.end(), i)) ;
|
|
-- j ;
|
|
if ( ! m_mTree.at(i).IsSplitVert()) {
|
|
// se la cella è più piccola della cella indagata, allora entrambi i figli saranno vicini di quest'ultima
|
|
if ( m_mTree.at(i).GetTopRight().y - m_mTree.at(i).GetBottomLeft().y <=
|
|
m_mTree.at(nId).GetTopRight().y - m_mTree.at(nId).GetBottomLeft().y) {
|
|
vRightNeighs.push_back( m_mTree.at(i).m_nChild1) ;
|
|
vRightNeighs.push_back( m_mTree.at(i).m_nChild2) ;
|
|
}
|
|
// altrimenti solo uno dei figli lo sarà
|
|
else {
|
|
if ( m_mTree.at(m_mTree.at(i).m_nChild1).GetTopRight().y <= m_mTree.at(nId).GetBottomLeft().y ||
|
|
m_mTree.at(m_mTree.at(i).m_nChild1).GetBottomLeft().y >= m_mTree.at(nId).GetTopRight().y)
|
|
vRightNeighs.push_back( m_mTree.at(i).m_nChild2) ;
|
|
else
|
|
vRightNeighs.push_back( m_mTree.at(i).m_nChild1) ;
|
|
}
|
|
}
|
|
else {
|
|
vRightNeighs.push_back( m_mTree.at(i).m_nChild1) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
std::vector<Cell> vCells ;
|
|
for ( int k : vRightNeighs)
|
|
vCells.push_back( m_mTree.at(k)) ;
|
|
std::sort( vCells.begin(), vCells.end(), Cell::minorY) ;
|
|
vRightNeighs.clear() ;
|
|
for ( Cell c : vCells)
|
|
vRightNeighs.push_back( c.m_nId) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
Tree::GetRootNeigh( int nEdge, INTVECTOR& vNeigh)
|
|
{
|
|
int nId = -1 ;
|
|
bool bMod = false ;
|
|
if ( nEdge == 0 ) {
|
|
if ( m_mTree[nId].m_nBottom == -2 ) {
|
|
m_mTree[nId].m_nBottom = -1 ;
|
|
bMod = true;
|
|
}
|
|
GetBottomNeigh( nId, vNeigh) ;
|
|
if ( bMod)
|
|
m_mTree[nId].m_nBottom = -2 ;
|
|
}
|
|
else if ( nEdge == 1 ) {
|
|
if ( m_mTree[nId].m_nRight == -2 ) {
|
|
m_mTree[nId].m_nRight = -1 ;
|
|
bMod = true;
|
|
}
|
|
GetRightNeigh( nId, vNeigh) ;
|
|
if ( bMod)
|
|
m_mTree[nId].m_nRight = -2 ;
|
|
}
|
|
else if ( nEdge == 2 ) {
|
|
if ( m_mTree[nId].m_nTop == -2 ) {
|
|
m_mTree[nId].m_nTop = -1 ;
|
|
bMod = true;
|
|
}
|
|
GetTopNeigh( nId, vNeigh) ;
|
|
if ( bMod)
|
|
m_mTree[nId].m_nTop = -2 ;
|
|
}
|
|
else if ( nEdge == 3 ) {
|
|
if ( m_mTree[nId].m_nLeft == -2 ) {
|
|
m_mTree[nId].m_nLeft = -1 ;
|
|
bMod = true;
|
|
}
|
|
GetLeftNeigh( nId, vNeigh) ;
|
|
if ( bMod)
|
|
m_mTree[nId].m_nLeft = -2 ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int
|
|
Tree::GetHeightLeaves( int nId, INTVECTOR& vnLeaves, int d) const
|
|
{
|
|
if ( nId == -1 && m_mTree.at(-1).IsLeaf()) {
|
|
vnLeaves.push_back( -1) ;
|
|
return 0 ;
|
|
}
|
|
else {
|
|
if ( (int) vnLeaves.size() == 0) {
|
|
if ( m_mTree.at(nId).IsLeaf())
|
|
return d ;
|
|
else {
|
|
vnLeaves.push_back( m_mTree.at(nId).m_nChild1) ;
|
|
vnLeaves.push_back( m_mTree.at(nId).m_nChild2) ;
|
|
if ( ! m_mTree.at(m_mTree.at(nId).m_nChild1).IsLeaf() || ! m_mTree.at(m_mTree.at(nId).m_nChild2).IsLeaf())
|
|
// almeno un child non è leaf quindi devo richiamare ricorsivamente questa funzione sui child in questione
|
|
d = GetHeightLeaves( nId, vnLeaves, m_mTree.at(m_mTree.at(nId).m_nChild1).m_nDepth) ;
|
|
}
|
|
}
|
|
else {
|
|
for ( int j = 0 ; j != (int) vnLeaves.size() ; ++ j) {
|
|
int i = vnLeaves.at(j) ;
|
|
if ( m_mTree.at(i).IsLeaf() ) {
|
|
continue ;
|
|
}
|
|
else {
|
|
// se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child
|
|
vnLeaves.erase( remove( vnLeaves.begin(),vnLeaves.end(),i)) ;
|
|
-- j ;
|
|
vnLeaves.push_back( m_mTree.at(i).m_nChild1) ;
|
|
vnLeaves.push_back( m_mTree.at(i).m_nChild2) ;
|
|
d = std::max ( d, m_mTree.at(m_mTree.at(i).m_nChild1).m_nDepth) ;
|
|
}
|
|
}
|
|
return d ;
|
|
}
|
|
return d - m_mTree.at(nId).m_nDepth ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int
|
|
Tree::GetDepth( int nId, int nRef = -2) const
|
|
{
|
|
int c = 0 ;
|
|
while ( m_mTree.at(nId).m_nParent != nRef) {
|
|
nId = m_mTree.at(nId).m_nParent ;
|
|
++ c ;
|
|
}
|
|
return c ;
|
|
}
|
|
|
|
struct generator
|
|
{
|
|
int value ;
|
|
generator() { value = -1 ;}
|
|
int operator() () { return ++value ; }
|
|
} ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Tree::GetPolygons( std::vector<POLYLINEVECTOR>& vPolygons) {
|
|
if ( (int) m_vPolygons.size() == 0 ) {
|
|
if ( ! m_bTrimmed) {
|
|
vPolygons.clear() ;
|
|
POLYLINEVECTOR vPolygonsBasic ;
|
|
GetPolygonsBasic( vPolygonsBasic) ;
|
|
for ( PolyLine pl : vPolygonsBasic) {
|
|
POLYLINEVECTOR vSinglePolygon ;
|
|
vSinglePolygon.push_back( pl) ;
|
|
vPolygons.push_back( vSinglePolygon) ;
|
|
}
|
|
return true ;
|
|
}
|
|
// trimmata
|
|
else {
|
|
TraceLoopLabelCell() ;
|
|
POLYLINEVECTOR vPolygonsBasic ;
|
|
GetPolygonsBasic( vPolygonsBasic) ;
|
|
// scorro sui poligoni delle celle non trimmate
|
|
int nCells = (int)vPolygonsBasic.size() ;
|
|
for ( int i = 0 ; i < nCells ; ++i ) {
|
|
|
|
// costruisco i poligoni partendo dal vettore delle intersezioni, come spiegato a pag15 di Cripps
|
|
int nId = m_vnLeaves[i] ;
|
|
if ( m_mTree[nId].m_nFlag == 4) {
|
|
// vettore dei poligoni ( loop) della cella nId
|
|
POLYLINEVECTOR vCellPolygons ;
|
|
vCellPolygons.push_back( vPolygonsBasic[i]) ;
|
|
vPolygons.push_back( vCellPolygons) ;
|
|
}
|
|
else if ( m_mTree[nId].m_nFlag == 0)
|
|
continue ;
|
|
else {
|
|
// vettore in cui salvo il chunk di appartenenza di ogni loop che attraversa la cella
|
|
INTVECTOR vnParentChunk ;
|
|
//int nEdgeIn = -1 ;
|
|
// 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()) ;
|
|
std::generate_n( vToCheck.begin(), (int) m_mTree[nId].m_vInters.size(), generator()) ;
|
|
// numero di poligoni aggiunti
|
|
int nPoly = 0 ;
|
|
// scorro sui vettori intersezione della cella nId e sui suoi vertici
|
|
// in questo for analizzo solo i loop che tagliano la cella
|
|
while( nPoly == 0 || (int)vToCheck.size() != 0) {
|
|
int nPolyBefore = nPoly ;
|
|
CreateCellPolygons( i, vPolygons, vToCheck, nPoly, vnParentChunk, vPolygonsBasic[i]) ;
|
|
if ( nPolyBefore == nPoly)
|
|
break ;
|
|
}
|
|
// ora analizzo anche i loop che sono contenuti nella cella
|
|
CreateIslandAndHoles( i, vPolygons, nPoly, vnParentChunk) ;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
else {
|
|
vPolygons = m_vPolygons ;
|
|
return true ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons)
|
|
{
|
|
if ( m_vPolygons.empty()) {
|
|
PNTVECTOR vVertices ;
|
|
INTVECTOR vNeigh ;
|
|
bool bBottomRight , bTopLeft ;
|
|
// scorro lungo tutte le celle leaves ( dell'albero bilanciato) e oltre agli angoli della cella aggiungo alla polyline anche i vertici sui lati
|
|
for ( int nId : m_vnLeaves) {
|
|
vVertices.clear() ;
|
|
vNeigh.clear() ;
|
|
vVertices.push_back( m_mTree.at(nId).GetBottomLeft()) ;
|
|
GetBottomNeigh( nId, vNeigh) ;
|
|
// aggiungo i vertici che sono sul lato bottom, solo se ho più di un vicino bottom
|
|
if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1){
|
|
for ( int j : vNeigh )
|
|
vVertices.push_back( m_mTree.at(j).GetTopRight()) ;
|
|
bBottomRight = true ;
|
|
}
|
|
else
|
|
bBottomRight = false ;
|
|
vNeigh.clear() ;
|
|
GetRightNeigh ( nId, vNeigh) ;
|
|
// aggiungo i vertici che sono sul lato right, solo se ho più di un vicino right
|
|
if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1){
|
|
for ( int j : vNeigh )
|
|
vVertices.push_back( m_mTree.at(j).GetBottomLeft()) ;
|
|
}
|
|
// se non l'ho già aggiunto tramite i vicini bottom aggiungo il punto bottom right
|
|
else if ( ! bBottomRight ) {
|
|
Point3d ptBr( m_mTree.at(nId).GetTopRight().x, m_mTree.at(nId).GetBottomLeft().y) ;
|
|
vVertices.push_back( ptBr) ;
|
|
}
|
|
vNeigh.clear() ;
|
|
vVertices.push_back( m_mTree.at(nId).GetTopRight()) ;
|
|
GetTopNeigh ( nId, vNeigh) ;
|
|
std::reverse( vNeigh.begin(), vNeigh.end()) ;
|
|
// aggiungo i vertici che sono sul lato top, solo se ho più di un vicino top
|
|
if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) {
|
|
for ( int j : vNeigh)
|
|
vVertices.push_back( m_mTree.at(j).GetBottomLeft()) ;
|
|
bTopLeft = true ;
|
|
}
|
|
else
|
|
bTopLeft = false ;
|
|
vNeigh.clear() ;
|
|
GetLeftNeigh ( nId, vNeigh) ;
|
|
std::reverse( vNeigh.begin(), vNeigh.end()) ;
|
|
// aggiungo i vertici che sono sul lato left, solo se ho più di un vicino left
|
|
if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) {
|
|
for ( int j : vNeigh)
|
|
vVertices.push_back( m_mTree.at(j).GetTopRight()) ;
|
|
}
|
|
// se non l'ho già aggiunto tramite i vicini top aggiungo il punto top left
|
|
else if ( ! bTopLeft) {
|
|
Point3d ptTl( m_mTree.at(nId).GetBottomLeft().x, m_mTree.at(nId).GetTopRight().y) ;
|
|
vVertices.push_back( ptTl) ;
|
|
}
|
|
vNeigh.clear() ;
|
|
vVertices.push_back( m_mTree.at(nId).GetBottomLeft()) ;
|
|
if ( ! m_bTrimmed) {
|
|
// se ho una cella con vicino dello stesso grado ( quindi il poligono ha solo 5 punti) controllo la curvatura nella cella e
|
|
// se necessario cambio l'ordine dei vertici per scegliere la diagonale di split migliore
|
|
if ( vVertices.size() == 5) {
|
|
Point3d ptPSrf, ptP00, ptP10, ptP11, ptP01;
|
|
double dU, dV ;
|
|
dU = ( m_mTree.at(nId).GetBottomLeft().x + m_mTree.at(nId).GetTopRight().x) / 2 ;
|
|
dV = ( m_mTree.at(nId).GetBottomLeft().y + m_mTree.at(nId).GetTopRight().y) / 2 ;
|
|
m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ;
|
|
ptP00 = m_mVert.at(nId).at(0) ;
|
|
ptP10 = m_mVert.at(nId).at(1) ;
|
|
ptP11 = m_mVert.at(nId).at(2) ;
|
|
ptP01 = m_mVert.at(nId).at(3) ;
|
|
Point3d ptP00P11 = ( ptP00 + ptP11) / 2 ;
|
|
Point3d ptP10P01 = ( ptP10 + ptP01) / 2 ;
|
|
// ho la curvatura maggiore sulla diagonale tra P10 e P01, ruoto l'ordine dei vertici, in modo che triangulate prenda la diagonale giusta
|
|
if ( Dist(ptP00P11, ptPSrf) + EPS_SMALL > Dist(ptP10P01, ptPSrf)) {
|
|
rotate(vVertices.begin(), vVertices.begin() + 1,vVertices.end()) ;
|
|
vVertices.back() = vVertices.at(0) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_vPolygons.emplace_back() ;
|
|
m_vPolygons.back().emplace_back() ;
|
|
for ( int i = 0 ; i < (int) vVertices.size() ; ++i) {
|
|
m_vPolygons.back().back().AddUPoint(i, vVertices.at(i)) ;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// restituisco i poligoni delle celle del tree nello spazio parametrico
|
|
for ( int t = 0 ; t < (int)m_vPolygons.size() ; ++ t) {
|
|
for ( int z = 0 ; z < (int)m_vPolygons[t].size(); ++z ) {
|
|
vPolygons.push_back( m_vPolygons[t][z]) ;
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
Tree::ResetTree( void)
|
|
{
|
|
//// setto tutti i nodi (foglie comprese) a Processed = false
|
|
//int nCToReset = -1 ;
|
|
//while ( nCToReset != -2 && m_mTree[nCToReset].IsProcessed() == true) {
|
|
// if ( m_mTree[nCToReset].IsLeaf()) {
|
|
// m_mTree[nCToReset].SetProcessed( false) ;
|
|
//
|
|
// // risalgo i parent finché non trovo il primo Child2 da deprocessare
|
|
// nCToReset = m_mTree[nCToReset].m_nParent ;
|
|
// if ( ! m_mTree[m_mTree[nCToReset].m_nChild1].IsProcessed() && ! m_mTree[m_mTree[nCToReset].m_nChild2].IsProcessed())
|
|
// m_mTree[nCToReset].SetProcessed( false) ;
|
|
// while ( ! m_mTree[m_mTree[nCToReset].m_nChild2].IsProcessed()) {
|
|
// if ( m_mTree[nCToReset].m_nParent != -2)
|
|
// nCToReset = m_mTree[nCToReset].m_nParent ;
|
|
// if ( ! m_mTree[m_mTree[nCToReset].m_nChild1].IsProcessed() && ! m_mTree[m_mTree[nCToReset].m_nChild2].IsProcessed())
|
|
// m_mTree[nCToReset].SetProcessed( false) ;
|
|
// if ( nCToReset == -1 && ! m_mTree[m_mTree[nCToReset].m_nChild2].IsProcessed())
|
|
// break ;
|
|
// }
|
|
// nCToReset = m_mTree[nCToReset].m_nChild2 ;
|
|
|
|
// }
|
|
// else {
|
|
// nCToReset = m_mTree[nCToReset].m_nChild1 ;
|
|
// }
|
|
//}
|
|
|
|
// setto tutte le foglie a Processed = false
|
|
for ( int nC : m_vnLeaves ) {
|
|
m_mTree[nC].SetProcessed( false) ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
INTVECTOR
|
|
Tree::FindCell( const Point3d& ptToAssign, CurveLine& clTrim) const
|
|
{
|
|
// riordino le celle da sinistra a destra ( rispetto al verso della cl)
|
|
// devo ancora aggiungerla questa feature!!!////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
INTVECTOR nCells ;
|
|
int nId = -1 ;
|
|
// se fallisce ritorna un vettore vuoto
|
|
// verifico che il punto sia all'interno dello spazio parametrico
|
|
if ( ptToAssign.x < m_mTree.at(-1).GetBottomLeft().x || ptToAssign.x > m_mTree.at( -1).GetTopRight().x ||
|
|
ptToAssign.y < m_mTree.at(-1).GetBottomLeft().y || ptToAssign.y > m_mTree.at( -1).GetTopRight().y ) {
|
|
//nCells.push_back( - 2) ;
|
|
return nCells ;
|
|
}
|
|
|
|
// se lo spazio parametrico non è stato suddiviso ( ho un piano), restituisco la cella root
|
|
if ( m_mTree.at(nId).IsLeaf() ) {
|
|
nCells.push_back( nId) ;
|
|
return nCells ;
|
|
}
|
|
|
|
while ( ! m_mTree.at(nId).IsLeaf()) {
|
|
if ( m_mTree.at(nId).IsSplitVert()) {
|
|
double dMid = ( m_mTree.at(nId).GetBottomLeft().x + m_mTree.at(nId).GetTopRight().x) / 2 ;
|
|
if ( ptToAssign.x < dMid + EPS_SMALL) {
|
|
nId = m_mTree.at(nId).m_nChild1 ;
|
|
}
|
|
else {
|
|
nId = m_mTree.at(nId).m_nChild2 ;
|
|
}
|
|
}
|
|
else {
|
|
double dMid = ( m_mTree.at(nId).GetBottomLeft().y + m_mTree.at(nId).GetTopRight().y) / 2 ;
|
|
if ( ptToAssign.y < dMid + EPS_SMALL ) {
|
|
nId = m_mTree.at(nId).m_nChild2 ;
|
|
}
|
|
else {
|
|
nId = m_mTree.at(nId).m_nChild1 ;
|
|
}
|
|
}
|
|
}
|
|
if ( nId != -1)
|
|
nCells.push_back( nId) ;
|
|
//if ( nId == -1)
|
|
// nId = -2 ;
|
|
|
|
//// devo verificare se sono sul bordo di una cella: in questo caso dovrei restituire anche il vicino con cui condivido quel lato!! /////////////////////
|
|
|
|
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) ;
|
|
//IntCrvCrvInfo aInfo, bInfo ;
|
|
//CurveLine clEdge, clEdge2 ;
|
|
//if ( AreSamePointApprox(ptToAssign, ptTl)){
|
|
// // lato top
|
|
// clEdge.Set( m_mTree.at(nId).GetTopRight(), ptTl) ;
|
|
// IntersLineLine illTrimEdge( clTrim, clEdge, true) ;
|
|
// illTrimEdge.GetIntCrvCrvInfo( aInfo) ;
|
|
// // lato sinistro
|
|
// clEdge2.Set( ptTl, m_mTree.at(nId).GetBottomLeft()) ;
|
|
// IntersLineLine illTrimEdge2( clTrim, clEdge2, true) ;
|
|
// illTrimEdge2.GetIntCrvCrvInfo( bInfo) ;
|
|
// if ( aInfo.bOverlap) {
|
|
// if ( aInfo.bCBOverEq ) {
|
|
|
|
// }
|
|
// }
|
|
//}
|
|
//else if ( AreSamePointApprox( ptToAssign, m_mTree.at(nId).GetBottomLeft())) {
|
|
|
|
//}
|
|
//else if ( AreSamePointApprox(ptToAssign, ptBr)) {
|
|
|
|
//}
|
|
//else if (AreSamePointApprox( ptToAssign, ptTl)) {
|
|
|
|
//}
|
|
|
|
|
|
if ( AreSamePointApprox(ptToAssign, ptTl) ||
|
|
AreSamePointApprox( ptToAssign, m_mTree.at(nId).GetBottomLeft()) ||
|
|
AreSamePointApprox(ptToAssign, ptBr) ||
|
|
AreSamePointApprox( ptToAssign, ptTl))
|
|
{
|
|
Point3d ptToAssignPlus ;
|
|
double dParam ;
|
|
Vector3d vDir ;
|
|
clTrim.GetParamAtPoint( ptToAssign, dParam, EPS_SMALL) ;
|
|
clTrim.GetPointTang( dParam + EPS_SMALL, ICurve::FROM_MINUS, ptToAssignPlus, vDir) ;
|
|
if ( abs( vDir.x) > 1 - EPS_SMALL || abs( vDir.y) > 1 - EPS_SMALL) {
|
|
vDir.Rotate( Z_AX, -90) ;
|
|
ptToAssignPlus = ptToAssignPlus + vDir * EPS_SMALL ;
|
|
}
|
|
nCells = FindCell( ptToAssignPlus, clTrim) ;
|
|
if ( nCells.empty()) {
|
|
ptToAssignPlus = ptToAssignPlus - 2 * vDir * EPS_SMALL ;
|
|
nCells = FindCell( ptToAssignPlus, clTrim) ;
|
|
}
|
|
}
|
|
return nCells ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
INTVECTOR
|
|
Tree::FindCell( const Point3d& ptToAssign, CurveLine& cl, INTVECTOR vCells) const
|
|
{
|
|
// se non trova nulla restituisce un vettore vuoto
|
|
// restituisce sempre solo una cella
|
|
|
|
// la CurveLine è il segmento di trim su cui giace ptToAssign
|
|
// devo usare ptInters + qualcosa///////////////////////////////////////////////
|
|
Point3d ptIntersPlus ;
|
|
double dParam ;
|
|
Vector3d vDir ;
|
|
cl.GetParamAtPoint( ptToAssign, dParam, EPS_SMALL) ;
|
|
cl.GetPointTang( dParam + EPS_SMALL, ICurve::FROM_MINUS, ptIntersPlus, vDir) ;
|
|
INTVECTOR nCells ;
|
|
int nId = -1 ;
|
|
bool bFound = false ;
|
|
for ( int nCell : vCells ) {
|
|
if ( ptIntersPlus.x >= m_mTree.at(nCell).GetBottomLeft().x && ptIntersPlus.x <= m_mTree.at(nCell).GetTopRight().x &&
|
|
ptIntersPlus.y >= m_mTree.at(nCell).GetBottomLeft().y && ptIntersPlus.y <= m_mTree.at(nCell).GetTopRight().y) {
|
|
nId = nCell ;
|
|
nCells.push_back( nId) ;
|
|
}
|
|
//if ( bFound)
|
|
// break ;
|
|
//if ( nCells.size() > 0)
|
|
// bFound = true ;
|
|
}
|
|
return nCells ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Tree::TraceLoopLabelCell( void)
|
|
{
|
|
// approssimo i loop di trim con delle spezzate
|
|
POLYLINEVECTOR vPlApprox ;
|
|
//for ( PtrOwner<ICurve> pCrv : m_vLoop){
|
|
for ( int p = 0 ; p < (int) m_vLoop.size(); ++ p){
|
|
PtrOwner<ICurve> pCrv( m_vLoop[p]->Clone()) ;
|
|
double dLinTol = 0.01 ; // questo è riferito allo spazio parametrico perché le curve di loop sono già state riscalate!!!!!!
|
|
double dAngTolDeg = 5 ;
|
|
PolyLine plApprox ;
|
|
int nType = 0 ;
|
|
pCrv->ApproxWithLines( dLinTol,dAngTolDeg, nType, plApprox) ;
|
|
vPlApprox.push_back( plApprox) ;
|
|
}
|
|
// ora le curve di trim hanno lo stesso indice delle loro corrispondenti spezzate nel vettore vPlApprox
|
|
|
|
double dLinTol = - EPS_SMALL ; // questo è riferito allo spazio parametrico, quando è già stato riporatato al range 0..1 !!!!!!
|
|
// il valore è negativo perché voglio considerare contenuto anche un punto che sta su un lato
|
|
POLYLINEVECTOR vplPolygons ;
|
|
GetPolygonsBasic( vplPolygons) ;
|
|
// percorro i loop trovando le interezioni con le celle e riempiendo i vettori m_vInters delle varie celle
|
|
for ( int i = 0 ; i < (int) vPlApprox.size(); ++ i) {
|
|
PolyLine plLoop = vPlApprox[i] ;
|
|
// calcolo se il loop è CCW o Cw
|
|
double dArea ;
|
|
Plane3d plExtPlane ;
|
|
bool bCCW ;
|
|
plLoop.IsClosedAndFlat( plExtPlane, dArea, 50 * EPS_SMALL) ;
|
|
if ( plExtPlane.GetVersN().z > 0 )
|
|
bCCW = true ;
|
|
else
|
|
bCCW = false ;
|
|
// trovo in quale cella è il ptStart
|
|
Point3d ptStart ;
|
|
plLoop.GetFirstPoint( ptStart) ;
|
|
PNTULIST lPt = plLoop.GetUPointList() ;
|
|
PNTULIST:: iterator ptFirst = lPt.begin();
|
|
PNTULIST:: iterator ptSecond = ptFirst ;
|
|
std::advance( ptSecond, 1) ;
|
|
CurveLine clFirst ;
|
|
clFirst.Set( ptFirst->first, ptSecond->first) ;
|
|
INTVECTOR nCells = FindCell( ptStart, clFirst) ;
|
|
int nId ;
|
|
if ( (int)nCells.size() == 1) {
|
|
nId = nCells[0] ;
|
|
}
|
|
else {
|
|
nId = nCells.back() ;
|
|
}
|
|
// trovo quali punti della polyline sono nella cella e l'intersezione
|
|
PNTVECTOR vptInters ;
|
|
vptInters.push_back( ptStart) ;
|
|
// qui mi devo salvare quanti elementi ho già nel vettore m_vInters della cella
|
|
// per poter fare il merge con l'ultimo vptInters della curva di trim, che sarà ancora in questa cella
|
|
// e terminerà nel punto di start
|
|
int nPass = (int) m_mTree[nId].m_vInters.size() ;
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
// salvo il verso del loop
|
|
m_mTree[nId].m_vInters.back().bCCW = bCCW ;
|
|
// salvo il chunk del loop
|
|
m_mTree[nId].m_vInters.back().nChunk = m_mChunk[i] ;
|
|
bool bLoopInside = true ;
|
|
Point3d ptCurr ;
|
|
INTVECTOR :: iterator iter = find( m_vnLeaves.begin(), m_vnLeaves.end(), nId) ;
|
|
int nIdPolygon = std::distance( m_vnLeaves.begin(), iter) ;
|
|
bool bVertex = false ;
|
|
while ( plLoop.GetNextPoint( ptCurr)) {
|
|
// sto uscendo dalla cella, quindi cerco l'intersezione
|
|
Point3d ptStart, ptEnd ;
|
|
plLoop.GetPrevPoint( ptStart) ;
|
|
plLoop.GetNextPoint( ptEnd) ;
|
|
CurveLine clTrim ;
|
|
clTrim.Set( ptStart, ptEnd) ;
|
|
while( ! IsPointInsidePolyLine( ptCurr, vplPolygons[nIdPolygon], dLinTol)) { /// qui devo mettere una tolleranza negativa per poter tener conto anche dei punti che sono SULLA curva
|
|
bLoopInside = false ;
|
|
// trovo l'intersezione e passo alla cella successiva. nId viene aggiornato dalla funzione FindInters
|
|
bVertex = false ;
|
|
FindInters( nId, clTrim, vptInters, bVertex) ;
|
|
// ricalcolo la posizione di nId nel vettore delle foglie
|
|
iter = find( m_vnLeaves.begin(), m_vnLeaves.end(), nId) ;
|
|
nIdPolygon = std::distance( m_vnLeaves.begin(), iter) ;
|
|
// salvo il verso del loop
|
|
m_mTree[nId].m_vInters.back().bCCW = bCCW ;
|
|
// salvo il chunk del loop
|
|
m_mTree[nId].m_vInters.back().nChunk = m_mChunk[i] ;
|
|
}
|
|
// aggiungo la fine del segmento nel vettore delle intersezioni
|
|
vptInters.push_back( ptCurr) ;
|
|
}
|
|
vptInters.pop_back() ;
|
|
m_mTree[nId].m_vInters.back().vpt = vptInters ;
|
|
if ( bLoopInside) {
|
|
m_mTree[nId].m_vnLoop.push_back( i) ;
|
|
// setto la categoria della cella
|
|
if ( m_mTree[nId].m_nFlag == -1)
|
|
m_mTree[nId].m_nFlag = 2 ;
|
|
else if ( m_mTree[nId].m_nFlag == 1)
|
|
m_mTree[nId].m_nFlag = 3 ;
|
|
// setto i lati di ingresso e uscita a -1 per indicare che ho un loop interno alla cella
|
|
m_mTree[nId].m_vInters.back().nIn = -1 ;
|
|
m_mTree[nId].m_vInters.back().nOut = -1 ;
|
|
}
|
|
// sono tornato alla cella di partenza, quindi devo fare il merge dei due vettori di intersezione che ho creato per questa cella
|
|
// per lo stesso loop
|
|
else {
|
|
// devo verificare se il loop finisce in un vertice! in questo caso sono nella penultima cella! e devo fare un FindInters di nuovo per sistemare
|
|
Point3d ptLast = m_mTree[nId].m_vInters.back().vpt.back() ;
|
|
Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ;
|
|
Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ;
|
|
int nLastId ;
|
|
if ( AreSamePointApprox( m_mTree[nId].GetTopRight(), ptLast) ||
|
|
AreSamePointApprox( ptTl, ptLast) ||
|
|
AreSamePointApprox( m_mTree[nId].GetBottomLeft(), ptLast) ||
|
|
AreSamePointApprox( ptBr, ptLast)) {
|
|
Point3d ptStart, ptEnd ;
|
|
plLoop.GetPrevPoint( ptEnd) ;
|
|
plLoop.GetPrevPoint( ptStart) ;
|
|
CurveLine clTrim ;
|
|
clTrim.Set( ptStart, ptEnd) ;
|
|
vptInters.clear() ;
|
|
nLastId = nId ;
|
|
FindInters( nId, clTrim, vptInters, bVertex) ;
|
|
m_mTree[nLastId].m_vInters.back().vpt.push_back( vptInters[0]) ;
|
|
}
|
|
int nOut = m_mTree[nId].m_vInters[nPass].nOut ;
|
|
m_mTree[nId].m_vInters.back().vpt.insert( m_mTree[nId].m_vInters.back().vpt.end(),
|
|
m_mTree[nId].m_vInters[nPass].vpt.begin(),
|
|
m_mTree[nId].m_vInters[nPass].vpt.end()) ;
|
|
m_mTree[nId].m_vInters[nPass] = m_mTree[nId].m_vInters.back() ;
|
|
m_mTree[nId].m_vInters.pop_back() ;
|
|
// sistemo il lato d'uscita
|
|
m_mTree[nId].m_vInters[nPass].nOut = nOut ;
|
|
}
|
|
}
|
|
|
|
// riordino i vettori di intersezione per ogni cella e setto il flag RightEdgeIn
|
|
for ( int nId : m_vnLeaves) {
|
|
std::sort( m_mTree[nId].m_vInters.begin( ), m_mTree[nId].m_vInters.end()) ;
|
|
SetRightEdgeIn( nId) ;
|
|
}
|
|
|
|
// devo riconoscere le celle dentro i loop che sono ancora con label nFlag2 = 0
|
|
ResetTree() ;
|
|
INTVECTOR vNeigh, vFirst ;
|
|
GetRootNeigh( 1, vFirst) ;
|
|
int nLastLeft = vFirst.back() ;
|
|
int nCell = vFirst[0] ;
|
|
GetRightNeigh( nCell, vNeigh) ;
|
|
// proseguo finché non sono sull'elemento più alto di vFirst e tutti i suoi vicini sono processati/categorizzati
|
|
bool bAllDone = false ;
|
|
while ( nCell != nLastLeft && ! bAllDone) {
|
|
// categorizzo la cella
|
|
m_mTree[nCell].m_nFlag2 = 1 ;
|
|
CategorizeCell( nCell) ;
|
|
bool bDone = false ;
|
|
int nInProcessing = -1 ;
|
|
int c = 0 ;
|
|
int nDisplay = -1 ;
|
|
// fintanto che la cella ha tra i vicini a destra una cella non elaborata mi sposto a destra
|
|
// definisco una cella Processed se tutto il ramo a destra è categorizzato
|
|
while ( ((int)vNeigh.size() > 0 && ! bDone) || ! m_mTree[nCell].IsProcessed()) {
|
|
// per debug
|
|
if ( nInProcessing != nCell) {
|
|
nInProcessing = nCell ;
|
|
c = 0 ;
|
|
}
|
|
else
|
|
++ c ;
|
|
// verso la cella a destra più in basso da cui non sono ancora passato
|
|
bool bProceeded = false ;
|
|
for ( int i = 0 ; i < (int)vNeigh.size(); ++ i) {
|
|
if ( m_mTree[vNeigh[i]].m_nFlag2 == 0 ) {
|
|
nCell = vNeigh[i] ;
|
|
nDisplay = m_mTree[nCell].m_nFlag ;
|
|
bProceeded = true ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( ! bProceeded ) {
|
|
m_mTree[nCell].SetProcessed() ;
|
|
}
|
|
else { //categorizzo la cella///////////////////////////////////////////////////////////
|
|
m_mTree[nCell].m_nFlag2 = 1 ;
|
|
CategorizeCell( nCell) ;
|
|
}
|
|
|
|
if ( ! m_mTree[nCell].IsProcessed()) {
|
|
// guardo i vicini a destra per passare alla prossima cella
|
|
vNeigh.clear() ;
|
|
GetRightNeigh( nCell, vNeigh) ;
|
|
bDone = true ;
|
|
// controllo che tra i vicini di destra ce ne sia almeno uno non processato
|
|
for ( int t: vNeigh) {
|
|
if ( ! m_mTree[t].IsProcessed()) {
|
|
bDone = false ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
// per debug
|
|
if ( c > 3)
|
|
break ;
|
|
}
|
|
vNeigh.clear() ;
|
|
GetRightNeigh( nCell, vNeigh) ;
|
|
// se non ho vicini a destra o se i vicini sono già tutti categorizzati
|
|
// torno indietro a sinistra alla cella già categorizzata più bassa
|
|
//bDone = true ;
|
|
c = 0 ;
|
|
while ( (int) vNeigh.size() == 0 || m_mTree[nCell].IsProcessed()) {
|
|
// per debug
|
|
if ( nInProcessing != nCell) {
|
|
nInProcessing = nCell ;
|
|
c = 0 ;
|
|
}
|
|
else
|
|
++ c ;
|
|
// trovo il vicino a sinistra, già categorizzato, più basso
|
|
vNeigh.clear() ;
|
|
GetLeftNeigh( nCell, vNeigh) ;
|
|
for ( int p = 0; p < (int)vNeigh.size() ; ++ p) {
|
|
if ( m_mTree[vNeigh[p]].m_nFlag2 != 0 ) {
|
|
nCell = vNeigh[p] ;
|
|
break ;
|
|
}
|
|
}
|
|
// se non ho vicini a sinistra sono tornato sul lato sinistro e quindi devo procedere alla cella più bassa non processata sul lato sinistro
|
|
if ( vNeigh.empty() ) {
|
|
for ( int p = 0 ; p < (int)vFirst.size() ; ++ p ) {
|
|
if ( m_mTree[vFirst[p]].m_nFlag2 == 0 ) {
|
|
nCell = vFirst[p] ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( nCell == nLastLeft && m_mTree[nCell].IsProcessed() ) {
|
|
// categorizzo////////////////////////////////////////////////////////////////////////////
|
|
m_mTree[nCell].m_nFlag2 = 1 ;
|
|
CategorizeCell( nCell) ;
|
|
bAllDone = true ;
|
|
break ;
|
|
}
|
|
}
|
|
// controllo se tutti i vicini di destra sono categorizzati
|
|
vNeigh.clear() ;
|
|
GetRightNeigh( nCell, vNeigh) ;
|
|
bool bDone = true ;
|
|
for ( int k = 0; k < (int)vNeigh.size() ; ++ k) {
|
|
if ( ! m_mTree[vNeigh[k]].IsProcessed() ) {
|
|
//nCell = vNeigh[k] ;
|
|
bDone = false ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( bDone) {
|
|
m_mTree[nCell].SetProcessed( bDone) ;
|
|
if ( m_mTree[nCell].m_nFlag2 == 0) {
|
|
m_mTree[nCell].m_nFlag2 = 1 ;
|
|
CategorizeCell( nCell) ;
|
|
}
|
|
}
|
|
// per debug
|
|
if ( c > 3)
|
|
break ;
|
|
}
|
|
vNeigh.clear() ;
|
|
GetRightNeigh( nCell, vNeigh) ;
|
|
|
|
//// se sono all'ultimo elemento di vFirst controllo se ho processato tutti i suoi vicini di destra
|
|
//if ( nCell == nLastLeft){
|
|
// vNeigh.clear() ;
|
|
// GetRightNeigh( nCell, vNeigh) ;
|
|
// bAllDone = true ;
|
|
// for( int j = 0 ; j < (int) vNeigh.size(); ++ j) {
|
|
// if ( ! m_mTree[vNeigh[j]].IsProcessed() ) {
|
|
// bAllDone = false ;
|
|
// break ;
|
|
// }
|
|
// }
|
|
//}
|
|
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVertex)
|
|
{
|
|
CurveLine clEdge , clEdge2 ;
|
|
Point3d ptStart , ptEnd ;
|
|
clTrim.GetStartPoint( ptStart) ;
|
|
clTrim.GetEndPoint( ptEnd) ;
|
|
// trovo da quale lato sto uscendo
|
|
Point3d ptTR = m_mTree[nId].GetTopRight() ;
|
|
Point3d ptBL = m_mTree[nId].GetBottomLeft() ;
|
|
Point3d ptTl( ptBL.x , ptTR.y) ;
|
|
Point3d ptBr( ptTR.x , ptBL.y) ;
|
|
int nEdge ; // flag che indica il lato su cui ho l'intersezione a partire dal lato top in senso antiorario
|
|
// oltre il 3 sono le celle adiacenti in diagonale al vertice-> 4 corrisponde al ptTl e da lì in senso antiorario
|
|
// -1 se la curva è sempre dentro la cella
|
|
bool bIntersFound = false ;
|
|
Point3d ptInters ;
|
|
if ( ptEnd.y >= ptTR.y && ptEnd.x <= ptTR.x) {
|
|
nEdge = 0 ;
|
|
// lato sopra
|
|
clEdge.Set( ptTR, ptTl) ;
|
|
//if ( ptEnd.x >= ptBL.x)
|
|
// ;// lato sinistro
|
|
//else //if ( ptEnd.x < ptBL.x)
|
|
if ( ptEnd.x < ptBL.x)
|
|
clEdge2.Set( ptTl, ptBL) ;
|
|
else if ( AreSamePointExact( ptEnd, ptTl)) {
|
|
nEdge = 4 ;
|
|
ptInters = ptTl ;
|
|
bIntersFound = true ;
|
|
}
|
|
}
|
|
else if ( ptEnd.x <= ptBL.x && ptEnd.y <= ptTR.y) {
|
|
nEdge = 1 ;
|
|
// lato sinistro
|
|
clEdge.Set( ptTl, ptBL) ;
|
|
//if ( ptEnd.y >= ptBL.y)
|
|
// ;
|
|
//// lato sotto
|
|
//else //if ( ptEnd.y < ptBL.y)
|
|
if ( ptEnd.y < ptBL.y)
|
|
clEdge2.Set( ptBL, ptBr) ;
|
|
else if ( AreSamePointExact( ptEnd, ptBL)) {
|
|
nEdge = 5 ;
|
|
ptInters = ptBL ;
|
|
bIntersFound = true ;
|
|
}
|
|
}
|
|
else if ( ptEnd.y <= ptBL.y && ptEnd.x >= ptBL.x) {
|
|
nEdge = 2 ;
|
|
// lato sotto
|
|
clEdge.Set( ptBL, ptBr) ;
|
|
//if ( ptEnd.x <= ptTR.x)
|
|
// ;
|
|
//// lato destro
|
|
//else //if ( ptEnd.x > ptTR.x)
|
|
if ( ptEnd.x > ptTR.x)
|
|
clEdge2.Set( ptBr, ptTR) ;
|
|
else if ( AreSamePointExact( ptEnd, ptBr)) {
|
|
nEdge = 6 ;
|
|
ptInters = ptBr ;
|
|
bIntersFound = true ;
|
|
}
|
|
}
|
|
else if ( ptEnd.x >= ptTR.x && ptEnd.y >= ptBL.y) {
|
|
nEdge = 3 ;
|
|
// lato desto
|
|
clEdge.Set( ptBr, ptTR) ;
|
|
//if ( ptEnd.y <= ptTR.y)
|
|
// ;
|
|
//// lato sopra
|
|
//else //if ( ptEnd.y > ptTR.y)
|
|
if ( ptEnd.y > ptTR.y)
|
|
clEdge2.Set( ptTR, ptTl) ;
|
|
else if ( AreSamePointExact( ptEnd, ptTR)) {
|
|
nEdge = 7 ;
|
|
ptInters = ptTR ;
|
|
bIntersFound = true ;
|
|
}
|
|
}
|
|
else
|
|
return false ;
|
|
|
|
if ( ! bIntersFound) {
|
|
// intersezione e controlli
|
|
IntersLineLine illExit( clTrim, clEdge, true) ;
|
|
IntCrvCrvInfo aInfo, aInfo2 ;
|
|
//if ( ! illExit.GetIntCrvCrvInfo( aInfo) )
|
|
// return false ;
|
|
illExit.GetIntCrvCrvInfo( aInfo) ;
|
|
if ( clEdge2.IsValid()){
|
|
IntersLineLine illExit2( clTrim, clEdge2, true) ;
|
|
//if ( ! illExit2.GetIntCrvCrvInfo( aInfo2) )
|
|
// return false ;
|
|
// verifico su quale dei due lati ho l'intersezione
|
|
if ( ! illExit2.GetIntCrvCrvInfo( aInfo2))
|
|
ptInters = aInfo.IciA[0].ptI ;
|
|
else {
|
|
// solo intersezione sul lato 2
|
|
if ( illExit.GetNumInters() == 0 ) {
|
|
ptInters = aInfo2.IciA[0].ptI ;
|
|
if ( nEdge > 3 && nEdge != 7)
|
|
nEdge = nEdge - 4 ;
|
|
else if ( nEdge < 3 )
|
|
++ nEdge ;
|
|
else
|
|
nEdge = 0 ;
|
|
}
|
|
// intersezione sul vertice della cella
|
|
else {
|
|
ptInters = aInfo2.IciA[0].ptI ;
|
|
bVertex = true ;
|
|
// la cella adiacente in diagonale a quel vertice
|
|
nEdge = nEdge + 4 ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
ptInters = aInfo.IciA[0].ptI ;
|
|
}
|
|
// devo controllare se l'intersezione è in un vertice ed eventualmente correggere nEdge
|
|
if ( nEdge < 4) {
|
|
if ( AreSamePointExact( ptInters, ptTl))
|
|
nEdge = 4 ;
|
|
else if ( AreSamePointExact( ptInters, ptBL))
|
|
nEdge = 5 ;
|
|
else if ( AreSamePointExact( ptInters, ptBr))
|
|
nEdge = 6 ;
|
|
else if ( AreSamePointExact( ptInters, ptTR))
|
|
nEdge = 7 ;
|
|
}
|
|
m_mTree[nId].m_vInters.back().nOut = nEdge ;
|
|
vptInters.push_back( ptInters) ;
|
|
// salvo il vettore intersezione per la cella e capisco in quale altra cella passare
|
|
if ( (int)vptInters.size() == 1)
|
|
m_mTree[nId].m_vInters.back().vpt.push_back( vptInters[0]) ;
|
|
else
|
|
m_mTree[nId].m_vInters.back().vpt = vptInters ;
|
|
vptInters.clear() ;
|
|
// setto la categoria della cella
|
|
if ( m_mTree[nId].m_nFlag == -1)
|
|
m_mTree[nId].m_nFlag = 1 ;
|
|
else if ( m_mTree[nId].m_nFlag == 2)
|
|
m_mTree[nId].m_nFlag = 3 ;
|
|
// seleziono la cella successiva da analizzare
|
|
INTVECTOR vNeigh, vNeigh1 ;
|
|
if ( nEdge == 0) {
|
|
GetTopNeigh( nId, vNeigh) ;
|
|
std::reverse( vNeigh.begin(), vNeigh.end()) ;
|
|
for ( int j : vNeigh ) {
|
|
if ( ptInters.x >= m_mTree[j].GetBottomLeft().x) {
|
|
nId = j ;
|
|
break ;
|
|
}
|
|
}
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ;
|
|
if ( ptInters.x > m_mTree[nId].GetBottomLeft().x + EPS_SMALL && ptInters.x < m_mTree[nId].GetTopRight().x - EPS_SMALL)
|
|
m_mTree[nId].m_vInters.back().nIn = 2 ;
|
|
else if ( AreSamePointApprox( ptInters, m_mTree[nId].GetBottomLeft()))
|
|
m_mTree[nId].m_vInters.back().nIn = 5 ;
|
|
else if ( AreSamePointApprox( ptInters, ptBr))
|
|
m_mTree[nId].m_vInters.back().nIn = 6 ;
|
|
else
|
|
m_mTree[nId].m_vInters.back().nIn = 2 ;
|
|
}
|
|
else if ( nEdge == 1) {
|
|
GetLeftNeigh( nId, vNeigh) ;
|
|
std::reverse( vNeigh.begin(), vNeigh.end()) ;
|
|
for ( int j : vNeigh ) {
|
|
if ( ptInters.y >= m_mTree[j].GetBottomLeft().y) {
|
|
nId = j ;
|
|
break ;
|
|
}
|
|
}
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ;
|
|
if ( ptInters.y > m_mTree[nId].GetBottomLeft().y + EPS_SMALL && ptInters.y < m_mTree[nId].GetTopRight().y - EPS_SMALL)
|
|
m_mTree[nId].m_vInters.back().nIn = 3 ;
|
|
else if ( AreSamePointApprox( ptInters, ptBr))
|
|
m_mTree[nId].m_vInters.back().nIn = 6 ;
|
|
else if ( AreSamePointApprox( ptInters, m_mTree[nId].GetTopRight()))
|
|
m_mTree[nId].m_vInters.back().nIn = 7 ;
|
|
else
|
|
m_mTree[nId].m_vInters.back().nIn = 3 ;
|
|
}
|
|
else if ( nEdge == 2) {
|
|
GetBottomNeigh( nId, vNeigh) ;
|
|
for ( int j : vNeigh ) {
|
|
if ( ptInters.x <= m_mTree[j].GetTopRight().x) {
|
|
nId = j ;
|
|
break ;
|
|
}
|
|
}
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ;
|
|
if ( ptInters.x > m_mTree[nId].GetBottomLeft().x + EPS_SMALL && ptInters.x < m_mTree[nId].GetTopRight().x - EPS_SMALL)
|
|
m_mTree[nId].m_vInters.back().nIn = 0 ;
|
|
else if ( AreSamePointApprox( ptInters, ptTl))
|
|
m_mTree[nId].m_vInters.back().nIn = 4 ;
|
|
else if ( AreSamePointApprox( ptInters, m_mTree[nId].GetTopRight()))
|
|
m_mTree[nId].m_vInters.back().nIn = 7 ;
|
|
else
|
|
m_mTree[nId].m_vInters.back().nIn = 0 ;
|
|
}
|
|
else if ( nEdge == 3) {
|
|
GetRightNeigh( nId, vNeigh) ;
|
|
for ( int j : vNeigh ) {
|
|
if ( ptInters.y <= m_mTree[j].GetTopRight().y) {
|
|
nId = j ;
|
|
break ;
|
|
}
|
|
}
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ;
|
|
if ( ptInters.y > m_mTree[nId].GetBottomLeft().y + EPS_SMALL && ptInters.y < m_mTree[nId].GetTopRight().y - EPS_SMALL)
|
|
m_mTree[nId].m_vInters.back().nIn = 1 ;
|
|
else if ( AreSamePointApprox( ptInters, m_mTree[nId].GetBottomLeft()))
|
|
m_mTree[nId].m_vInters.back().nIn = 5 ;
|
|
else if ( AreSamePointApprox( ptInters, ptTl))
|
|
m_mTree[nId].m_vInters.back().nIn = 4 ;
|
|
else
|
|
m_mTree[nId].m_vInters.back().nIn = 1 ;
|
|
}
|
|
// esco da uno dei vertici
|
|
else if ( nEdge == 4) {
|
|
GetTopNeigh( nId, vNeigh) ;
|
|
GetLeftNeigh( nId, vNeigh1) ;
|
|
INTVECTOR nPossible, nPossible1 ;
|
|
nPossible = FindCell( ptInters, clTrim, vNeigh) ;
|
|
nPossible1 = FindCell( ptInters, clTrim, vNeigh1) ;
|
|
// ingresso dal basso
|
|
if ( ! nPossible.empty()) {
|
|
nId = nPossible[0] ;
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
// controllo se entro in un vertice o a metà lato
|
|
Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ;
|
|
if ( AreSamePointExact( ptInters, ptBr))
|
|
m_mTree[nId].m_vInters.back().nIn = 6 ;
|
|
else if ( AreSamePointExact( ptInters, m_mTree[nId].GetBottomLeft()))
|
|
m_mTree[nId].m_vInters.back().nIn = 5 ;
|
|
else
|
|
m_mTree[nId].m_vInters.back().nIn = 2 ;
|
|
}
|
|
// ingresso da destra
|
|
else if ( ! nPossible1.empty()) {
|
|
nId = nPossible1.back() ;
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
// controllo se entro in un vertice o a metà lato
|
|
Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ;
|
|
if ( AreSamePointExact( ptInters, ptBr))
|
|
m_mTree[nId].m_vInters.back().nIn = 6 ;
|
|
else if ( AreSamePointExact( ptInters, m_mTree[nId].GetTopRight()))
|
|
m_mTree[nId].m_vInters.back().nIn = 7 ;
|
|
else
|
|
m_mTree[nId].m_vInters.back().nIn = 3 ;
|
|
}
|
|
// ingresso in diagonale
|
|
else {
|
|
if ( ! vNeigh.empty()) {
|
|
int nIdTemp = vNeigh[0] ;
|
|
vNeigh.clear() ;
|
|
GetLeftNeigh( nIdTemp, vNeigh) ;
|
|
nId = vNeigh[0] ;
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
m_mTree[nId].m_vInters.back().nIn = 6 ;
|
|
}
|
|
else {
|
|
nId = vNeigh1.back() ;
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
m_mTree[nId].m_vInters.back().nIn = 7 ;
|
|
}
|
|
}
|
|
}
|
|
else if ( nEdge == 5) {
|
|
GetLeftNeigh( nId, vNeigh) ;
|
|
GetBottomNeigh( nId, vNeigh1) ;
|
|
INTVECTOR nPossible, nPossible1 ;
|
|
nPossible = FindCell( ptInters, clTrim, vNeigh) ;
|
|
nPossible1 = FindCell( ptInters, clTrim, vNeigh1) ;
|
|
// ingresso dal destra
|
|
if ( ! nPossible.empty()) {
|
|
nId = nPossible[0] ;
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
// controllo se entro in un vertice o a metà lato
|
|
Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ;
|
|
if ( AreSamePointExact( ptInters, ptBr))
|
|
m_mTree[nId].m_vInters.back().nIn = 6 ;
|
|
else if ( AreSamePointExact( ptInters, m_mTree[nId].GetTopRight()))
|
|
m_mTree[nId].m_vInters.back().nIn = 7 ;
|
|
else
|
|
m_mTree[nId].m_vInters.back().nIn = 3 ;
|
|
}
|
|
// ingresso dall'alto
|
|
else if ( ! nPossible1.empty()) {
|
|
nId = nPossible1[0] ;
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
// controllo se entro in un vertice o a metà lato
|
|
Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ;
|
|
if ( AreSamePointExact( ptInters, ptTl))
|
|
m_mTree[nId].m_vInters.back().nIn = 4 ;
|
|
else if ( AreSamePointExact( ptInters, m_mTree[nId].GetTopRight()))
|
|
m_mTree[nId].m_vInters.back().nIn = 7 ;
|
|
else
|
|
m_mTree[nId].m_vInters.back().nIn = 0 ;
|
|
}
|
|
// ingresso in diagonale
|
|
else {
|
|
if ( ! vNeigh.empty()) {
|
|
int nIdTemp = vNeigh[0] ;
|
|
vNeigh.clear() ;
|
|
GetBottomNeigh( nIdTemp, vNeigh) ;
|
|
nId = vNeigh.back() ;
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
m_mTree[nId].m_vInters.back().nIn = 7 ;
|
|
}
|
|
else {
|
|
nId = vNeigh[0] ;
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
m_mTree[nId].m_vInters.back().nIn = 4 ;
|
|
}
|
|
}
|
|
}
|
|
else if ( nEdge == 6) {
|
|
GetBottomNeigh( nId, vNeigh) ;
|
|
GetRightNeigh( nId, vNeigh1) ;
|
|
INTVECTOR nPossible, nPossible1 ;
|
|
nPossible = FindCell( ptInters, clTrim, vNeigh) ;
|
|
nPossible1 = FindCell( ptInters, clTrim, vNeigh1) ;
|
|
// ingresso dall'alto
|
|
if ( ! nPossible.empty()) {
|
|
nId = nPossible.back() ;
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
// controllo se entro in un vertice o a metà lato
|
|
Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ;
|
|
if ( AreSamePointExact( ptInters, ptTl))
|
|
m_mTree[nId].m_vInters.back().nIn = 4 ;
|
|
else if ( AreSamePointExact( ptInters, m_mTree[nId].GetTopRight()))
|
|
m_mTree[nId].m_vInters.back().nIn = 7 ;
|
|
else
|
|
m_mTree[nId].m_vInters.back().nIn = 0 ;
|
|
}
|
|
// ingresso da sinistra
|
|
else if ( ! nPossible1.empty()) {
|
|
nId = nPossible1[0] ;
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
// controllo se entro in un vertice o a metà lato
|
|
Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ;
|
|
if ( AreSamePointExact( ptInters, ptTl))
|
|
m_mTree[nId].m_vInters.back().nIn = 4 ;
|
|
else if ( AreSamePointExact( ptInters, m_mTree[nId].GetBottomLeft()))
|
|
m_mTree[nId].m_vInters.back().nIn = 5 ;
|
|
else
|
|
m_mTree[nId].m_vInters.back().nIn = 1 ;
|
|
}
|
|
// ingresso in diagonale
|
|
else {
|
|
if ( ! vNeigh.empty()){
|
|
int nIdTemp = vNeigh.back() ;
|
|
vNeigh.clear() ;
|
|
GetRightNeigh( nIdTemp, vNeigh) ;
|
|
nId = vNeigh.back() ;
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
m_mTree[nId].m_vInters.back().nIn = 4 ;
|
|
}
|
|
else {
|
|
GetRightNeigh( nId, vNeigh) ;
|
|
nId = vNeigh[0] ;
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
m_mTree[nId].m_vInters.back().nIn = 5 ;
|
|
}
|
|
}
|
|
}
|
|
else if ( nEdge == 7) {
|
|
GetRightNeigh( nId, vNeigh) ;
|
|
GetTopNeigh( nId, vNeigh1) ;
|
|
INTVECTOR nPossible, nPossible1 ;
|
|
nPossible = FindCell( ptInters, clTrim, vNeigh) ;
|
|
nPossible1 = FindCell( ptInters, clTrim, vNeigh1) ;
|
|
// ingresso da sinistra
|
|
if ( ! nPossible.empty()) {
|
|
nId = nPossible.back() ;
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
// controllo se entro in un vertice o a metà lato
|
|
Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ;
|
|
if ( AreSamePointExact( ptInters, ptTl))
|
|
m_mTree[nId].m_vInters.back().nIn = 4 ;
|
|
else if ( AreSamePointExact( ptInters, m_mTree[nId].GetBottomLeft()))
|
|
m_mTree[nId].m_vInters.back().nIn = 5 ;
|
|
else
|
|
m_mTree[nId].m_vInters.back().nIn = 1 ;
|
|
}
|
|
// ingresso dal basso
|
|
else if ( ! nPossible1.empty()) {
|
|
nId = nPossible1.back() ;
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
// controllo se entro in un vertice o a metà lato
|
|
Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ;
|
|
if ( AreSamePointExact( ptInters, ptBr))
|
|
m_mTree[nId].m_vInters.back().nIn = 6 ;
|
|
else if ( AreSamePointExact( ptInters, m_mTree[nId].GetBottomLeft()))
|
|
m_mTree[nId].m_vInters.back().nIn = 5 ;
|
|
else
|
|
m_mTree[nId].m_vInters.back().nIn = 2 ;
|
|
}
|
|
// ingresso in diagonale
|
|
else {
|
|
if ( ! vNeigh.empty()) {
|
|
int nIdTemp = vNeigh.back() ;
|
|
vNeigh.clear() ;
|
|
GetTopNeigh( nIdTemp, vNeigh) ;
|
|
nId = vNeigh[0] ;
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
m_mTree[nId].m_vInters.back().nIn = 5 ;
|
|
}
|
|
else {
|
|
nId = vNeigh.back() ;
|
|
m_mTree[nId].m_vInters.emplace_back() ;
|
|
m_mTree[nId].m_vInters.back().nIn = 6 ;
|
|
}
|
|
}
|
|
}
|
|
// aggiungo l'intersezione al vettore delle intersezioni della prossima cella
|
|
vptInters.push_back( ptInters) ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Tree::CreateCellPolygons( int nLeafId, std::vector<POLYLINEVECTOR>& vPolygons, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk, PolyLine plCell)
|
|
{
|
|
// conto quanti vertici in più ho per lato e creo un vettore dei vertici per lato
|
|
int nId = m_vnLeaves[nLeafId] ;
|
|
std::vector<PNTVECTOR> vEdgeVertex ;
|
|
Point3d ptTl(m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ;
|
|
Point3d ptBr(m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ;
|
|
vEdgeVertex.emplace_back() ;
|
|
vEdgeVertex.back().push_back( m_mTree[nId].GetTopRight()) ;
|
|
vEdgeVertex.emplace_back() ;
|
|
vEdgeVertex.back().push_back( ptTl) ;
|
|
vEdgeVertex.emplace_back() ;
|
|
vEdgeVertex.back().push_back( m_mTree[nId].GetBottomLeft()) ;
|
|
vEdgeVertex.emplace_back() ;
|
|
vEdgeVertex.back().push_back( ptBr) ;
|
|
// la PolyLine è riempita a partire dal lato bottom
|
|
Point3d ptStart ;
|
|
plCell.GetFirstPoint( ptStart) ;
|
|
INTVECTOR vEdge = { 2, 3, 0, 1} ;
|
|
for ( int p = 0 ; p < 4 ; ++ p) {
|
|
int j = vEdge[p] ;
|
|
int next = j +1 ;
|
|
if ( j == 3)
|
|
next = 0 ;
|
|
Point3d ptToAdd ;
|
|
while ( plCell.GetNextPoint( ptToAdd) && ! AreSamePointExact( ptToAdd, vEdgeVertex[next][0])) {
|
|
vEdgeVertex[j].push_back( ptToAdd) ;
|
|
}
|
|
}
|
|
|
|
// comincio a costruire il poligono
|
|
INTVECTOR vToCheckNow = vToCheck ;
|
|
vToCheck.clear() ;
|
|
// vettore dei poligoni ( loop) della cella nId
|
|
POLYLINEVECTOR vCellPolygons ;
|
|
// costruisco i poligoni partendo dal vettore delle intersezioni, come spiegato a pag15 di Cripps
|
|
PolyLine plTrimmedPoly ;
|
|
// numero di volte che la cella è stata attraversata da una curva di trim
|
|
int nPassToCheck = (int) vToCheckNow.size() ;
|
|
// numero di vertici aggiunti al nuovo poligono
|
|
int c = 0 ;
|
|
// scorro sui vettori intersezione della cella nId e sui suoi vertici
|
|
// in questo for analizzo solo i loop che tagliano la cella
|
|
int nEdgeIn = -1 ;
|
|
int nFirstLoopInPoly = -1 ;
|
|
INTVECTOR vAddedLoops ;
|
|
for ( int w = 0 ; w < (int)vToCheckNow.size() ; ++ w) {
|
|
// indice del loop in m_vInters
|
|
int j = vToCheckNow[w] ;
|
|
Inters inA = m_mTree[nId].m_vInters[j] ;
|
|
if ( inA.nIn != -1 ) {
|
|
int nEdge ;
|
|
if ( nEdgeIn == -1 ) {
|
|
// salvo il lato di ingresso del primo lato del poligono che sto costruendo
|
|
nEdgeIn = inA.nIn ;
|
|
nFirstLoopInPoly = j ;
|
|
}
|
|
for ( Point3d ptInt : inA.vpt ) {
|
|
AddVertex( nId, vEdgeVertex, plTrimmedPoly, c, ptInt) ;
|
|
}
|
|
vAddedLoops.push_back( j) ;
|
|
nEdge = inA.nOut ;
|
|
// devo verificare di non essere uscito in un vertice, con un tratto sovrapposto al lato che ripercorrerò tra poco
|
|
Point3d ptLast, ptSecondToLast;
|
|
plTrimmedPoly.GetLastPoint(ptLast) ;
|
|
plTrimmedPoly.GetPrevPoint(ptSecondToLast) ;
|
|
Vector3d vLast = ptLast - ptSecondToLast ;
|
|
vLast.Normalize();
|
|
Vector3d vEdge ;
|
|
if ( AreSameEdge( nEdge, 0)) {
|
|
if ( AreSamePointApprox(ptLast, ptTl) ) {
|
|
vEdge = m_mTree[nId].GetBottomLeft() - ptTl ;
|
|
vEdge.Normalize() ;
|
|
if ( AreOppositeVectorApprox(vLast, vEdge) ) {
|
|
plTrimmedPoly.EraseLastUPoint() ;
|
|
nEdge = 1 ;
|
|
}
|
|
}
|
|
}
|
|
else if ( AreSameEdge( nEdge, 1) && AreSamePointApprox(ptLast, m_mTree[nId].GetBottomLeft()) ) {
|
|
vEdge = ptBr - m_mTree[nId].GetBottomLeft() ;
|
|
vEdge.Normalize() ;
|
|
if ( AreOppositeVectorApprox(vLast, vEdge) ) {
|
|
plTrimmedPoly.EraseLastUPoint() ;
|
|
nEdge = 2 ;
|
|
}
|
|
}
|
|
else if ( AreSameEdge( nEdge, 2) ) {
|
|
if ( AreSamePointApprox(ptLast, ptBr) ) {
|
|
vEdge = m_mTree[nId].GetTopRight() - ptBr ;
|
|
vEdge.Normalize() ;
|
|
if ( AreOppositeVectorApprox(vLast, vEdge) ) {
|
|
plTrimmedPoly.EraseLastUPoint() ;
|
|
nEdge = 3 ;
|
|
}
|
|
}
|
|
}
|
|
else if ( AreSameEdge( nEdge, 3) && AreSamePointApprox(ptLast, m_mTree[nId].GetTopRight()) ) {
|
|
vEdge = ptTl - m_mTree[nId].GetTopRight() ;
|
|
vEdge.Normalize() ;
|
|
if ( AreOppositeVectorApprox(vLast, vEdge) ) {
|
|
plTrimmedPoly.EraseLastUPoint() ;
|
|
nEdge = 0 ;
|
|
}
|
|
}
|
|
|
|
// se mi è rimasto solo un punto sulla polyline vuol dire che avevo solo un tratto parallelo ad lato
|
|
// quindi salto al prossimo loop
|
|
if ( plTrimmedPoly.GetPointNbr() == 1 ) {
|
|
plTrimmedPoly.Clear() ;
|
|
continue ;
|
|
}
|
|
if ( nEdge > 3 && nEdge != 7 ) {
|
|
nEdge = nEdge - 3 ;
|
|
}
|
|
else if ( nEdge == 7 ) {
|
|
nEdge = 0 ;
|
|
}
|
|
// se ho altri Pass vado avanti ad aggiungere vertici finché trovo il prossimo o finché non sono tornato sul lato di partenza
|
|
bool bNotCameBack = true ;
|
|
bool bValidNextStart = false ;
|
|
bool bAtNextStart = false ;
|
|
if ( w < nPassToCheck - 1) { // ho messo w al posto di j ////////////////////////////////////////////////////////////////////////////////////////
|
|
int nSecondCheck = 0 ;
|
|
int nNext ;
|
|
// ciclo sui loop successivi per vedere se ne ho uno con un valid start
|
|
for ( int t = w + 1 ; t < nPassToCheck ; ++ t) {
|
|
bValidNextStart = CheckIfBetween( m_mTree[nId].m_vInters[j], m_mTree[nId].m_vInters[vToCheckNow[t]]) ;
|
|
if ( bValidNextStart) {
|
|
nNext = t ;
|
|
bAtNextStart = AreSameEdge( m_mTree[nId].m_vInters[j].nOut, m_mTree[nId].m_vInters[vToCheckNow[t]].nIn) ;
|
|
break ;
|
|
}
|
|
else {
|
|
++ nSecondCheck ;
|
|
vToCheck.push_back( vToCheckNow[t]) ;
|
|
}
|
|
}
|
|
|
|
bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ;
|
|
|
|
while ( ! ( bValidNextStart && bAtNextStart) && bNotCameBack) {
|
|
Point3d ptVert ;
|
|
if ( nEdge == 0)
|
|
ptVert = ptTl ;
|
|
else if ( nEdge == 1)
|
|
ptVert = m_mTree[nId].GetBottomLeft() ;
|
|
else if ( nEdge == 2)
|
|
ptVert = ptBr ;
|
|
else if ( nEdge == 3)
|
|
ptVert = m_mTree[nId].GetTopRight() ;
|
|
AddVertex( nId, vEdgeVertex, plTrimmedPoly, c, ptVert) ;
|
|
if ( nEdge > 3 && nEdge != 7)
|
|
nEdge = nEdge - 4 ;
|
|
else if ( nEdge < 3 )
|
|
++ nEdge ;
|
|
else
|
|
nEdge = 0 ;
|
|
|
|
// aggiorno le condizioni per il while
|
|
if ( bValidNextStart)
|
|
bAtNextStart = AreSameEdge( nEdge, m_mTree[nId].m_vInters[vToCheckNow[nNext]].nIn) ;
|
|
|
|
bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ;
|
|
}
|
|
// se ho trovato un altro loop salto all'inizio del for
|
|
if ( bValidNextStart) {
|
|
w = w + nSecondCheck ;
|
|
continue ;
|
|
}
|
|
}
|
|
// non ho altri loop quindi aggiungo vertici finché torno al punto di partenza
|
|
else {
|
|
bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ;
|
|
|
|
while ( bNotCameBack) {
|
|
Point3d ptVert ;
|
|
if ( nEdge == 0)
|
|
ptVert = ptTl ;
|
|
else if ( nEdge == 1)
|
|
ptVert = m_mTree[nId].GetBottomLeft() ;
|
|
else if ( nEdge == 2)
|
|
ptVert = ptBr ;
|
|
else if ( nEdge == 3)
|
|
ptVert = m_mTree[nId].GetTopRight() ;
|
|
AddVertex( nId, vEdgeVertex, plTrimmedPoly, c, ptVert) ;
|
|
if ( nEdge > 3 && nEdge != 7)
|
|
nEdge = nEdge - 4 ;
|
|
else if ( nEdge < 3 )
|
|
++ nEdge ;
|
|
else
|
|
nEdge = 0 ;
|
|
// aggiorno le condizioni per il while
|
|
bNotCameBack = ! ( AreSameEdge( nEdge, nEdgeIn) && CheckIfBefore( plTrimmedPoly, nEdge)) ;
|
|
}
|
|
}
|
|
plTrimmedPoly.Close() ;
|
|
double dArea ;
|
|
plTrimmedPoly.GetAreaXY( dArea) ;
|
|
if ( dArea > SQ_EPS_SMALL) {
|
|
vCellPolygons.push_back( plTrimmedPoly) ;
|
|
vPolygons.push_back( vCellPolygons) ;
|
|
++ nPoly ;
|
|
vnParentChunk.push_back( inA.nChunk) ;
|
|
vCellPolygons.clear() ;
|
|
}
|
|
c = 0 ;
|
|
plTrimmedPoly.Clear() ;
|
|
nEdgeIn = -1 ;
|
|
// devo verificare se tra i loop che sono finiti in vToCheck in realtà qualcuno l'ho usato per fare un poligono/////////////////////////////////////
|
|
for ( int k = 0 ; k < (int)vToCheck.size() ; ++ k) {
|
|
for ( int i = 0 ; i < (int)vAddedLoops.size() ; ++ i) {
|
|
if ( vToCheck[k] == vAddedLoops[i] ) {
|
|
vToCheck.erase(vToCheck.begin() + k) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
continue ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Tree::CreateIslandAndHoles( int nLeafId, std::vector<POLYLINEVECTOR>& vPolygons, int& nPoly, INTVECTOR& vnParentChunk)
|
|
{
|
|
// vettore dei poligoni ( loop) della cella nId
|
|
POLYLINEVECTOR vCellPolygons ;
|
|
// costruisco i poligoni partendo dal vettore delle intersezioni, come spiegato a pag15 di Cripps
|
|
int nId = m_vnLeaves[nLeafId] ;
|
|
PolyLine plTrimmedPoly ;
|
|
// numero di volte che la cella è stata attraversata da una curva di trim
|
|
int nPass = (int) m_mTree[nId].m_vInters.size() ;
|
|
// numero di vertici aggiunti al nuovo poligono
|
|
int c = 0 ;
|
|
|
|
// loop interni in una cella intersecata
|
|
if ( m_mTree[nId].m_nFlag == 3 || m_mTree[nId].m_nFlag == 2) {
|
|
PolyLine plInLoop ;
|
|
// numero dei loop interni passati
|
|
int n = 0 ;
|
|
Inters inA = m_mTree[nId].m_vInters[n] ;
|
|
// se ho almeno un loop CW che non è contenuto in un altro poligono o in un loop interno CCW
|
|
bool bAllCW = true ;
|
|
for ( Inters inB : m_mTree[nId].m_vInters) {
|
|
if ( inB.nIn == -1){
|
|
if ( inB.bCCW) {
|
|
bAllCW = false ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
// la seconda condizione è da cambiareeeeeeeeeeeeeeeeeeeee////////////////////////////////////////////////////////////////////////////////////////////
|
|
if ( m_mTree[nId].m_nFlag == 2 && ! inA.bCCW) {
|
|
// i loop esterni sono CW, quindi prima dei loop di trim aggiungo il bordo cella
|
|
Point3d ptVert = m_mTree[nId].GetTopRight() ;
|
|
plInLoop.AddUPoint( 0, ptVert) ;
|
|
ptVert.x = m_mTree[nId].GetBottomLeft().x ;
|
|
ptVert.y = m_mTree[nId].GetTopRight().y ;
|
|
plInLoop.AddUPoint( 1, ptVert) ;
|
|
ptVert = m_mTree[nId].GetBottomLeft() ;
|
|
plInLoop.AddUPoint( 2, ptVert) ;
|
|
ptVert.x = m_mTree[nId].GetTopRight().x ;
|
|
ptVert.y = m_mTree[nId].GetBottomLeft().y ;
|
|
plInLoop.AddUPoint( 3, ptVert) ;
|
|
plInLoop.Close();
|
|
vCellPolygons.push_back( plInLoop) ;
|
|
vPolygons.push_back( vCellPolygons) ;
|
|
++ nPoly ;
|
|
vnParentChunk.push_back( inA.nChunk) ;
|
|
vCellPolygons.clear() ;
|
|
plInLoop.Clear() ;
|
|
}
|
|
while ( inA.nIn == -1) {
|
|
// numero di vertici aggiunti al nuovo poligono
|
|
int k = 0 ;
|
|
for ( Point3d ptInt : inA.vpt) {
|
|
plInLoop.AddUPoint( k, ptInt) ;
|
|
++ k ;
|
|
}
|
|
plInLoop.Close();
|
|
bool bAdded = false ;
|
|
// se il loop è CW devo controllare in quale altro dei poligoni che ho già aggiunto è contenuto
|
|
if ( ! inA.bCCW) {
|
|
Point3d ptStart ;
|
|
plInLoop.GetFirstPoint( ptStart) ;
|
|
int nOtherPoly = (int)vPolygons.size() ;
|
|
for ( int r = 0 ; r < nPoly ; ++r ) {
|
|
if ( IsPointInsidePolyLine( ptStart, vPolygons[nOtherPoly - r - 1][0], -0.01) && vnParentChunk[nPoly - r - 1] == inA.nChunk ) {
|
|
vPolygons[nOtherPoly - r - 1].push_back( plInLoop) ;
|
|
plInLoop.Clear() ;
|
|
vnParentChunk.push_back( inA.nChunk) ;
|
|
bAdded = true ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
if ( ! bAdded ) {
|
|
vCellPolygons.push_back( plInLoop) ;
|
|
vPolygons.push_back( vCellPolygons) ;
|
|
++ nPoly ;
|
|
vnParentChunk.push_back( inA.nChunk) ;
|
|
plInLoop.Clear() ;
|
|
vCellPolygons.clear() ;
|
|
}
|
|
|
|
plInLoop.Clear() ;
|
|
++ n ;
|
|
inA = m_mTree[nId].m_vInters[n] ;
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Tree::CheckIfBefore( PolyLine& pl, int nEdge) const
|
|
{
|
|
// controllo se ptEnd è prima di ptStart sul lato nEdge rispetto al senso antiorario ( quindi se è dopo in senso orario)
|
|
Point3d ptStart, ptEnd ;
|
|
pl.GetFirstPoint( ptStart) ;
|
|
pl.GetLastPoint( ptEnd) ;
|
|
if ( nEdge == 0 ) {
|
|
return ptEnd.x > ptStart.x ;
|
|
}
|
|
else if ( nEdge == 1 ) {
|
|
return ptEnd.y > ptStart.y ;
|
|
}
|
|
else if ( nEdge == 2 ) {
|
|
return ptEnd.x < ptStart.x ;
|
|
}
|
|
else if ( nEdge == 3 ) {
|
|
return ptEnd.y < ptStart.y ;
|
|
}
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Tree::CheckIfBefore( Inters& inA) const
|
|
{
|
|
// controllo se l'ingresso è prima dell'uscita
|
|
int nEdge1 = inA.nIn ;
|
|
int nEdge2 = inA.nOut ;
|
|
PolyLine pl ;
|
|
pl.AddUPoint( 0, inA.vpt.back()) ;
|
|
pl.AddUPoint( 1, inA.vpt[0]) ;
|
|
INTVECTOR vEdges = { 7, 0, 4, 1, 5, 2, 6} ;
|
|
// controllo se nEdge1 viene prima di nEdge2. la partenza è da ptTR e l'arrivo è ptBr
|
|
|
|
INTVECTOR :: iterator iter1 = find( vEdges.begin(), vEdges.end(), nEdge1) ;
|
|
int nPos1 = std::distance( vEdges.begin(), iter1) ;
|
|
INTVECTOR :: iterator iter2 = find( vEdges.begin(), vEdges.end(), nEdge2) ;
|
|
int nPos2 = std::distance( vEdges.begin(), iter2) ;
|
|
if ( nPos1 < nPos2)
|
|
return true ;
|
|
else if ( nPos1 > nPos2)
|
|
return false ;
|
|
// nPos1 == nPos2
|
|
else {
|
|
if ( CheckIfBefore( pl, vEdges[nPos1])) {
|
|
return true ;
|
|
}
|
|
else
|
|
return false ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Tree::CheckIfBefore( int& nEdge1, Point3d& ptP1, int& nEdge2, Point3d& ptP2) const
|
|
{
|
|
INTVECTOR vEdges = { 7, 0, 4, 1, 5, 2, 6} ;
|
|
// controllo se ptP1, che è su nEdge1, viene prima di ptP2, che è su nEdge2. la partenza è da ptTR e l'arrivo è ptBr
|
|
INTVECTOR :: iterator iter1 = find( vEdges.begin(), vEdges.end(), nEdge1) ;
|
|
int nPos1 = std::distance( vEdges.begin(), iter1) ;
|
|
INTVECTOR :: iterator iter2 = find( vEdges.begin(), vEdges.end(), nEdge2) ;
|
|
int nPos2 = std::distance( vEdges.begin(), iter2) ;
|
|
if ( nPos1 < nPos2)
|
|
return true ;
|
|
else if ( nPos1 > nPos2)
|
|
return false ;
|
|
// ( nPos1 == nPos2)
|
|
else {
|
|
PolyLine pl ;
|
|
pl.AddUPoint( 0, ptP2) ;
|
|
pl.AddUPoint( 1, ptP1) ;
|
|
if ( CheckIfBefore( pl, vEdges[nPos1]))
|
|
return true ;
|
|
else
|
|
return false ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Tree::CheckIfBefore( int& nEdge, Point3d& ptP1, Point3d& ptP2) const
|
|
{
|
|
// sul lato nEdge controllo se ptP1 viene prima di ptP2.
|
|
// i lati vengono percorsi in senso antiorario
|
|
if ( nEdge == 0 ) {
|
|
return ptP1.x > ptP2.x ;
|
|
}
|
|
else if ( nEdge == 1 ) {
|
|
return ptP1.y > ptP2.y ;
|
|
}
|
|
else if ( nEdge == 2 ) {
|
|
return ptP1.x < ptP2.x ;
|
|
}
|
|
else if ( nEdge == 3 ) {
|
|
return ptP1.y < ptP2.y ;
|
|
}
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Tree::CheckIfAfter( PolyLine& pl, Point3d& ptNextStart, int nEdge) const
|
|
{
|
|
// controllo se ptNextStart è più avanti rispetto a ptEnd in senso antiorario
|
|
// ATTENZIONE i due punti devono essere sullo stesso lato!
|
|
|
|
// se i punti non sono sullo stesso lato ritorno false
|
|
Point3d ptEnd ;
|
|
pl.GetLastPoint( ptEnd) ;
|
|
if ( nEdge == 0 ) {
|
|
if ( ptNextStart.y > ptEnd.y - EPS_SMALL && ptNextStart.y < ptEnd.y + EPS_SMALL)
|
|
return ptEnd.x > ptNextStart.x ;
|
|
else
|
|
return false ;
|
|
}
|
|
else if ( nEdge == 1 ) {
|
|
if ( ptNextStart.x > ptEnd.x - EPS_SMALL && ptNextStart.x < ptEnd.x + EPS_SMALL)
|
|
return ptEnd.y > ptNextStart.y ;
|
|
else
|
|
return false ;
|
|
}
|
|
else if ( nEdge == 2 ) {
|
|
if ( ptNextStart.y > ptEnd.y - EPS_SMALL && ptNextStart.y < ptEnd.y + EPS_SMALL)
|
|
return ptEnd.x < ptNextStart.x ;
|
|
else
|
|
return false ;
|
|
}
|
|
else if ( nEdge == 3 ) {
|
|
if ( ptNextStart.x > ptEnd.x - EPS_SMALL && ptNextStart.x < ptEnd.x + EPS_SMALL)
|
|
return ptEnd.y < ptNextStart.y ;
|
|
else
|
|
return false ;
|
|
}
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Tree::AreSameEdge( int nEdge1, int nEdge2) const
|
|
{
|
|
if ( nEdge1 == 0) {
|
|
if ( nEdge2 == 4 || nEdge2 == 0 || nEdge2 == 7)
|
|
return true;
|
|
else
|
|
return false ;
|
|
}
|
|
else if ( nEdge1 == 1) {
|
|
if ( nEdge2 == 4 || nEdge2 == 1 || nEdge2 == 5)
|
|
return true;
|
|
else
|
|
return false ;
|
|
}
|
|
else if ( nEdge1 == 2) {
|
|
if ( nEdge2 == 6 || nEdge2 == 2 || nEdge2 == 5)
|
|
return true;
|
|
else
|
|
return false ;
|
|
}
|
|
else if ( nEdge1 == 3) {
|
|
if ( nEdge2 == 6 || nEdge2 == 3 || nEdge2 == 7)
|
|
return true;
|
|
else
|
|
return false ;
|
|
}
|
|
else if ( nEdge1 == 4) {
|
|
if ( nEdge2 == 0 || nEdge2 == 1 || nEdge2 == 7 || nEdge2 == 5)
|
|
return true;
|
|
else
|
|
return false ;
|
|
}
|
|
else if ( nEdge1 == 5) {
|
|
if ( nEdge2 == 2 || nEdge2 == 1 || nEdge2 == 4 || nEdge2 == 6)
|
|
return true;
|
|
else
|
|
return false ;
|
|
}
|
|
else if ( nEdge1 == 6) {
|
|
if ( nEdge2 == 2 || nEdge2 == 3 || nEdge2 == 5 || nEdge2 == 7)
|
|
return true;
|
|
else
|
|
return false ;
|
|
}
|
|
else if ( nEdge1 == 7) {
|
|
if ( nEdge2 == 0 || nEdge2 == 3 || nEdge2 == 4 || nEdge2 == 6)
|
|
return true;
|
|
else
|
|
return false ;
|
|
}
|
|
else
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Tree::AddVertex( int nId, std::vector<PNTVECTOR>& vEdgeVertex, PolyLine& plTrimmedPoly, int& c, Point3d& ptToAdd) const
|
|
{
|
|
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) ;
|
|
Point3d ptBL = m_mTree.at(nId).GetBottomLeft() ;
|
|
Point3d ptTR = m_mTree.at(nId).GetTopRight() ;
|
|
Point3d ptLast ;
|
|
plTrimmedPoly.GetLastPoint( ptLast) ;
|
|
// verifico di essere allineato con un lato, sennò aggiungo e basta
|
|
Vector3d vDir = ptToAdd - ptLast ;
|
|
vDir.Normalize() ;
|
|
if ( abs( vDir.x) > 1 - EPS_SMALL || abs( vDir.y) > 1 - EPS_SMALL) {
|
|
// se su un edge devo fare dei controlli
|
|
// edge 0
|
|
if ( ptToAdd.x >= ptBL.x && ptToAdd.x <= ptTR.x && ptToAdd.y == ptTR.y && abs(vDir.x) > 1 - EPS_SMALL) {
|
|
for ( int t = 0 ; t < (int)vEdgeVertex[0].size() ; ++ t) {
|
|
Point3d ptIntermed = vEdgeVertex[0][t] ;
|
|
if ( ptIntermed.x > ptToAdd.x && ptIntermed.x < ptLast.x) {
|
|
plTrimmedPoly.AddUPoint( c, ptIntermed) ;
|
|
++ c ;
|
|
}
|
|
else
|
|
break ;
|
|
}
|
|
plTrimmedPoly.AddUPoint( c, ptToAdd) ;
|
|
++ c ;
|
|
}
|
|
// edge 1
|
|
else if ( ptToAdd.y >= ptBL.y && ptToAdd.y <= ptTR.y && ptToAdd.x == ptBL.x && abs(vDir.y) > 1 - EPS_SMALL) {
|
|
for ( int t = 0 ; t < (int)vEdgeVertex[1].size() ; ++ t) {
|
|
Point3d ptIntermed = vEdgeVertex[1][t] ;
|
|
if ( ptIntermed.y > ptToAdd.y && ptIntermed.y < ptLast.y) {
|
|
plTrimmedPoly.AddUPoint( c, ptIntermed) ;
|
|
++ c ;
|
|
}
|
|
else
|
|
break ;
|
|
}
|
|
plTrimmedPoly.AddUPoint( c, ptToAdd) ;
|
|
++ c ;
|
|
}
|
|
// edge 2
|
|
else if ( ptToAdd.x >= ptBL.x && ptToAdd.x <= ptTR.x && ptToAdd.y == ptBL.y && abs(vDir.x) > 1 - EPS_SMALL) {
|
|
for ( int t = 0 ; t < (int)vEdgeVertex[2].size() ; ++ t) {
|
|
Point3d ptIntermed = vEdgeVertex[2][t] ;
|
|
if ( ptIntermed.x < ptToAdd.x && ptIntermed.x > ptLast.x) {
|
|
plTrimmedPoly.AddUPoint( c, ptIntermed) ;
|
|
++ c ;
|
|
}
|
|
else
|
|
break ;
|
|
}
|
|
plTrimmedPoly.AddUPoint( c, ptToAdd) ;
|
|
++ c ;
|
|
}
|
|
// edge 3
|
|
else if ( ptToAdd.y >= ptBL.y && ptToAdd.y <= ptTR.y && ptToAdd.x == ptTR.x && abs(vDir.y) > 1 - EPS_SMALL) {
|
|
for ( int t = 0 ; t < (int)vEdgeVertex[3].size() ; ++ t) {
|
|
Point3d ptIntermed = vEdgeVertex[3][t] ;
|
|
if ( ptIntermed.y < ptToAdd.y && ptIntermed.y > ptLast.y) {
|
|
plTrimmedPoly.AddUPoint( c, ptIntermed) ;
|
|
++ c ;
|
|
}
|
|
else
|
|
break ;
|
|
}
|
|
plTrimmedPoly.AddUPoint( c, ptToAdd) ;
|
|
++ c ;
|
|
}
|
|
// sono allineato con un lato, ma NON sono su un lato
|
|
// aggiungo e basta
|
|
else {
|
|
plTrimmedPoly.AddUPoint( c, ptToAdd);
|
|
++ c ;
|
|
}
|
|
}
|
|
// non su un edge, quindi aggiungo e basta
|
|
else {
|
|
plTrimmedPoly.AddUPoint( c, ptToAdd);
|
|
++ c ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
////----------------------------------------------------------------------------
|
|
//bool
|
|
//Tree::SetRightEdgeIn( int nId, std::vector<PNTVECTOR>& vEdgeVertex, PolyLine& plTrimmedPoly)
|
|
//{
|
|
// Point3d ptBr( m_mTree.at(nId).GetTopRight().x , m_mTree.at(nId).GetBottomLeft().y) ;
|
|
// Point3d ptTR = m_mTree.at(nId).GetTopRight() ;
|
|
// int nPos0 = -1 , nPos1 = -1 ;
|
|
// bool bSave = false ;
|
|
// PNTLIST lPtInt ;
|
|
// for ( int k = 0 ; k < plTrimmedPoly.GetPointNbr() ; ++ k) {
|
|
// Point3d ptIter ;
|
|
// plTrimmedPoly. GetNextPoint( ptIter) ;
|
|
// if ( AreSamePointExact( ptIter, ptBr) ) {
|
|
// nPos0 = k ;
|
|
// bSave = bSave ^ true ;
|
|
// }
|
|
// if ( AreSamePointExact( ptIter, ptTR) ) {
|
|
// nPos1 = k ;
|
|
// bSave = bSave ^ true ;
|
|
// }
|
|
// if ( bSave) {
|
|
// lPtInt.push_back( ptIter) ;
|
|
// }
|
|
// }
|
|
// lPtInt.pop_front() ;
|
|
// // verifico se ci sono tutti e due i punti
|
|
// if ( nPos0 != -1 && nPos1 != -1 ) {
|
|
// // se sono di seguito tutto il lato destro è dentro
|
|
// if ( nPos1 == nPos0 + 1 || nPos0 == nPos1 + 1) {
|
|
// m_mTree[nId].m_nRightEdgeIn = 1 ;
|
|
// }
|
|
// // ci sono dei punti in mezzo, devo capire se sono allineati o no
|
|
// else {
|
|
// // verifico se tutti i punti intermedi sono allineati o no
|
|
// CurveLine clRightEdge ;
|
|
// clRightEdge.Set( ptBr, ptTR) ;
|
|
// bool bAllOn = true ;
|
|
//
|
|
// PNTLIST::iterator lIter = lPtInt.begin() ;
|
|
// std::advance(lIter, 0) ;
|
|
// for ( int p = 0 ; p < (int)lPtInt.size() ; ++ p) {
|
|
// if ( ! clRightEdge.IsPointOn( *lIter)) {
|
|
// bAllOn = false ;
|
|
// break ;
|
|
// }
|
|
// }
|
|
// // divisi da punti allineati e quindi lato dentro
|
|
// if ( bAllOn) {
|
|
// m_mTree[nId].m_nRightEdgeIn = 1 ;
|
|
// }
|
|
// // se sono dentro, ma non allineati, allora solo in parte
|
|
// else {
|
|
// m_mTree[nId].m_nRightEdgeIn = 2 ;
|
|
// }
|
|
// }
|
|
// }
|
|
// // il lato destro è sicuramente esterno
|
|
// else {
|
|
// m_mTree[nId].m_nRightEdgeIn = 0 ;
|
|
// }
|
|
// return true ;
|
|
//}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Tree::SetRightEdgeIn( int nId)
|
|
{
|
|
Point3d ptBr( m_mTree.at(nId).GetTopRight().x , m_mTree.at(nId).GetBottomLeft().y) ;
|
|
Point3d ptTR = m_mTree.at(nId).GetTopRight() ;
|
|
// se ho inters sul lato destro allora in parte è dentro
|
|
int nPass = (int) m_mTree[nId].m_vInters.size() ;
|
|
bool bDone = false ;
|
|
for ( int k = 0 ; k < nPass ; ++ k) {
|
|
if ( m_mTree[nId].m_vInters[k].nIn == 3 || m_mTree[nId].m_vInters[k].nOut == 3) {
|
|
m_mTree[nId].m_nRightEdgeIn = 2 ;
|
|
bDone = true ;
|
|
break ;
|
|
}
|
|
// considero anche ingressi/ uscite dai vertici 6 e 7
|
|
// controllo nei vertici
|
|
if ( m_mTree[nId].m_vInters[k].nOut == 6 && m_mTree[nId].m_vInters[k].nIn == 7) {
|
|
m_mTree[nId].m_nRightEdgeIn = 1 ;
|
|
bDone = true ;
|
|
break ;
|
|
}
|
|
if ( m_mTree[nId].m_vInters[k].nOut == 7 && m_mTree[nId].m_vInters[k].nIn == 6 ) {
|
|
m_mTree[nId].m_nRightEdgeIn = 0 ;
|
|
bDone = true ;
|
|
break ;
|
|
}
|
|
/*if ( AreSameEdge( m_mTree[nId].m_vInters[k].nIn, 3) || AreSameEdge( m_mTree[nId].m_vInters[k].nOut, 3) ) {
|
|
m_mTree[nId].m_nRightEdgeIn = 2 ;
|
|
bDone = true ;
|
|
break ;
|
|
}*/
|
|
}
|
|
// se non ho inters sul lato destro devo verificare se è tutto dentro o tutto fuori
|
|
if ( ! bDone) {
|
|
// ciclo sulle inters e cerco quella più a destra, se ha un'uscita più bassa di un'entrata allora il right edge è compreso!
|
|
bool bFound = false ;
|
|
bool bRightMost = false ;
|
|
int nEdgeIn = 6, nEdgeOut = 7, nLoop ;
|
|
Point3d ptIn, ptOut ;
|
|
ptIn = ptOut = m_mTree[nId].GetBottomLeft() ;
|
|
for ( int k = 0 ; k < nPass ; ++ k) {
|
|
// trovo il loop che ha l'ingresso o l'uscita più a destra
|
|
if ( CheckIfBefore( m_mTree[nId].m_vInters[k].nIn, m_mTree[nId].m_vInters[k].vpt[0], nEdgeIn, ptIn) ||
|
|
CheckIfBefore( nEdgeOut, ptOut, m_mTree[nId].m_vInters[k].nOut, m_mTree[nId].m_vInters[k].vpt.back())) {
|
|
nLoop = k ;
|
|
nEdgeIn = m_mTree[nId].m_vInters[k].nIn ;
|
|
ptIn = m_mTree[nId].m_vInters[k].vpt[0] ;
|
|
nEdgeOut = m_mTree[nId].m_vInters[k].nOut ;
|
|
ptOut = m_mTree[nId].m_vInters[k].vpt.back() ;
|
|
bFound = true ;
|
|
}
|
|
}
|
|
if ( bFound && CheckIfBefore( m_mTree[nId].m_vInters[nLoop])) {
|
|
bRightMost = true ;
|
|
}
|
|
// se il mio campione attraversa dall'alto al basso allora il lato destro è dentro!!!
|
|
if ( bFound && bRightMost)
|
|
m_mTree[nId].m_nRightEdgeIn = 1 ;
|
|
else
|
|
m_mTree[nId].m_nRightEdgeIn = 0 ;
|
|
|
|
}
|
|
|
|
if ( m_mTree[nId].m_nRightEdgeIn != -1)
|
|
return true ;
|
|
else
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Tree::CategorizeCell( int& nId)
|
|
{
|
|
if ( m_mTree[nId].m_nFlag != -1) {
|
|
return true ;
|
|
}
|
|
INTVECTOR vNeigh, vNeigh1 ;
|
|
GetLeftNeigh( nId, vNeigh) ;
|
|
// mi servono i vicini di sinistra per capire se sono dentro il loop o fuori
|
|
// nRightEdgeIn // 0 right edge fuori, 1 right edge dentro, 2 metà e metà
|
|
// nFlag // 0 fuori, 1 intersecata, 2 contiene loop, 3 = 1 & 2, 4 dentro
|
|
if ( (int)vNeigh.size() == 0 ) {
|
|
m_mTree[nId].m_nFlag = 0 ;
|
|
}
|
|
else if ( (int)vNeigh.size() == 1) {
|
|
if ( m_mTree[vNeigh[0]].m_nRightEdgeIn == 1)
|
|
m_mTree[nId].m_nFlag = 4 ;
|
|
else if ( m_mTree[vNeigh[0]].m_nRightEdgeIn == 0)
|
|
// devo verificare se la cella è intersecata
|
|
if ( m_mTree[vNeigh[0]].m_nFlag == 1 || m_mTree[vNeigh[0]].m_nFlag == 3)
|
|
m_mTree[nId].m_nFlag = 0 ;
|
|
else {
|
|
if ( m_mTree[vNeigh[0]].m_nFlag == 4) {
|
|
m_mTree[nId].m_nFlag = 4 ;
|
|
}
|
|
else if ( m_mTree[vNeigh[0]].m_nFlag == 0) {
|
|
m_mTree[nId].m_nFlag = 0 ;
|
|
}
|
|
}
|
|
// se solo parte del right edge del vicino è compreso, allora devo verificare se la cella è contenuta o no
|
|
// guardando nFlag del vicino bottom, che è già categorizzato!
|
|
else if ( m_mTree[vNeigh[0]].m_nRightEdgeIn == 2 ) {
|
|
GetBottomNeigh( nId, vNeigh1) ;
|
|
int nNeigh = vNeigh1[0] ;
|
|
if ( m_mTree[nNeigh].m_nFlag == 0 || m_mTree[nNeigh].m_nFlag == 2) {
|
|
m_mTree[nId].m_nFlag = 0 ;
|
|
}
|
|
else if ( m_mTree[nNeigh].m_nFlag == 4) {
|
|
m_mTree[nId].m_nFlag = 4 ;
|
|
}
|
|
else if ( m_mTree[nNeigh].m_nFlag == 1 || m_mTree[nNeigh].m_nFlag == 3) {
|
|
if ( m_mTree[nNeigh].m_nRightEdgeIn == 0)
|
|
m_mTree[nId].m_nFlag = 0 ;
|
|
else if ( m_mTree[nNeigh].m_nRightEdgeIn == 1)
|
|
m_mTree[nId].m_nFlag = 4 ;
|
|
else if ( m_mTree[nNeigh].m_nRightEdgeIn == 2 ) {
|
|
// in questo caso devo verificare le intersezioni sul lato destro del vicino bottom
|
|
// scorro e cerco l'intersezione più alta, se è out la cella è dentro, se è in devo verificare l'out se è più a sinistra o a destra.
|
|
int nPass = (int) m_mTree[nNeigh].m_vInters.size() ;
|
|
bool bTopMost = false ;
|
|
bool bFound = false;
|
|
Point3d ptInters, ptBr( m_mTree[nNeigh].GetTopRight().x, m_mTree[nNeigh].GetBottomLeft().y) ;
|
|
ptInters = ptBr ; // inizializzato a vertice bottom right
|
|
int nEdgeIn = 3, nEdgeOut = 3, nLoop ;
|
|
for ( int r = 0 ; r < nPass; ++ r ) {
|
|
// trovo il loop che ha l'ingresso o l'uscita più in alto sul lato destro
|
|
// verifico che o l'ingresso o l'uscita siano sul lato destro e che sia l'intersezione più alta su quel lato
|
|
if ( m_mTree[nNeigh].m_vInters[r].nIn == 3 && ! CheckIfBefore( m_mTree[nNeigh].m_vInters[r].nIn, m_mTree[nNeigh].m_vInters[r].vpt[0], ptInters)) {
|
|
nLoop = r ;
|
|
ptInters = m_mTree[nNeigh].m_vInters[r].vpt[0] ;
|
|
bFound = true ;
|
|
}
|
|
if ( m_mTree[nNeigh].m_vInters[r].nOut == 3 && ! CheckIfBefore( m_mTree[nNeigh].m_vInters[r].nOut, m_mTree[nNeigh].m_vInters[r].vpt.back(), ptInters)) {
|
|
nLoop = r ;
|
|
ptInters = m_mTree[nNeigh].m_vInters[r].vpt.back() ;
|
|
bFound = true ;
|
|
}
|
|
// controllo nei vertici
|
|
if ( m_mTree[nNeigh].m_vInters[r].nOut == 7 || m_mTree[nNeigh].m_vInters[r].nIn == 7) {
|
|
nLoop = r ;
|
|
ptInters = m_mTree[nNeigh].GetTopRight() ;
|
|
bFound = true ;
|
|
break ;
|
|
}
|
|
if ( m_mTree[nNeigh].m_vInters[r].nOut == 6 || m_mTree[nNeigh].m_vInters[r].nIn == 6 ) {
|
|
nLoop = r ;
|
|
ptInters = ptBr ;
|
|
bFound = true ;
|
|
}
|
|
}
|
|
if ( bFound && CheckIfBefore( m_mTree[nNeigh].m_vInters[nLoop])) {
|
|
bTopMost = true ;
|
|
}
|
|
if ( bFound && bTopMost) {
|
|
if ( AreSameEdge(m_mTree[nNeigh].m_vInters[nLoop].nIn, 3) && AreSameEdge(m_mTree[nNeigh].m_vInters[nLoop].nOut, 3) ) {
|
|
if ( CheckIfBefore( m_mTree[nNeigh].m_vInters[nLoop]))
|
|
m_mTree[nId].m_nFlag = 4 ;
|
|
else
|
|
m_mTree[nId].m_nFlag = 0 ;
|
|
}
|
|
else if ( AreSameEdge(m_mTree[nNeigh].m_vInters[nLoop].nOut, 3))
|
|
m_mTree[nId].m_nFlag = 4 ;
|
|
else if ( AreSameEdge(m_mTree[nNeigh].m_vInters[nLoop].nIn, 3) ) {
|
|
// devo verificare se il l'uscita è più a sinistra o più a destra della cella
|
|
Point3d ptOut = m_mTree[nNeigh].m_vInters[nLoop].vpt.back() ;
|
|
Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ;
|
|
if ( ptOut.x >= ptBr.x)
|
|
m_mTree[nId].m_nFlag = 4 ;
|
|
else
|
|
m_mTree[nId].m_nFlag = 0 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for ( int r = 0 ; r < (int)vNeigh.size() ; ++ r) {
|
|
if ( m_mTree[vNeigh[r]].m_nRightEdgeIn == 1) {
|
|
m_mTree[nId].m_nFlag = 4 ;
|
|
break ;
|
|
}
|
|
else if ( m_mTree[vNeigh[r]].m_nRightEdgeIn == 0) {
|
|
m_mTree[nId].m_nFlag = 0 ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Tree::CheckIfBetween( Inters& inA, Inters& inB) const
|
|
{
|
|
// controllo se inB è compreso tra l'end e lo start di inA
|
|
// ( dall'end di A percorro i bordi della cella fino a tornare allo start e devo incontrare In e Out di B)
|
|
INTVECTOR vEdges ;
|
|
int nEdge = inA.nOut ;
|
|
while ( nEdge != inA.nIn || (int) vEdges.size() == 0) {
|
|
vEdges.push_back( nEdge) ;
|
|
if ( nEdge == 3)
|
|
nEdge = 0 ;
|
|
else
|
|
++ nEdge ;
|
|
}
|
|
if ( inA.nIn != inA.nOut)
|
|
vEdges.push_back( nEdge) ;
|
|
bool bFound = false ;
|
|
for ( int i : vEdges) {
|
|
if ( AreSameEdge(inB.nIn, i)) {
|
|
if ( AreSameEdge(inB.nIn, inA.nIn) && AreSameEdge(inA.nIn, inA.nOut)) {
|
|
nEdge = inA.nIn ;
|
|
//se l'inizio di A è prima della fine, allora devo controllare che B sia compreso tra Out e In (esterno)
|
|
if ( CheckIfBefore( nEdge, inA.vpt[0], inA.vpt.back()) ) {
|
|
if ( CheckIfBefore( nEdge, inA.vpt.back(), inB.vpt[0]) || CheckIfBefore( nEdge, inB.vpt[0], inA.vpt[0]))
|
|
bFound = true ;
|
|
}
|
|
// se l'inizio di A è dopo la fine, allora devo controllare che B sia compreso tra In e Out ( interno)
|
|
else {
|
|
if ( CheckIfBefore( nEdge, inA.vpt.back(), inB.vpt[0]) && CheckIfBefore( nEdge, inB.vpt[0], inA.vpt[0]))
|
|
bFound = true ;
|
|
}
|
|
}
|
|
else if ( AreSameEdge(inB.nIn, inA.nOut)) {
|
|
PolyLine pl ;
|
|
pl.AddUPoint( 0, inA.vpt[0]) ;
|
|
pl.AddUPoint( 1, inA.vpt.back()) ;
|
|
if ( CheckIfAfter( pl, inB.vpt[0], i))
|
|
bFound = true ;
|
|
}
|
|
else if ( AreSameEdge(inB.nIn, inA.nIn)) {
|
|
//devo controllare il loop b sia prima dell'inizio di A
|
|
if ( CheckIfBefore(inA.nIn, inB.vpt[0], inA.nIn, inA.vpt[0]))
|
|
bFound = true ;
|
|
}
|
|
else
|
|
// devo controllare che inB sia prima di OutB
|
|
if ( AreSameEdge(inB.nOut, inB.nIn) && CheckIfBefore( inB.nOut, inB.vpt[0], inB.vpt.back())) {
|
|
bFound = true ;
|
|
}
|
|
else if ( ! AreSameEdge(inB.nOut,inB.nIn))
|
|
bFound = true ;
|
|
}
|
|
if ( AreSameEdge(inB.nOut, i) && ! bFound && CheckIfBefore(i, inA.vpt[0], inB.vpt.back()) && CheckIfBefore(i, inA.vpt.back(), inB.vpt.back()))
|
|
break ;
|
|
}
|
|
return bFound ;
|
|
}
|