EgtGeomKernel :

- risolti i bug noti
- gestiti problemi numerici al bordo delle celle
Manca
- test in casi più complicati
This commit is contained in:
Daniele Bariletti
2023-06-13 11:55:33 +02:00
parent 1aeb2809fa
commit d3d7f94c3a
3 changed files with 144 additions and 43 deletions
+118 -38
View File
@@ -69,7 +69,7 @@ Cell::IsLeaf ( void) const
//----------------------------------------------------------------------------
Tree::Tree( void)
: m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosed( false)
: m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosed( false), m_bSplitPatches( true)
{
Point3d ptBl( 0, 0), ptTr ( 1 * SBZ_TREG_COEFF, 1 * SBZ_TREG_COEFF) ;
Cell cRoot( ptBl, ptTr) ;
@@ -78,9 +78,9 @@ Tree::Tree( void)
//----------------------------------------------------------------------------
Tree::Tree( const SurfBezier* pSrfBz, bool bSplitPatches)
: m_bBilinear( false), m_bMulti( false), m_bClosed( false)
: m_bBilinear( false), m_bMulti( false), m_bClosed( false), m_bSplitPatches( bSplitPatches)
{
SetSurf( pSrfBz, bSplitPatches) ;
SetSurf( pSrfBz, m_bSplitPatches) ;
}
//----------------------------------------------------------------------------
@@ -93,6 +93,7 @@ void
Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches)
{
m_pSrfBz = pSrfBz ;
m_bSplitPatches = bSplitPatches ;
// le coordinate delle celle sono nello spazio parametrico
int nDegU, nDegV, nSpanU, nSpanV ;
bool bIsRat, bTrimmed ;
@@ -100,6 +101,8 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches)
m_bTrimmed = bTrimmed ;
m_nDegU = nDegU ;
m_nDegV = nDegV ;
m_nSpanU = nSpanU ;
m_nSpanV = nSpanV ;
if ( nDegU == 1 && nDegV == 1)
m_bBilinear = true ;
if ( nSpanU * nSpanV != 1)
@@ -176,7 +179,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches)
int nId = -1 ;
for ( int i = 1 ; i < nSpanU ; ++i) {
m_mTree[nId].SetSplitDirVert( true) ;
Split( nId, i) ;
Split( nId, i * SBZ_TREG_COEFF) ;
++ nId ;
++ nId ;
}
@@ -185,11 +188,13 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches)
for ( int nId : vLeaves) {
for ( int j = nSpanV - 1 ; j > 0 ; --j ) {
m_mTree[nId].SetSplitDirVert( false) ;
Split( nId, j) ;
Split( nId, j * SBZ_TREG_COEFF) ;
nId = m_mTree[nId].m_nChild2 ;
}
}
// split preliminari per dividere le patch in modo da triangolarle indipendentemente////////////////////////////////////////////////////////
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 {
@@ -603,6 +608,8 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax)
m_mTree[nCToSplit].SetProcessed() ;
// risalgo i parent finché non trovo il primo Child2 da processare
nCToSplit = m_mTree[nCToSplit].m_nParent ;
if ( nCToSplit == -2)
return true ;
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()) {
@@ -736,6 +743,8 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax)
m_mTree[nCToSplit].SetProcessed() ;
// risalgo i parent finché non trovo il primo Child2 da processare
nCToSplit = m_mTree[nCToSplit].m_nParent ;
if ( nCToSplit == -2)
return true ;
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()) {
@@ -1215,7 +1224,8 @@ Tree::GetPolygons( std::vector<POLYLINEVECTOR>& vPolygons) {
}
// trimmata
else {
TraceLoopLabelCell() ;
if ( ! TraceLoopLabelCell())
return false ;
POLYLINEVECTOR vPolygonsBasic ;
GetPolygonsBasic( vPolygonsBasic) ;
// scorro sui poligoni delle celle non trimmate
@@ -1416,12 +1426,19 @@ Tree::FindCell( const Point3d& ptToAssign, CurveLine& clTrim) const
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 ;
}
//// 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 ;
//}
// se ho diviso preliminarmente le patches e in uno dei due parametri ho un numero dispari di patches devo individuare a mano la cella parent
// in cui individuare la foglia giusta
if ( m_bSplitPatches && ( (m_nSpanU % 2 != 0 && m_nSpanU > 1) || (m_nSpanV % 2 != 0 && m_nSpanV > 1))) {
INTVECTOR nParents = FindCell( ptToAssign, clTrim, m_vnParents) ;
nId = nParents.back() ;
}
// individuo la foglia in cui ho lo start del loop
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 ;
@@ -1442,11 +1459,14 @@ Tree::FindCell( const Point3d& ptToAssign, CurveLine& clTrim) const
}
}
}
if ( nId != -1)
nCells.push_back( nId) ;
//if ( nId != -1)
// nCells.push_back( nId) ;
//if ( nId == -1)
// nId = -2 ;
nCells.push_back( nId) ;
//// 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) ;
@@ -1482,7 +1502,7 @@ Tree::FindCell( const Point3d& ptToAssign, CurveLine& clTrim) const
if ( AreSamePointApprox(ptToAssign, ptTl) ||
AreSamePointApprox( ptToAssign, m_mTree.at(nId).GetBottomLeft()) ||
AreSamePointApprox(ptToAssign, ptBr) ||
AreSamePointApprox( ptToAssign, ptTl))
AreSamePointApprox( ptToAssign, m_mTree.at(nId).GetTopRight()))
{
Point3d ptToAssignPlus ;
double dParam ;
@@ -1602,6 +1622,7 @@ Tree::TraceLoopLabelCell( void)
INTVECTOR :: iterator iter = find( m_vnLeaves.begin(), m_vnLeaves.end(), nId) ;
int nIdPolygon = std::distance( m_vnLeaves.begin(), iter) ;
bool bVertex = false ;
bool bEraseNextPoint = false ;
while ( plLoop.GetNextPoint( ptCurr)) {
// sto uscendo dalla cella, quindi cerco l'intersezione
Point3d ptTStart, ptTEnd ;
@@ -1610,10 +1631,28 @@ Tree::TraceLoopLabelCell( void)
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
if ( bEraseNextPoint ) {
vptInters.pop_back() ;
bEraseNextPoint = false ;
}
bLoopInside = false ;
// trovo l'intersezione e passo alla cella successiva. nId viene aggiornato dalla funzione FindInters
// trovo l'intersezione e passo alla cella successiva. nId viene aggiornato dalla funzione FindInters
bVertex = false ;
FindInters( nId, clTrim, vptInters, bVertex) ;
// se non trovo l'intersezione vuol dire che non sono nella cella giusta!
// al precedente FindInters avrei dovuto passare di cella
if ( ! FindInters( nId, clTrim, vptInters, bVertex)) {
// scaterò il punto molto vicino al lato e tengo solo l'intersezione del trim col lato
m_mTree[nId].m_vInters.back().vpt.pop_back() ;
plLoop.GetPrevPoint( ptTEnd) ;
plLoop.GetPrevPoint( ptTStart) ;
plLoop.GetNextPoint( ptCurr) ;
clTrim.Set( ptTStart, ptTEnd) ;
//clTrim.ExtendEndByLen( EPS_SMALL * 2) ;
vptInters.clear() ;
if ( FindInters( nId, clTrim, vptInters, bVertex))
return false ;
bEraseNextPoint = true ;
}
// 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) ;
@@ -1644,7 +1683,8 @@ Tree::TraceLoopLabelCell( void)
else {
// verifico se sono effettivamente nella cella di partenza o nella penultima cella
// 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 ptLast = m_mTree[nId].m_vInters.back().vpt.back() ;
Point3d ptLast = ptCurr ;
if ( nId != nFirstCell) {
Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ;
Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ;
@@ -1661,21 +1701,43 @@ Tree::TraceLoopLabelCell( void)
vptInters.clear() ;
nLastId = nId ;
FindInters( nId, clTrim, vptInters, bVertex) ;
m_mTree[nLastId].m_vInters.back().vpt.push_back( vptInters[0]) ;
if ( ! AreSamePointExact( vptInters[0], m_mTree[nLastId].m_vInters.back().vpt.back()))
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 ;
// sono tornato nella cella iniziale, quindi giunto i due vettori intersezione
if ( nId == nFirstCell) {
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 ;
}
// se non sono tornato alla cella di partenza
else {
m_mTree[nId].m_vInters.pop_back() ;
if ( (int)m_mTree[nId].m_vInters.size() == 0)
m_mTree[nId].m_nFlag = 0 ;
// aggiusto nIn della cella di partenza ( in questo caso dovrei aver avuto un ingresso direttamente in un vertice)
Point3d ptFirst = m_mTree[nFirstCell].m_vInters[nPass].vpt[0] ;
Point3d ptTl( m_mTree[nFirstCell].GetBottomLeft().x, m_mTree[nFirstCell].GetTopRight().y) ;
Point3d ptBr( m_mTree[nFirstCell].GetTopRight().x, m_mTree[nFirstCell].GetBottomLeft().y) ;
if ( AreSamePointApprox( m_mTree[nFirstCell].GetTopRight(), ptFirst))
m_mTree[nFirstCell].m_vInters[nPass].nIn = 7 ;
else if (AreSamePointApprox( ptTl, ptFirst))
m_mTree[nFirstCell].m_vInters[nPass].nIn = 4 ;
else if (AreSamePointApprox( m_mTree[nFirstCell].GetBottomLeft(), ptFirst))
m_mTree[nFirstCell].m_vInters[nPass].nIn = 5 ;
else if (AreSamePointApprox( ptBr, ptFirst))
m_mTree[nFirstCell].m_vInters[nPass].nIn = 6 ;
}
}
}
// riordino i vettori di intersezione per ogni cella e setto il flag RightEdgeIn
// 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) ;
@@ -1913,16 +1975,21 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert
// intersezione e controlli
IntersLineLine illExit( clTrim, clEdge, true) ;
IntCrvCrvInfo aInfo, aInfo2 ;
//if ( ! illExit.GetIntCrvCrvInfo( aInfo) )
// return false ;
illExit.GetIntCrvCrvInfo( aInfo) ;
bool bIntersOn1Found = true ;
if ( ! illExit.GetIntCrvCrvInfo( aInfo) && ! clEdge2.IsValid()) {
bIntersOn1Found = false ;
return false ;
}
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 ;
if ( bIntersOn1Found)
ptInters = aInfo.IciA[0].ptI ;
else
return false ;
else {
// solo intersezione sul lato 2
if ( illExit.GetNumInters() == 0 ) {
@@ -1958,7 +2025,10 @@ Tree::FindInters( int& nId, CurveLine& clTrim, PNTVECTOR& vptInters, bool& bVert
nEdge = 7 ;
}
m_mTree[nId].m_vInters.back().nOut = nEdge ;
vptInters.push_back( ptInters) ;
if ( (int)vptInters.size() == 0)
vptInters.push_back( ptInters) ;
else if ( ! AreSamePointExact(ptInters , vptInters.back()))
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]) ;
@@ -2303,6 +2373,9 @@ Tree::CreateCellPolygons( int nLeafId, std::vector<POLYLINEVECTOR>& vPolygons, I
int nFirstLoopInPoly = -1 ;
INTVECTOR vAddedLoops ;
for ( int w = 0 ; w < (int)vToCheckNow.size() ; ++ w) {
if ( m_mTree[nId].m_vInters[w].vpt.size() < 2) {
continue ;
}
// indice del loop in m_vInters
int j = vToCheckNow[w] ;
Inters inA = m_mTree[nId].m_vInters[j] ;
@@ -2366,6 +2439,8 @@ Tree::CreateCellPolygons( int nLeafId, std::vector<POLYLINEVECTOR>& vPolygons, I
// quindi salto al prossimo loop
if ( plTrimmedPoly.GetPointNbr() == 1 ) {
plTrimmedPoly.Clear() ;
if ( j == nFirstLoopInPoly)
nEdgeIn = -1 ;
continue ;
}
if ( nEdge > 3 && nEdge != 7 ) {
@@ -2530,7 +2605,7 @@ Tree::CreateIslandAndHoles( int nLeafId, std::vector<POLYLINEVECTOR>& vPolygons,
// numero dei loop interni passati
Inters inA ;
// se ho almeno un loop CW che non è contenuto in un altro poligono o in un loop interno CCW devo aggiungere il bordo
bool bEdgeToAdd = true ;
//bool bEdgeToAdd = true ;
bool bAllContained = true ;
bool bContained = false ;
int nInters = (int) m_mTree[nId].m_vInters.size() ;
@@ -2559,7 +2634,8 @@ Tree::CreateIslandAndHoles( int nLeafId, std::vector<POLYLINEVECTOR>& vPolygons,
break ;
}
if ( m_mTree[nId].m_nFlag == 2 && ( bEdgeToAdd || ! bAllContained)) {
//if ( m_mTree[nId].m_nFlag == 2 && ( bEdgeToAdd || ! bAllContained)) {
if ( m_mTree[nId].m_nFlag == 2 && ! bAllContained) {
// 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) ;
@@ -2837,7 +2913,11 @@ Tree::AddVertex( int nId, std::vector<PNTVECTOR>& vEdgeVertex, PolyLine& plTrimm
Point3d ptLast ;
plTrimmedPoly.GetLastPoint( ptLast) ;
// verifico di essere allineato con un lato, sennò aggiungo e basta
Vector3d vDir = ptToAdd - ptLast ;
Vector3d vDir;
if ( ! AreSamePointExact(ptToAdd, ptLast))
vDir = ptToAdd - ptLast ;
else
return true ;
// se non riesco a normalizzare perché sono troppo vicino ad un vertice allora aggiungo direttamente il vertice
if ( ! vDir.Normalize()) {
plTrimmedPoly.EraseLastUPoint() ;
@@ -3027,7 +3107,7 @@ Tree::SetRightEdgeIn( int nId)
m_mTree[nId].m_nRightEdgeIn = 0 ;
return true ;
}
// se ho inters sul lato destro allora in parte è dentro
// se ho inters sul lato destro ( nEdge == 3) allora in parte è dentro
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 ;
@@ -3307,7 +3387,7 @@ Tree::CheckIfBetween( Inters& inA, 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.nIn, inA.vpt[0]))
if ( CheckIfBefore(inA.nIn, inB.vpt[0], inA.vpt[0]))
bFound = true ;
}
else