Files
EgtGeomKernel/SurfTriMeshUtilities.cpp
T
2021-10-27 17:53:12 +02:00

226 lines
11 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2015-2015
//----------------------------------------------------------------------------
// File : SurfTriMeshUtilities.cpp Data : 25.10.21 Versione :
// Contenuto : Implementazione della classe Superfici TriMesh.
//
//
//
// Modifiche : 25.10.21 LM Creazione modulo.
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "Triangulate.h"
#include "SurfTriMesh.h"
#include "DistPointLine.h"
#include <unordered_map>
using namespace std ;
//----------------------------------------------------------------------------
bool
SurfTriMesh::SimplifyFacets( double dMaxEdgeLen)
{
// Se la lunghezza massima del lato del triangolo sul bordo della faccia è nulla, ho finito.
if ( dMaxEdgeLen < EPS_SMALL)
return true ;
// Le superfici devono essere valide.
if ( ! IsValid())
return false ;
// Verifico la definizione delle facce.
VerifyFaceting() ;
// 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.
POLYLINEVECTOR LoopVec ;
GetFacetLoops( nF, LoopVec) ;
// Recupero le adiacenze della faccia.
INTMATRIX vAdj ;
GetFacetAdjacencies( nF, vAdj) ;
// Ciclo sui loop della faccia.
for ( int nL = 0 ; nL < int( LoopVec.size()) ; ++ nL) {
// 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 ;
}
}
}
}
}
if ( bFacetToRetriangulate) {
FacetMap.emplace( nF, LoopVec) ;
}
}
// Ciclo sulle facce da ritriangolare per eliminare i triangoli.
for ( auto itF = FacetMap.begin() ; itF != FacetMap.end() ; ++ itF) {
// Cancello i triangoli della faccia.
INTVECTOR vFacetTria ;
GetAllTriaInFacet( itF->first, vFacetTria) ;
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) ;
}
}
}
return AdjustVertices() && DoCompacting() ;
}