EgtGeomKernel :

- risolti vari bug
- ridotto il calcolo del tree alle bbox delle curve di trim
This commit is contained in:
Daniele Bariletti
2023-06-21 09:30:07 +02:00
parent ebda605497
commit e9c22b895b
3 changed files with 307 additions and 155 deletions
+257 -123
View File
@@ -24,6 +24,7 @@
#include "/EgtDev/Include/EGkPolyLine.h"
#include "/EgtDev/Include/EGkDistPointCurve.h"
#include "/EgtDev/Include/EGkCurve.h"
#include "DistPointCrvComposite.h"
//----------------------------------------------------------------------------
Cell::Cell( void)
@@ -77,10 +78,10 @@ Tree::Tree( void)
}
//----------------------------------------------------------------------------
Tree::Tree( const SurfBezier* pSrfBz, const bool bSplitPatches)
: m_bBilinear( false), m_bMulti( false), m_bClosed( false), m_bSplitPatches( bSplitPatches)
Tree::Tree( const SurfBezier* pSrfBz, const bool bSplitPatches, const Point3d ptMin, const Point3d ptMax)
: m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosed( false), m_bSplitPatches( true)
{
SetSurf( pSrfBz, m_bSplitPatches) ;
SetSurf( pSrfBz, bSplitPatches, ptMin, ptMax) ;
}
//----------------------------------------------------------------------------
@@ -90,8 +91,20 @@ Tree::~Tree( void)
//----------------------------------------------------------------------------
void
Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches)
Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches, const Point3d ptMin, const Point3d ptMax)
{
// pulisco i vettori membri
m_vnLeaves.clear() ;
m_vnParents.clear() ;
m_mVert.clear() ;
m_vLoop.clear() ;
m_mChunk.clear() ;
m_vPlApprox.clear() ;
m_vChunk.clear() ;
m_vPolygons.clear() ;
m_pSrfBz = pSrfBz ;
m_bSplitPatches = bSplitPatches ;
// le coordinate delle celle sono nello spazio parametrico
@@ -113,9 +126,8 @@ Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches)
INTVECTOR vChunk ;
// recupero la superficie di trim per avere accesso diretto ai loop e mantenendo le informazioni sui chunk
Frame3d frSurf ;
PtrOwner<SurfFlatRegion> pTrimReg( m_pSrfBz->GetTrimRegion()->Clone()) ;
double dLinTol = 0.01 ; // questo è riferito allo spazio parametrico perché le curve di loop sono già state riscalate!!!!!!
double dLinTol = 0.01 ; // questo è riferito allo spazio parametrico
double dAngTolDeg = 5 ;
for ( int i = 0 ; i < pTrimReg->GetChunkCount() ; ++ i) {
PtrOwner<SurfFlatRegion> pChunk( pTrimReg->CloneChunk( i)) ;
@@ -157,125 +169,225 @@ Tree::SetSurf( const SurfBezier* pSrfBz, const bool bSplitPatches)
return dArea1 > dArea2 ;}) ;
}
// salvo i vertici 3d della cella root
Point3d ptBottom ( 0, 0) ;
Point3d ptTop( nSpanU * SBZ_TREG_COEFF, nSpanV * SBZ_TREG_COEFF) ;
Cell cRoot( ptBottom, ptTop) ;
bool bLimited = false ;
if ( ! AreSamePointExact( ptMax,ORIG) && ! AreSamePointExact( ptMax,ptTop)) {
ptTop = ptMax ;
bLimited = true ;
}
m_mTree.clear() ;
Cell cRoot( ptMin, ptTop) ;
m_mTree.insert( std::pair< int, Cell>( -1, cRoot)) ;
Point3d ptP00, ptP10, ptP11, ptP01 ;
bool bOk = false ;
if ( ! bLimited) {
ptP00 = m_pSrfBz->GetControlPoint( 0, &bOk) ;
ptP10 = m_pSrfBz->GetControlPoint( nDegU * nSpanU, &bOk) ;
ptP11 = m_pSrfBz->GetControlPoint( ( nDegU * nSpanU + 1) * ( nDegV * nSpanV + 1) - 1, &bOk) ;
ptP01 = m_pSrfBz->GetControlPoint( ( nDegU * nSpanU + 1) * ( nDegV * nSpanV), &bOk) ;
}
else {
m_pSrfBz->GetPointD1D2( ptMin.x / SBZ_TREG_COEFF, ptMin.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00) ;
m_pSrfBz->GetPointD1D2( ptMax.x / SBZ_TREG_COEFF, ptMin.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10) ;
m_pSrfBz->GetPointD1D2( ptMax.x / SBZ_TREG_COEFF, ptMax.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11) ;
m_pSrfBz->GetPointD1D2( ptMin.x / SBZ_TREG_COEFF, ptMax.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01) ;
}
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
m_vnParents.clear() ;
if ( bSplitPatches && ( nSpanU > 1 || nSpanV > 1)) {
int nId = -1 ;
for ( int i = 1 ; i < nSpanU ; ++i) {
m_mTree[nId].SetSplitDirVert( true) ;
Split( nId, i * SBZ_TREG_COEFF) ;
++ nId ;
++ nId ;
if ( i * SBZ_TREG_COEFF > ptMin.x && i * SBZ_TREG_COEFF < ptTop.x){
m_mTree[nId].SetSplitDirVert( true) ;
Split( nId, i * SBZ_TREG_COEFF) ;
++ 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 * SBZ_TREG_COEFF) ;
nId = m_mTree[nId].m_nChild2 ;
if ( j * SBZ_TREG_COEFF > ptMin.y && j * SBZ_TREG_COEFF < ptTop.y){
m_mTree[nId].SetSplitDirVert( false) ;
Split( nId, j * SBZ_TREG_COEFF) ;
nId = m_mTree[nId].m_nChild2 ;
}
}
}
vLeaves.clear() ;
GetHeightLeaves( -1, vLeaves) ;
m_vnParents = vLeaves ;
}
// 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) ;
// controllo se la superficie è chiusa. In tal caso la splitto sul parametro su cui è chiusa
// 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) ;
// 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
// 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 ptV0, ptV1 ;
Point3d ptU0, ptU1 ;
// 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) ;
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( true) ;
m_mTree[0].SetSplitDirVert( false) ;
Split( 0) ;
m_mTree[1].SetSplitDirVert( true) ;
m_mTree[1].SetSplitDirVert( false) ;
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) ;
}
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) ;
// calcolo e salvo la lunghezza reale delle curve di bezier di bordo
PtrOwner<CurveComposite> pCrvV0( m_pSrfBz->GetCurveOnU( 0)) ;
PtrOwner<CurveComposite> pCrvV1( m_pSrfBz->GetCurveOnU( 1)) ;
PtrOwner<CurveComposite> pCrvU0( m_pSrfBz->GetCurveOnV( 0)) ;
PtrOwner<CurveComposite> pCrvU1( m_pSrfBz->GetCurveOnV( 1)) ;
double dLen0 ; pCrvV0->GetApproxLength( dLen0) ;
double dLen1 ; pCrvU1->GetApproxLength( dLen1) ;
double dLen2 ; pCrvV1->GetApproxLength( dLen2) ;
double dLen3 ; pCrvU0->GetApproxLength( dLen3) ;
m_vDim.clear() ;
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)) ;
}
//----------------------------------------------------------------------------
bool
AddOrMergeBBox ( const BBox3d& bBox3dA , std::vector<BBox3d>& vBBox, const bool& bAdd = true, const int& nInd = 0) {
Point3d ptMin = bBox3dA.GetMin() ;
Point3d ptMax = bBox3dA.GetMax() ;
if ( (int)vBBox.size() == 0) {
vBBox.push_back( bBox3dA) ;
return true ;
}
bool bAdded = false ;
for ( int b = 0 ; b < (int)vBBox.size() ; ++b) {
BBox3d bBox3dB = vBBox[b] ;
BBox3d b3Int ;
// se sono celle diverse e ho un'intersezione faccio il merge
if ( ! ( AreSamePointExact( ptMin, bBox3dB.GetMin()) && AreSamePointExact( ptMax, bBox3dB.GetMax())) &&
bBox3dA.FindIntersectionXY( bBox3dB, b3Int)) {
vBBox[b].Add( bBox3dA) ;
if ( ! bAdd ) {
vBBox.erase( vBBox.begin() + nInd) ;
-- b ;
}
// se ho fatto un merge devo controllare se ora la nuova bbox ha delle intersezioni
AddOrMergeBBox( vBBox[b], vBBox, false, b) ;
bAdded = true ;
break ;
}
}
if ( ! bAdded && bAdd)
vBBox.push_back( bBox3dA) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Tree::GetIndependentTrees( std::vector<std::tuple<Point3d,Point3d>>& vTrees)
{
if ( ! m_bTrimmed ) {
vTrees.push_back( std::tuple<Point3d, Point3d>( ORIG, ORIG));
}
else {
// se ho dei loop di trim trovo le loro BBox3d per costruire l'albero solo all'interno di queste BBox
bool bIsRoot = false ;
std::vector<BBox3d> vBBox ;
for ( int a = 0 ; a < (int)m_vPlApprox.size(); ++a ) {
PolyLine plLoop = std::get<0>( m_vPlApprox[a]) ;
// calcolo la BBox3d
BBox3d bBox3dA ;
Point3d pt ;
plLoop.GetFirstPoint( pt) ;
bBox3dA.Add( pt) ;
while ( plLoop.GetNextPoint( pt))
bBox3dA.Add( pt) ;
// controllo se ho intersezioni con altre bbox
// se ho intersezioni unisco le bbox, altrimenti le lascio indipendenti
AddOrMergeBBox( bBox3dA, vBBox) ;
}
// controllo se dopo aver unito le bbox ho ottenuto Root
Point3d ptTR( m_nSpanU * SBZ_TREG_COEFF, m_nSpanV * SBZ_TREG_COEFF) ;
for (int c = 0 ; c < (int)vBBox.size(); ++ c) {
BBox3d bBox3d = vBBox[c] ;
if ( AreSamePointEpsilon( bBox3d.GetMin(), ORIG, 10) && AreSamePointEpsilon( bBox3d.GetMax(), ptTR, 10)){
bIsRoot = true ;
break ;
}
}
// restituisco le celle parent di partenza a partire dalle bbox che ho ottenuto
if ( ! bIsRoot ) {
for (int i = 0 ; i < (int)vBBox.size() ; ++ i) {
Point3d ptMin = vBBox[i].GetMin() ;
Point3d ptMax = vBBox[i].GetMax() ;
vTrees.push_back( std::tuple<Point3d,Point3d>( ptMin, ptMax)) ;
}
}
else
vTrees.push_back( std::tuple<Point3d, Point3d>( ORIG, ORIG));
}
return true ;
}
//----------------------------------------------------------------------------
void
Tree::Split( const int& nId, const double& dSplitValue)
@@ -283,7 +395,7 @@ Tree::Split( const int& nId, const 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!!!!!!!!!!!!!!!!!!!
// quando si implementerà lo split a parametro libero bisognerà impedire che si facciano split troppo vicini al bordo della cella!!!!!!!!!!!!!!!!!!!
m_mTree[nId].m_dSplit = dSplitValue ;
Cell cChild1, cChild2 ;
cChild1.m_nDepth = m_mTree[nId].m_nDepth + 1 ;
@@ -1219,7 +1331,7 @@ Tree::GetPolygons( std::vector<POLYLINEVECTOR>& vPolygons) {
return false ;
POLYLINEVECTOR vPolygonsBasic ;
GetPolygonsBasic( vPolygonsBasic) ;
// scorro sui poligoni delle celle non trimmate
// scorro sulle celle e costruisco i poligoni
int nCells = (int)vPolygonsBasic.size() ;
for ( int i = 0 ; i < nCells ; ++i) {
@@ -1418,12 +1530,11 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& clTrim) const
nCells.push_back( nId) ;
// se sono in un vertice o su un lato devo controllare di aver trovato la cella giusta
Point3d ptBr( m_mTree.at( nId).GetTopRight().x , m_mTree.at( nId).GetBottomLeft().y) ;
Point3d ptTl( m_mTree.at( nId).GetBottomLeft().x , m_mTree.at( nId).GetTopRight().y) ;
if ( AreSamePointApprox( ptToAssign, ptTl) ||
AreSamePointApprox( ptToAssign, m_mTree.at( nId).GetBottomLeft()) ||
AreSamePointApprox( ptToAssign, ptBr) ||
AreSamePointApprox( ptToAssign, m_mTree.at( nId).GetTopRight()))
if ( abs( ptToAssign.x - ptTl.x) < EPS_SMALL || abs( ptToAssign.x - ptBr.x) < EPS_SMALL ||
abs( ptToAssign.y - ptTl.y) < EPS_SMALL || abs( ptToAssign.y - ptBr.y) < EPS_SMALL)
{
Point3d ptToAssignPlus ;
double dParam ;
@@ -1432,11 +1543,11 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& clTrim) const
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 ;
ptToAssignPlus = ptToAssignPlus + vDir * 2 * EPS_SMALL ;
}
nCells = FindCell( ptToAssignPlus, clTrim) ;
if ( nCells.empty()) {
ptToAssignPlus = ptToAssignPlus - 2 * vDir * EPS_SMALL ;
ptToAssignPlus = ptToAssignPlus - 4 * vDir * EPS_SMALL ;
nCells = FindCell( ptToAssignPlus, clTrim) ;
}
}
@@ -1473,16 +1584,16 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& cl, INTVECTOR vCells
bool
Tree::TraceLoopLabelCell( void)
{
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
// il valore è negativo perché voglio considerare contenuto anche un punto che sta su un lato
double dLinTol = - EPS_SMALL ;
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) m_vPlApprox.size() ; ++ i) {
PolyLine plLoop = std::get<0>(m_vPlApprox[i]) ;
// calcolo se il loop è CCW o CW
// controllo se il loop è CCW o CW
bool bCCW = std::get<1>(m_vPlApprox[i]) ;
// trovo in quale cella è il ptStart
// trovo in quale cella è il ptStart
Point3d ptStart ;
plLoop.GetFirstPoint( ptStart) ;
PNTULIST lPt = plLoop.GetUPointList() ;
@@ -1493,9 +1604,14 @@ Tree::TraceLoopLabelCell( void)
clFirst.Set( ptFirst->first, ptSecond->first) ;
// individuo la cella da cui parte il loop
INTVECTOR nCells = FindCell( ptStart, clFirst) ;
int nId = nCells.back() ;
int nId ;
if ( ! nCells.empty())
nId = nCells.back() ;
else
// il loop è fuori dalla cella root che sto analizzando
continue ;
int nFirstCell = nId ;
// trovo quali punti della polyline sono nella cella e l'intersezione
// 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
@@ -1512,18 +1628,15 @@ Tree::TraceLoopLabelCell( void)
INTVECTOR :: iterator iter = find( m_vnLeaves.begin(), m_vnLeaves.end(), nId) ;
int nIdPolygon = std::distance( m_vnLeaves.begin(), iter) ;
bool bEraseNextPoint = false ;
//// per debug
//int c = 0 ;
Cell cUnderWork ;
while ( plLoop.GetNextPoint( ptCurr)) {
//++ c ;
// sto uscendo dalla cella, quindi cerco l'intersezione
Point3d ptTStart, ptTEnd ;
plLoop.GetPrevPoint( ptTStart) ;
plLoop.GetNextPoint( ptTEnd) ;
CurveLine clTrim ;
clTrim.Set( ptTStart, ptTEnd) ;
while( ! IsPointInsidePolyLine( ptCurr, vplPolygons[nIdPolygon], dLinTol)) { /// qui devo mettere una tolleranza negativa per poter tener conto anche dei punti che sono SULLA curva
// qui devo mettere una tolleranza negativa per poter tener conto anche dei punti che sono SULLA curva
while( ! IsPointInsidePolyLine( ptCurr, vplPolygons[nIdPolygon], dLinTol)) {
// sto uscendo dalla cella, quindi cerco l'intersezione
if ( bEraseNextPoint) {
vptInters.pop_back() ;
bEraseNextPoint = false ;
@@ -1552,8 +1665,6 @@ Tree::TraceLoopLabelCell( void)
m_mTree[nId].m_vInters.back().bCCW = bCCW ;
// salvo il chunk del loop
m_mTree[nId].m_vInters.back().nChunk = m_mChunk[i] ;
// per debug
cUnderWork = m_mTree[nId] ;
}
// aggiungo la fine del segmento nel vettore delle intersezioni
vptInters.push_back( ptCurr) ;
@@ -1620,7 +1731,7 @@ Tree::TraceLoopLabelCell( void)
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) {
while ( ! bAllDone) {
// categorizzo la cella
m_mTree[nCell].m_nFlag2 = 1 ;
CategorizeCell( nCell) ;
@@ -1640,7 +1751,8 @@ Tree::TraceLoopLabelCell( void)
if ( ! bProceeded) {
m_mTree[nCell].SetProcessed() ;
}
else { //categorizzo la cella
else {
//categorizzo la cella
m_mTree[nCell].m_nFlag2 = 1 ;
CategorizeCell( nCell) ;
}
@@ -2015,7 +2127,7 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool
m_mTree[nId].m_vInters.back().nIn = 7 ;
}
else {
nId = vNeigh[0] ;
nId = vNeigh1[0] ;
m_mTree[nId].m_vInters.emplace_back() ;
m_mTree[nId].m_vInters.back().nIn = 4 ;
}
@@ -2064,8 +2176,7 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool
m_mTree[nId].m_vInters.back().nIn = 4 ;
}
else {
GetRightNeigh( nId, vNeigh) ;
nId = vNeigh[0] ;
nId = vNeigh1[0] ;
m_mTree[nId].m_vInters.emplace_back() ;
m_mTree[nId].m_vInters.back().nIn = 5 ;
}
@@ -2114,7 +2225,7 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool
m_mTree[nId].m_vInters.back().nIn = 5 ;
}
else {
nId = vNeigh.back() ;
nId = vNeigh1.back() ;
m_mTree[nId].m_vInters.emplace_back() ;
m_mTree[nId].m_vInters.back().nIn = 6 ;
}
@@ -2369,7 +2480,7 @@ Tree::CreateCellPolygons( const int& nLeafId, std::vector<POLYLINEVECTOR>& vPoly
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/////////////////////////////////////
// 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]) {
@@ -2395,6 +2506,7 @@ Tree::CreateIslandAndHoles( const int& nLeafId, std::vector<POLYLINEVECTOR>& vPo
PolyLine plTrimmedPoly ;
// loop interni in una cella intersecata
int nChunkBiggestCW = -1 ;
if ( m_mTree[nId].m_nFlag == 3 || m_mTree[nId].m_nFlag == 2) {
PolyLine plInLoop ;
Inters inA ;
@@ -2407,6 +2519,8 @@ Tree::CreateIslandAndHoles( const int& nLeafId, std::vector<POLYLINEVECTOR>& vPo
if ( inA.nIn == -1) {
// per ogni loop CW verifico che ci sia un loop CCW dello stesso chunk ( che quindi lo contiene)
if ( ! inA.bCCW) {
if ( nChunkBiggestCW == -1)
nChunkBiggestCW = inA.nChunk ;
bContained = false ;
Inters inB = m_mTree[nId].m_vInters[0] ;
for( int c = 0 ; c < nInters ; ++ c){
@@ -2443,7 +2557,8 @@ Tree::CreateIslandAndHoles( const int& nLeafId, std::vector<POLYLINEVECTOR>& vPo
vCellPolygons.push_back( plInLoop) ;
vPolygons.push_back( vCellPolygons) ;
++ nPoly ;
vnParentChunk.push_back( inA.nChunk) ;
// imposto il chunk del loop CW più grande ( il primo che ho incontrato)
vnParentChunk.push_back( nChunkBiggestCW) ;
vCellPolygons.clear() ;
plInLoop.Clear() ;
}
@@ -2577,20 +2692,37 @@ Tree::CheckIfBefore( const int& nEdge1, const Point3d& ptP1, const int& nEdge2,
//----------------------------------------------------------------------------
bool
Tree::CheckIfBefore( const int& nEdge, const Point3d& ptP1, const Point3d& ptP2) const
Tree::CheckIfBefore( const int& nEdge, const Point3d& ptP1, const Point3d& ptP2, const int& nEdge2) const
{
// i punti devono essere sullo stesso lato nEdge
// nEdge2 è di backup, in caso nEdge sia un vertice, per capire di quale lato si tratta
int nEdgeRef ;
if ( nEdge != nEdge2 && nEdge2 != -1) {
if ( std::min(nEdge, nEdge2) < 4)
nEdgeRef = std::min(nEdge, nEdge2) ;
else if ( AreSameEdge( nEdge, 0) && AreSameEdge( nEdge2, 0))
nEdgeRef = 0 ;
else if ( AreSameEdge( nEdge, 1) && AreSameEdge( nEdge2, 1))
nEdgeRef = 1 ;
else if ( AreSameEdge( nEdge, 2) && AreSameEdge( nEdge2, 2))
nEdgeRef = 2 ;
else if ( AreSameEdge( nEdge, 3) && AreSameEdge( nEdge2, 3))
nEdgeRef = 3 ;
}
else
nEdgeRef = nEdge ;
// sul lato nEdge controllo se ptP1 viene prima di ptP2.
// i lati vengono percorsi in senso antiorario
if ( AreSameEdge( nEdge, 0)) {
if ( AreSameEdge( nEdgeRef, 0)) {
return ptP1.x > ptP2.x ;
}
else if ( AreSameEdge( nEdge, 1)) {
else if ( AreSameEdge( nEdgeRef, 1)) {
return ptP1.y > ptP2.y ;
}
else if ( AreSameEdge( nEdge, 2)) {
else if ( AreSameEdge( nEdgeRef, 2)) {
return ptP1.x < ptP2.x ;
}
else if ( AreSameEdge( nEdge, 3)) {
else if ( AreSameEdge( nEdgeRef, 3)) {
return ptP1.y < ptP2.y ;
}
return false ;
@@ -3049,13 +3181,13 @@ Tree::CategorizeCell( const int& nId)
bool bIntersIn ;
for ( int k = 0 ; k < (int) m_mTree[vNeigh[0]].m_vInters.size() ; ++ k) {
if ( AreSameEdge( m_mTree[vNeigh[0]].m_vInters[k].nIn, 3)) {
if ( CheckIfBefore( nEdge, m_mTree[vNeigh[0]].m_vInters[k].vpt[0], ptInters)) {
if ( CheckIfBefore( nEdge, m_mTree[vNeigh[0]].m_vInters[k].vpt[0], ptInters, 3)) {
ptInters = m_mTree[vNeigh[0]].m_vInters[k].vpt[0] ;
bIntersIn = true ;
}
}
if ( AreSameEdge( m_mTree[vNeigh[0]].m_vInters[k].nOut, 3)) {
if ( CheckIfBefore( nEdge, m_mTree[vNeigh[0]].m_vInters[k].vpt.back(), ptInters)) {
if ( CheckIfBefore( nEdge, m_mTree[vNeigh[0]].m_vInters[k].vpt.back(), ptInters, 3)) {
ptInters = m_mTree[vNeigh[0]].m_vInters[k].vpt.back() ;
bIntersIn = false ;
}
@@ -3103,6 +3235,7 @@ Tree::CheckIfBetween( const Inters& inA, const Inters& inB) const
}
else if ( nEdge == 7)
nEdge = 0 ;
// creo la sequenza di Edges da scorrere per trovare i possibili validNextStart
while ( ! AreSameEdge( nEdge, inA.nIn) || (int) vEdges.size() == 0) {
vEdges.push_back( nEdge) ;
if ( nEdge == 3)
@@ -3115,16 +3248,16 @@ Tree::CheckIfBetween( const Inters& inA, const Inters& inB) const
bool bFound = false ;
for ( int i : vEdges) {
if ( AreSameEdge( inB.nIn, i)) {
if ( AreSameEdge( inB.nIn, inA.nIn) && AreSameEdge( inA.nIn, inA.nOut)) {
if ( AreSameEdge( inB.nIn, inA.nIn) && AreSameEdge( inA.nIn, inA.nOut) && AreSameEdge( inB.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]))
if ( CheckIfBefore( nEdge, inA.vpt[0], inA.vpt.back(), inA.nOut)) {
if ( CheckIfBefore( nEdge, inA.vpt.back(), inB.vpt[0], inA.nOut ) || CheckIfBefore( nEdge, inB.vpt[0], inA.vpt[0], inA.nOut))
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]))
if ( CheckIfBefore( nEdge, inA.vpt.back(), inB.vpt[0], inA.nOut) && CheckIfBefore( nEdge, inB.vpt[0], inA.vpt[0], inA.nOut))
bFound = true ;
}
}
@@ -3138,17 +3271,18 @@ Tree::CheckIfBetween( const Inters& inA, const Inters& inB) const
}
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.vpt[0]))
if ( CheckIfBefore( inA.nIn, inB.vpt[0], inA.vpt[0], inB.nIn))
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())) {
if ( AreSameEdge( inB.nOut, inB.nIn) && CheckIfBefore( inB.nOut, inB.vpt[0], inB.vpt.back(), inB.nIn)) {
bFound = true ;
}
else if ( ! AreSameEdge( inB.nOut,inB.nIn))
bFound = true ;
}
// se incontro prima l'uscita dell'ingresso, sicuramente InB NON è un validNextStart
if ( AreSameEdge( inB.nOut, i) && ! bFound && CheckIfBefore( i, inA.vpt[0], inB.vpt.back()) && CheckIfBefore( i, inA.vpt.back(), inB.vpt.back()))
break ;
}