EgtGeomKernel 2.3k1 :
- corretto offset di segmenti di retta singoli con estrusione - modifiche per calcolo taglio superfici TriMesh - modifiche a funzione SimplifyFacets di superfici TriMesh.
This commit is contained in:
+207
-183
@@ -1,8 +1,8 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// EgalTech 2015-2015
|
||||
// EgalTech 2021-2021
|
||||
//----------------------------------------------------------------------------
|
||||
// File : SurfTriMeshUtilities.cpp Data : 25.10.21 Versione :
|
||||
// Contenuto : Implementazione della classe Superfici TriMesh.
|
||||
// File : SurfTriMeshUtilities.cpp Data : 01.11.21 Versione : 2.3k1
|
||||
// Contenuto : Implementazione funzioni di utilità di Superfici TriMesh.
|
||||
//
|
||||
//
|
||||
//
|
||||
@@ -19,208 +19,232 @@
|
||||
|
||||
using namespace std ;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool
|
||||
IsVertex( PNTULIST& PointList, PNTULIST::const_iterator itCurr)
|
||||
{
|
||||
// recupero il punto precedente
|
||||
PNTULIST::const_iterator itPrev ;
|
||||
if ( itCurr == PointList.begin())
|
||||
itPrev = prev( PointList.end(), 2) ;
|
||||
else
|
||||
itPrev = prev( itCurr) ;
|
||||
// recupero il punto successivo
|
||||
auto itNext = next( itCurr) ;
|
||||
if ( itNext == PointList.end())
|
||||
itNext = next( PointList.begin()) ;
|
||||
// se cambia faccia adiacente tra prima e dopo, va bene
|
||||
if ( itPrev->second != itCurr->second)
|
||||
return true ;
|
||||
// se lati aperti e cambia direzione tra prima e dopo, va bene
|
||||
if ( itPrev->second == -1) {
|
||||
DistPointLine PointLineDistCalc( itCurr->first, itPrev->first, itNext->first) ;
|
||||
double dDist ;
|
||||
if ( PointLineDistCalc.GetDist( dDist) && dDist > EPS_SMALL)
|
||||
return true ;
|
||||
}
|
||||
// altrimenti non va bene
|
||||
return false ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool
|
||||
ChooseGoodStartPoint( PNTULIST& PointList)
|
||||
{
|
||||
// se il punto iniziale è un vertice, non devo fare alcunché
|
||||
if ( IsVertex( PointList, PointList.begin()))
|
||||
return true ;
|
||||
// altrimenti cerco il vertice più vicino
|
||||
for ( auto it = next( PointList.begin()) ; it != PointList.end() ; ++it) {
|
||||
if ( IsVertex( PointList, it)) {
|
||||
// cancello ultimo punto ( coincide con primo)
|
||||
PointList.pop_back() ;
|
||||
// sposto la parte iniziale dei punti alla fine
|
||||
PointList.splice( PointList.end(), PointList, PointList.begin(), it) ;
|
||||
// aggiungo punto finale come copia dell'iniziale
|
||||
PointList.push_back( PointList.front()) ;
|
||||
// ho finito
|
||||
return true ;
|
||||
}
|
||||
}
|
||||
return false ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool
|
||||
AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, bool& bModif)
|
||||
{
|
||||
// Ciclo sui punti del loop
|
||||
auto itLast = PointList.begin() ;
|
||||
for ( auto it = next( itLast) ; it != PointList.end() ; ++ it) {
|
||||
|
||||
// Se dal punto corrente inizia un segmento adiacente a un'altra faccia
|
||||
if ( itLast->second != it->second) {
|
||||
// Elimino i punti interni
|
||||
auto itNextToLast = next( itLast) ;
|
||||
for ( auto itInn = itNextToLast ; itInn != it ; ) {
|
||||
itInn = PointList.erase( itInn) ;
|
||||
bModif = true ;
|
||||
}
|
||||
// Se la lunghezza del segmento supera il limite imposto
|
||||
double dSegLen = Dist( it->first, itLast->first) ;
|
||||
if ( dSegLen > dMaxEdgeLen) {
|
||||
// determino il numero di step
|
||||
double dRatio = dSegLen / dMaxEdgeLen ;
|
||||
int nStepCount = int( dRatio) + 1 ;
|
||||
// inserisco i punti
|
||||
auto itAdd = it ;
|
||||
for ( int nP = 1 ; nP < nStepCount ; ++ nP) {
|
||||
double dCoeff = nP / nStepCount ;
|
||||
itAdd = PointList.insert( itAdd, POINTU( Media( itLast->first, it->first, dCoeff), itLast->second)) ;
|
||||
bModif = true ;
|
||||
}
|
||||
}
|
||||
// Nuovo punto di riferimento
|
||||
itLast = it ;
|
||||
}
|
||||
|
||||
// Se sono due segmenti liberi non allineati
|
||||
else if ( itLast->second == - 1) {
|
||||
// Calcolo se i punti compresi fra gli estremi sono allineati
|
||||
bool bAreAligned = true ;
|
||||
auto itNextToLast = next( itLast) ;
|
||||
for ( auto itInn = itNextToLast ; itInn != it && bAreAligned ; ++ itInn) {
|
||||
DistPointLine PointLineDistCalc( itInn->first, itLast->first, it->first) ;
|
||||
double dDist ;
|
||||
if ( PointLineDistCalc.GetDist( dDist))
|
||||
bAreAligned = ( dDist < EPS_SMALL) ;
|
||||
}
|
||||
// Se i punti sono allineati
|
||||
if ( bAreAligned) {
|
||||
// Verifico se il successivo punto non è più allineato
|
||||
auto itNextToCurr = next( it) ;
|
||||
if ( itNextToCurr != PointList.end()) {
|
||||
for ( auto itInn = itNextToLast ; itInn != itNextToCurr && bAreAligned ; ++ itInn) {
|
||||
DistPointLine PointLineDistCalc( itInn->first, itLast->first, itNextToCurr->first) ;
|
||||
double dDist ;
|
||||
if ( PointLineDistCalc.GetDist( dDist))
|
||||
bAreAligned = ( dDist < EPS_SMALL) ;
|
||||
}
|
||||
}
|
||||
// Se ho trovato un insieme massimale di punti allineati li processo
|
||||
if ( ! bAreAligned || itNextToCurr == PointList.end()) {
|
||||
// Elimino i punti interni
|
||||
for ( auto itInn = itNextToLast ; itInn != it ; ) {
|
||||
itInn = PointList.erase( itInn) ;
|
||||
bModif = true ;
|
||||
}
|
||||
// Se la lunghezza del segmento supera il limite imposto
|
||||
double dSegLen = Dist( it->first, itLast->first) ;
|
||||
if ( dSegLen > dMaxEdgeLen) {
|
||||
// determino il numero di step
|
||||
double dRatio = dSegLen / dMaxEdgeLen ;
|
||||
int nStepCount = int( dRatio) + 1 ;
|
||||
// inserisco i punti
|
||||
auto itAdd = it ;
|
||||
for ( int nP = 1 ; nP < nStepCount ; ++ nP) {
|
||||
double dCoeff = nP / nStepCount ;
|
||||
itAdd = PointList.insert( itAdd, POINTU( Media( itLast->first, it->first, dCoeff), itLast->second)) ;
|
||||
bModif = true ;
|
||||
}
|
||||
}
|
||||
// Nuovo punto di riferimento
|
||||
itLast = it ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
SurfTriMesh::SimplifyFacets( double dMaxEdgeLen)
|
||||
{
|
||||
// Se la lunghezza massima del lato del triangolo sul bordo della faccia è nulla, ho finito.
|
||||
// La trimesh deve essere valida
|
||||
if ( ! IsValid())
|
||||
return false ;
|
||||
// Se la lunghezza massima del lato del triangolo sul bordo della faccia è nulla, non devo fare alcunché
|
||||
if ( dMaxEdgeLen < EPS_SMALL)
|
||||
return true ;
|
||||
|
||||
// Le superfici devono essere valide.
|
||||
if ( ! IsValid())
|
||||
return false ;
|
||||
// Recupero il numero delle facce (esegue anche una verifica delle stesse)
|
||||
int nFacetCnt = GetFacetCount() ;
|
||||
|
||||
// Verifico la definizione delle facce.
|
||||
VerifyFaceting() ;
|
||||
// Ciclo sulle facce della mesh per trovare quelle da ritriangolare
|
||||
unordered_map< int, pair< PNTVECTOR, INTVECTOR>> FacetMap ;
|
||||
for ( int nF = 0 ; nF < nFacetCnt ; ++ nF) {
|
||||
|
||||
// Ciclo sulle facce delle mesh.
|
||||
unordered_map<int, POLYLINEVECTOR> FacetMap ;
|
||||
int nFacetNum = GetFacetCount() ;
|
||||
for ( int nF = 0 ; nF < nFacetNum ; ++ nF) {
|
||||
bool bFacetToRetriangulate = false ;
|
||||
// Recupero i loop della faccia.
|
||||
// Recupero i loop della faccia (il parametro indica la faccia adiacente)
|
||||
POLYLINEVECTOR LoopVec ;
|
||||
GetFacetLoops( nF, LoopVec) ;
|
||||
// Recupero le adiacenze della faccia.
|
||||
INTMATRIX vAdj ;
|
||||
GetFacetAdjacencies( nF, vAdj) ;
|
||||
// Ciclo sui loop della faccia.
|
||||
|
||||
// Ciclo sui loop della faccia
|
||||
bool bToRetriangulate = false ;
|
||||
for ( int nL = 0 ; nL < int( LoopVec.size()) ; ++ nL) {
|
||||
// Lista dei punti del loop.
|
||||
|
||||
// Lista dei punti del loop
|
||||
PNTULIST& PointList = LoopVec[nL].GetUPointList() ;
|
||||
// Mi assicuro che il punto finale non sia all'interno di un segmento.
|
||||
auto itFirst = PointList.begin() ;
|
||||
int nNewStartPos = 0 ;
|
||||
for ( auto it = itFirst ; it != PointList.end() ; ++ it, ++ nNewStartPos) {
|
||||
if ( itFirst->second != it->second) {
|
||||
{
|
||||
// cancello ultimo punto ( coincide con primo)
|
||||
PointList.pop_back() ;
|
||||
// sposto la metà iniziale dei punti alla fine
|
||||
for ( int i = 0 ; i < nNewStartPos ; ++ i)
|
||||
PointList.splice( PointList.end(), PointList, PointList.begin()) ;
|
||||
// aggiungo punto finale come copia dell'iniziale
|
||||
PointList.push_back( PointList.front()) ;
|
||||
}
|
||||
break ;
|
||||
}
|
||||
else if ( itFirst->second == - 1 && it != itFirst) {
|
||||
// Valuto se i punti compresi fra gli estremi sono allinati.
|
||||
bool bAreAlligned = true ;
|
||||
auto itNextToLast = itFirst ;
|
||||
++ itNextToLast ;
|
||||
for ( auto itInn = itNextToLast ; itInn != it && bAreAlligned ; ++ itInn) {
|
||||
DistPointLine PointLineDistCalc( itInn->first, itFirst->first, it->first, false) ;
|
||||
double dDist ;
|
||||
PointLineDistCalc.GetDist( dDist) ;
|
||||
bAreAlligned = bAreAlligned && dDist < EPS_SMALL ;
|
||||
}
|
||||
// I punti sono allineati.
|
||||
if ( bAreAlligned) {
|
||||
// Valuto se includendo anche il punto successivo non ci sarebbe più allineamento,
|
||||
// ovvero avrei trovato un insieme massimale di punti allineati.
|
||||
auto itNextToCurr = it ;
|
||||
++ itNextToCurr ;
|
||||
// Se il punto corrente è l'ultimo, ho trovato un insieme massimale di punti allineati.
|
||||
if ( itNextToCurr != PointList.end()) {
|
||||
for ( auto itInn = itNextToLast ; itInn != itNextToCurr && bAreAlligned ; ++ itInn) {
|
||||
DistPointLine PointLineDistCalc( itInn->first, itFirst->first, itNextToCurr->first, false) ;
|
||||
double dDist ;
|
||||
PointLineDistCalc.GetDist( dDist) ;
|
||||
bAreAlligned = bAreAlligned && dDist < EPS_SMALL ;
|
||||
}
|
||||
}
|
||||
// Se ho trovato un insieme massimale di punti allineati li ridistribuisco,
|
||||
// altrimenti procedo per includere il punto successivo nell'insieme.
|
||||
if ( ! bAreAlligned || itNextToCurr == PointList.end()) {
|
||||
{
|
||||
// cancello ultimo punto ( coincide con primo)
|
||||
PointList.pop_back() ;
|
||||
// sposto la metà iniziale dei punti alla fine
|
||||
for ( int i = 0 ; i < nNewStartPos ; ++ i)
|
||||
PointList.splice( PointList.end(), PointList, PointList.begin()) ;
|
||||
// aggiungo punto finale come copia dell'iniziale
|
||||
PointList.push_back( PointList.front()) ;
|
||||
}
|
||||
break ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ciclo sui punti del loop.
|
||||
auto itLast = PointList.begin() ;
|
||||
for ( auto it = itLast ; it != PointList.end() ; ++ it) {
|
||||
// Dal punto corrente spicca un segmento adiacente a una nuova faccia.
|
||||
if ( itLast->second != it->second) {
|
||||
// Elimino punti interni.
|
||||
auto itNextToLast = itLast ;
|
||||
++ itNextToLast ;
|
||||
for ( auto itInn = itNextToLast ; itInn != it ; ) {
|
||||
itInn = PointList.erase( itInn) ;
|
||||
bFacetToRetriangulate = true ;
|
||||
}
|
||||
// Versore direzione del segmento e sua lunghezza.
|
||||
Vector3d vtSeg = it->first - itLast->first ;
|
||||
double dSegLen = vtSeg.Len() ;
|
||||
vtSeg /= dSegLen ;
|
||||
// Calcolo numero dei punti da inserire.
|
||||
double dRatio = dSegLen / dMaxEdgeLen ;
|
||||
int nStepNum = ( dRatio < 1 + EPS_SMALL ? int( dRatio) : int( dRatio) + 1) ;
|
||||
// Aggiungo i nuovi punti.
|
||||
double dMyLen = dSegLen / nStepNum ;
|
||||
auto itAdd = it ;
|
||||
for ( int nP = 1 ; nP < nStepNum ; ++ nP) {
|
||||
itAdd = PointList.insert( itAdd, POINTU( it->first - nP * dMyLen * vtSeg, itLast->second)) ;
|
||||
bFacetToRetriangulate = true ;
|
||||
}
|
||||
itLast = it ;
|
||||
}
|
||||
// Possono essere due segmenti liberi non allineati.
|
||||
else if ( itLast->second == - 1 && it != itLast) {
|
||||
// Valuto se i punti compresi fra gli estremi sono allinati.
|
||||
bool bAreAlligned = true ;
|
||||
auto itNextToLast = itLast ;
|
||||
++ itNextToLast ;
|
||||
for ( auto itInn = itNextToLast ; itInn != it && bAreAlligned ; ++ itInn) {
|
||||
DistPointLine PointLineDistCalc( itInn->first, itLast->first, it->first, false) ;
|
||||
double dDist ;
|
||||
PointLineDistCalc.GetDist( dDist) ;
|
||||
bAreAlligned = bAreAlligned && dDist < EPS_SMALL ;
|
||||
}
|
||||
// I punti sono allineati.
|
||||
if ( bAreAlligned) {
|
||||
// Valuto se includendo anche il punto successivo non ci sarebbe più allineamento,
|
||||
// ovvero avrei trovato un insieme massimale di punti allineati.
|
||||
auto itNextToCurr = it ;
|
||||
++ itNextToCurr ;
|
||||
// Se il punto corrente è l'ultimo, ho trovato un insieme massimale di punti allineati.
|
||||
if ( itNextToCurr != PointList.end()) {
|
||||
for ( auto itInn = itNextToLast ; itInn != itNextToCurr && bAreAlligned ; ++ itInn) {
|
||||
DistPointLine PointLineDistCalc( itInn->first, itLast->first, itNextToCurr->first, false) ;
|
||||
double dDist ;
|
||||
PointLineDistCalc.GetDist( dDist) ;
|
||||
bAreAlligned = bAreAlligned && dDist < EPS_SMALL ;
|
||||
}
|
||||
}
|
||||
// Se ho trovato un insieme massimale di punti allineati li ridistribuisco,
|
||||
// altrimenti procedo per includere il punto successivo nell'insieme.
|
||||
if ( ! bAreAlligned || itNextToCurr == PointList.end()) {
|
||||
for ( auto itInn = itNextToLast ; itInn != it ; ) {
|
||||
itInn = PointList.erase( itInn) ;
|
||||
bFacetToRetriangulate = true ;
|
||||
}
|
||||
// Versore direzione del segmento e sua lunghezza.
|
||||
Vector3d vtSeg = it->first - itLast->first ;
|
||||
double dSegLen = vtSeg.Len() ;
|
||||
vtSeg /= dSegLen ;
|
||||
// Calcolo numero dei punti da inserire.
|
||||
double dRatio = dSegLen / dMaxEdgeLen ;
|
||||
int nStepNum = ( dRatio < 1 + EPS_SMALL ? int( dRatio) : int( dRatio) + 1) ;
|
||||
// Aggiungo i nuovi punti.
|
||||
double dMyLen = dSegLen / nStepNum ;
|
||||
auto itAdd = it ;
|
||||
for ( int nP = 1 ; nP < nStepNum ; ++ nP) {
|
||||
itAdd = PointList.insert( itAdd, POINTU( it->first - nP * dMyLen * vtSeg, itLast->second)) ;
|
||||
bFacetToRetriangulate = true ;
|
||||
}
|
||||
itLast = it ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mi assicuro che il punto iniziale/finale non sia all'interno di un possibile segmento
|
||||
if ( ! ChooseGoodStartPoint( PointList))
|
||||
return false ;
|
||||
|
||||
// Sistemo il loop
|
||||
bool bModif = false ;
|
||||
if ( ! AdjustLoop( PointList, dMaxEdgeLen, bModif))
|
||||
return false ;
|
||||
if ( bModif)
|
||||
bToRetriangulate = true ;
|
||||
}
|
||||
if ( bFacetToRetriangulate) {
|
||||
FacetMap.emplace( nF, LoopVec) ;
|
||||
|
||||
// Se da ritriangolare,
|
||||
if ( bToRetriangulate) {
|
||||
// Eseguo la ritriangolazione della faccia
|
||||
PNTVECTOR vPt ;
|
||||
INTVECTOR vTr ;
|
||||
if ( Triangulate().Make( LoopVec, vPt, vTr)) {
|
||||
FacetMap.emplace( nF, make_pair( vPt, vTr)) ;
|
||||
}
|
||||
// Se non riesco a triangolare anche solo questa faccia, interrompo tutto
|
||||
else
|
||||
return false ;
|
||||
}
|
||||
}
|
||||
|
||||
// Ciclo sulle facce da ritriangolare per eliminare i triangoli.
|
||||
// Ciclo sulle facce da ritriangolare per eliminare i triangoli (nel contempo salvo flag colore)
|
||||
unordered_map< int, int> ColorMap ;
|
||||
for ( auto itF = FacetMap.begin() ; itF != FacetMap.end() ; ++ itF) {
|
||||
// Cancello i triangoli della faccia.
|
||||
// Recupero i triangoli della faccia
|
||||
INTVECTOR vFacetTria ;
|
||||
GetAllTriaInFacet( itF->first, vFacetTria) ;
|
||||
for ( int& nT : vFacetTria)
|
||||
// Salvo il colore della faccia da flag di un suo triangolo
|
||||
ColorMap.emplace( itF->first, m_vTria[m_vFacet[itF->first]].nTFlag) ;
|
||||
// Cancello i triangoli della faccia.
|
||||
for ( int nT : vFacetTria)
|
||||
RemoveTriangle( nT) ;
|
||||
}
|
||||
// Ritriangolo le facce.
|
||||
for ( auto itF = FacetMap.begin() ; itF != FacetMap.end() ; ++ itF) {
|
||||
// Ritriangolo la faccia.
|
||||
PNTVECTOR vPt ;
|
||||
INTVECTOR vTr ;
|
||||
if ( Triangulate().Make( itF->second, vPt, vTr)) {
|
||||
// Inserisco i nuovi triangoli.
|
||||
for ( int n = 0 ; n < int( vTr.size()) - 2 ; n += 3) {
|
||||
int nNewTriaVertId[3] = { vTr[n], vTr[n + 1], vTr[n + 2] } ;
|
||||
int nNewId[3] = { AddVertex(vPt[nNewTriaVertId[0]]),
|
||||
AddVertex(vPt[nNewTriaVertId[1]]),
|
||||
AddVertex(vPt[nNewTriaVertId[2]]) } ;
|
||||
// Il colore passato nel secondo parametro è definito perché il vettore delle facce ha ancora salvato l'indice di un suo triangolo e
|
||||
// il triangolo è cancellato semplicente assegnadno la costante apposita VT_DEL (-2) a nIdVert[0]; ma il suo colore resta definito.
|
||||
int nNewTriaNum = AddTriangle( nNewId, m_vTria[m_vFacet[itF->first]].nTFlag) ;
|
||||
}
|
||||
|
||||
// Applico le nuove triangolazioni delle facce
|
||||
for ( auto itFac = FacetMap.begin() ; itFac != FacetMap.end() ; ++ itFac) {
|
||||
const PNTVECTOR& vPt = itFac->second.first ;
|
||||
const INTVECTOR& vTr = itFac->second.second ;
|
||||
// Inserisco i nuovi triangoli
|
||||
for ( int n = 0 ; n < int( vTr.size()) - 2 ; n += 3) {
|
||||
int nNewId[3] = { AddVertex( vPt[vTr[n]]),
|
||||
AddVertex( vPt[vTr[n + 1]]),
|
||||
AddVertex( vPt[vTr[n + 2]])} ;
|
||||
auto itCol = ColorMap.find( itFac->first) ;
|
||||
int nTFlag = ( itCol != ColorMap.end() ? itCol->second : 0) ;
|
||||
int nNewTriaId = AddTriangle( nNewId, nTFlag) ;
|
||||
}
|
||||
}
|
||||
|
||||
return AdjustVertices() && DoCompacting() ;
|
||||
}
|
||||
// dichiaro necessità ricalcolo della grafica e di hashgrids3d
|
||||
m_OGrMgr.Reset() ;
|
||||
ResetHashGrids3d() ;
|
||||
|
||||
// Eseguo aggiustamenti
|
||||
return ( AdjustVertices() && DoCompacting()) ;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user