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:
DarioS
2021-11-02 08:19:11 +01:00
parent 6deff01b6e
commit 76d009ddbe
7 changed files with 680 additions and 1236 deletions
+207 -183
View File
@@ -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()) ;
}