ffad8c6dd2
- correzioni alle operazioni booleane tra superfici trimesh.
2725 lines
121 KiB
C++
2725 lines
121 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2019-2019
|
|
//----------------------------------------------------------------------------
|
|
// File : SurfTriMeshBooleans.cpp Data : 27.05.19 Versione : 2.1e5
|
|
// Contenuto : Implementazione delle funzioni booleane per SurfFTrimesh.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 10.05.19 LM Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "stdafx.h"
|
|
#include "SurfTriMesh.h"
|
|
#include "CurveLine.h"
|
|
#include "CurveComposite.h"
|
|
#include "SurfFlatRegion.h"
|
|
#include "DistPointLine.h"
|
|
#include "Triangulate.h"
|
|
#include "GeoConst.h"
|
|
#include "/EgtDev/Include/EgkCurve.h"
|
|
#include "/EgtDev/Include/EgkDistPointCurve.h"
|
|
#include "/EgtDev/Include/EgkDistPointTria.h"
|
|
#include "/EgtDev/Include/EgkIntersLineTria.h"
|
|
#include "/EgtDev/Include/EgkIntersTriaTria.h"
|
|
#include "/EgtDev/Include/EGkChainCurves.h"
|
|
#include "/EgtDev/Include/EGkGeoCollection.h"
|
|
#include "/EgtDev/Include/EGkPolygon3d.h"
|
|
#include <algorithm>
|
|
|
|
using namespace std ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
int
|
|
IntersRectangleTriangle( const Point3d& ptP, const Vector3d& vtL1, const Vector3d& vtL2,
|
|
const Triangle3d& trTria, Point3d& ptStSeg, Point3d& ptEnSeg)
|
|
{
|
|
// Definisco i due triangoli formanti il rettangolo
|
|
Triangle3d trTriaA ;
|
|
trTriaA.Set( ptP, ptP + vtL1, ptP + vtL2) ;
|
|
if ( ! trTriaA.Validate())
|
|
return -1 ;
|
|
Triangle3d trTriaB ;
|
|
trTriaB.Set( ptP + vtL1, ptP + vtL1 + vtL2, ptP + vtL2) ;
|
|
if ( ! trTriaB.Validate())
|
|
return -1 ;
|
|
// Interseco il triangolo con il primo dei due triangoli del rettangolo
|
|
int nIntA = 0 ;
|
|
Point3d ptIntA1, ptIntA2 ;
|
|
TRIA3DVECTOR vTriaA ;
|
|
int nIntTypeA = IntersTriaTria( trTria, trTriaA, ptIntA1, ptIntA2, vTriaA) ;
|
|
if ( FromSpecialToNormal( nIntTypeA) == ITTT_PNT || FromSpecialToNormal( nIntTypeA) == ITTT_VERT)
|
|
nIntA = 1 ;
|
|
else if ( FromSpecialToNormal( nIntTypeA) == ITTT_YES || FromSpecialToNormal( nIntTypeA) == ITTT_EDGE) {
|
|
nIntA = 2 ;
|
|
}
|
|
// Interseco il triangolo con il secondo dei due triangoli del rettangolo
|
|
int nIntB = 0 ;
|
|
Point3d ptIntB1, ptIntB2 ;
|
|
TRIA3DVECTOR vTriaB ;
|
|
int nIntTypeB = IntersTriaTria( trTria, trTriaB, ptIntB1, ptIntB2, vTriaB) ;
|
|
if ( FromSpecialToNormal( nIntTypeB) == ITTT_PNT || FromSpecialToNormal( nIntTypeB) == ITTT_VERT)
|
|
nIntB = 1 ;
|
|
else if ( FromSpecialToNormal( nIntTypeB) == ITTT_YES || FromSpecialToNormal( nIntTypeB) == ITTT_EDGE) {
|
|
nIntB = 2 ;
|
|
}
|
|
// Unisco le due intersezioni
|
|
int nIntTot = nIntA + nIntB ;
|
|
if ( nIntTot == 4) {
|
|
if ( AreSamePointApprox( ptIntA2, ptIntB1)) {
|
|
ptStSeg = ptIntA1 ;
|
|
ptEnSeg = ptIntB2 ;
|
|
}
|
|
else {
|
|
ptStSeg = ptIntB1 ;
|
|
ptEnSeg = ptIntA2 ;
|
|
}
|
|
return 2 ;
|
|
}
|
|
else if ( nIntTot == 3) {
|
|
if ( nIntA == 2) {
|
|
ptStSeg = ptIntA1 ;
|
|
ptEnSeg = ptIntA2 ;
|
|
}
|
|
else {
|
|
ptStSeg = ptIntB1 ;
|
|
ptEnSeg = ptIntB2 ;
|
|
}
|
|
return 2 ;
|
|
}
|
|
else if ( nIntTot == 2) {
|
|
if ( nIntA == 2) {
|
|
ptStSeg = ptIntA1 ;
|
|
ptEnSeg = ptIntA2 ;
|
|
}
|
|
else if ( nIntA == 1) {
|
|
ptStSeg = ptIntA1 ;
|
|
ptEnSeg = ptIntB1 ;
|
|
}
|
|
else {
|
|
ptStSeg = ptIntB1 ;
|
|
ptEnSeg = ptIntB2 ;
|
|
}
|
|
return 2 ;
|
|
}
|
|
else if ( nIntTot == 1) {
|
|
if ( nIntA == 1)
|
|
ptStSeg = ptIntA1 ;
|
|
else
|
|
ptStSeg = ptIntB1 ;
|
|
return 1 ;
|
|
}
|
|
else
|
|
return 0 ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
ChangeStart( const Point3d& ptNewStart, PNTVECTOR& Loop)
|
|
{
|
|
// Cerco se esiste un tratto del loop chiuso su cui giace il punto
|
|
int nSeg = - 1 ;
|
|
for ( int nPt = 0 ; nPt < int( Loop.size()) && nSeg == - 1 ; ++ nPt) {
|
|
// Estremi del segmento corrente del loop
|
|
Point3d ptSegSt = Loop[nPt] ;
|
|
Point3d ptSegEn = Loop[( nPt + 1) % int( Loop.size())] ;
|
|
// Vedo se il punto giace sul segmento del loop
|
|
DistPointLine dDistCalc( ptNewStart, ptSegSt, ptSegEn) ;
|
|
double dSqDist ;
|
|
dDistCalc.GetSqDist( dSqDist) ;
|
|
if ( dSqDist < SQ_EPS_SMALL) {
|
|
nSeg = nPt ;
|
|
}
|
|
}
|
|
// Se il punto non sta sul loop, errore
|
|
if ( nSeg == - 1)
|
|
return false ;
|
|
// Verifico che il punto stia su un vertice, in tal caso non devo fare nulla
|
|
bool bOnStart = AreSamePointApprox( Loop[nSeg], ptNewStart) ;
|
|
bool bOnEnd = AreSamePointApprox( Loop[( nSeg + 1) % int( Loop.size())], ptNewStart) ;
|
|
if ( bOnStart || bOnEnd) {
|
|
if ( bOnEnd) {
|
|
++ nSeg ;
|
|
if ( nSeg % int( Loop.size()) == 0)
|
|
return true ;
|
|
}
|
|
PNTVECTOR vTempVec ;
|
|
for ( int nPt = 0 ; nPt < nSeg ; ++ nPt)
|
|
vTempVec.emplace_back( Loop[nPt]) ;
|
|
int nSize = int( Loop.size()) ;
|
|
for ( int nPt = 0 ; nPt < nSize - nSeg ; ++ nPt) {
|
|
Loop[nPt] = Loop[nPt + nSeg] ;
|
|
}
|
|
for ( int nPt = 0 ; nPt < int( vTempVec.size()) ; ++ nPt) {
|
|
Loop[nPt + nSize - nSeg] = vTempVec[nPt] ;
|
|
}
|
|
return true ;
|
|
}
|
|
// Ridimensiono il loop
|
|
Loop.resize( Loop.size() + 1) ;
|
|
// Copio i primi punti
|
|
PNTVECTOR LoopTemp ;
|
|
for ( int nPt = 0 ; nPt <= nSeg ; ++ nPt)
|
|
LoopTemp.emplace_back( Loop[nPt]) ;
|
|
// Aggiungo il nuovo punto all'inizio
|
|
Loop[0] = ptNewStart ;
|
|
// Sposto gli ultimi in testa
|
|
int nLastPointNum = int( Loop.size()) - 1 - nSeg ;
|
|
for ( int nPt = 1 ; nPt <= nLastPointNum ; ++ nPt) {
|
|
Loop[nPt] = Loop[nPt + nSeg] ;
|
|
}
|
|
// Porto i primi in fondo
|
|
for ( int nPt = 0 ; nPt < int( LoopTemp.size()) ; ++ nPt) {
|
|
Loop[nPt + nLastPointNum] = LoopTemp[nPt] ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SplitAtPoint( const Point3d& ptStop, const PNTVECTOR& Loop, PNTVECTOR& Loop1, PNTVECTOR& Loop2)
|
|
{
|
|
// Cerco se esiste un tratto del loop chiuso su cui giace il punto
|
|
int nSeg = - 1 ;
|
|
for ( int nPt = 0 ; nPt < int( Loop.size()) && nSeg == - 1 ; ++ nPt) {
|
|
// Estremi del segmento corrente del loop
|
|
Point3d ptSegSt = Loop[nPt] ;
|
|
Point3d ptSegEn = Loop[( nPt + 1) % int( Loop.size())] ;
|
|
// Vedo se il punto giace sul segmento del loop
|
|
DistPointLine dDistCalc( ptStop, ptSegSt, ptSegEn) ;
|
|
double dSqDist ;
|
|
dDistCalc.GetSqDist( dSqDist) ;
|
|
if ( dSqDist < SQ_EPS_SMALL) {
|
|
nSeg = nPt ;
|
|
}
|
|
}
|
|
// Se il punto non sta sul loop, errore
|
|
if ( nSeg == - 1)
|
|
return false ;
|
|
// Verifico che il punto stia su un vertice, in tal caso non devo aggiungerlo
|
|
bool bFirst = AreSamePointApprox( Loop[nSeg], ptStop) ;
|
|
bool bLast = AreSamePointApprox( Loop[( nSeg + 1) % int( Loop.size())], ptStop) ;
|
|
// Se il punto è sul vertice finale del segmento, aggiungo il vertice alla lista da inglobare al primo loop
|
|
if ( bLast)
|
|
++ nSeg ;
|
|
// Inglobo fino a nSeg nel primo loop
|
|
for ( int nPt = 0 ; nPt <= nSeg ; ++ nPt)
|
|
Loop1.emplace_back( Loop[nPt]) ;
|
|
// Se il punto è interno al segmento, lo inglobo in entrambi i loop
|
|
if ( ! ( bFirst || bLast)) {
|
|
Loop1.emplace_back( ptStop) ;
|
|
Loop2.emplace_back( ptStop) ;
|
|
}
|
|
else {
|
|
Loop2.emplace_back( Loop[nSeg]) ;
|
|
}
|
|
// Inglobo gli ultimi vertici in Loop2
|
|
for ( int nPt = nSeg + 1 ; nPt < int( Loop.size()) ; ++ nPt)
|
|
Loop2.emplace_back( Loop[nPt]) ;
|
|
Loop2.emplace_back( Loop[0]) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
AddChainToChain( const Chain& ChainToAdd, PNTVECTOR& OrigChain)
|
|
{
|
|
// Se la catena da aggiungere è vuota, non devo fare alcunchè
|
|
if ( ChainToAdd.size() == 0)
|
|
return true ;
|
|
// Se la catena originale è vuota, non è possibile aggiungere nulla
|
|
if ( OrigChain.size() == 0)
|
|
return false ;
|
|
// Se la catena originale è chiusa non posso aggiungere nulla
|
|
int nLastOrig = max( int( OrigChain.size()) - 1, 0) ;
|
|
if ( AreSamePointApprox( OrigChain[0], OrigChain[nLastOrig]))
|
|
return false ;
|
|
int nLastToAdd = max( int( ChainToAdd.size()) - 1, 0) ;
|
|
if ( AreSamePointApprox( OrigChain[nLastOrig], ChainToAdd[0].ptSt)) {
|
|
for ( int nPt = 1 ; nPt <= nLastToAdd ; ++ nPt) {
|
|
if ( nPt == nLastToAdd) {
|
|
if ( ! AreSamePointApprox(OrigChain[0], ChainToAdd[nPt].ptSt))
|
|
OrigChain.emplace_back( ChainToAdd[nPt].ptSt) ;
|
|
}
|
|
else if ( nPt == 1) {
|
|
if ( ! AreSamePointApprox( OrigChain[nLastOrig], ChainToAdd[nPt].ptSt))
|
|
OrigChain.emplace_back( ChainToAdd[nPt].ptSt) ;
|
|
}
|
|
else
|
|
OrigChain.emplace_back( ChainToAdd[nPt].ptSt) ;
|
|
}
|
|
return true ;
|
|
}
|
|
/*else if ( AreSamePointApprox( OrigChain[0], ChainToAdd[nLastToAdd].ptEn)) {
|
|
int nOldDim = OrigChain.size() ;
|
|
int nNewDim = nOldDim + ChainToAdd.size() + 1 ;
|
|
OrigChain.resize( nNewDim) ;
|
|
int nShift = std::max( nNewDim - nOldDim, 0) ;
|
|
for ( int nPt = nOldDim - 1 ; nPt >= 0 ; -- nPt) {
|
|
OrigChain[nPt + nShift] = OrigChain[nPt] ;
|
|
}
|
|
for ( int nPt = 0 ; nPt < int( ChainToAdd.size()) ; ++ nPt) {
|
|
OrigChain[nPt] = ChainToAdd[nPt].ptSt ;
|
|
}
|
|
OrigChain[int( ChainToAdd.size())] = ChainToAdd[int(ChainToAdd.size()) - 1].ptEn ;
|
|
return true ;
|
|
}*/
|
|
else
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq)
|
|
{
|
|
// La superficie deve essere valida
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// La curva deve essere valida e chiusa, il vettore estrusione deve essere non nullo
|
|
Vector3d vtExtr ;
|
|
if ( ! cvCurve.GetExtrusion( vtExtr) || vtExtr.IsSmall() || ! cvCurve.IsClosed())
|
|
return false ;
|
|
// Approssimo la curva con segmenti
|
|
CurveComposite cvCompo ;
|
|
PolyLine PL ;
|
|
if ( ! cvCurve.ApproxWithLines( LIN_TOL_FINE, ANG_TOL_STD_DEG, ICurve::APL_STD, PL) || ! cvCompo.FromPolyLine( PL))
|
|
return false ;
|
|
// Appiattisco la polilinea nel piano perpendicolare all'estrusione
|
|
Frame3d frCurve ;
|
|
Point3d ptStart ; cvCompo.GetStartPoint( ptStart) ;
|
|
frCurve.Set( ptStart, vtExtr) ;
|
|
cvCompo.ToLoc( frCurve) ;
|
|
if ( ! cvCompo.Scale( GLOB_FRM, 1, 1, 0))
|
|
return false ;
|
|
double dArea ;
|
|
cvCompo.GetAreaXY( dArea) ;
|
|
BBox3d b3Crv ;
|
|
cvCompo.GetLocalBBox( b3Crv) ;
|
|
cvCompo.ToGlob( frCurve) ;
|
|
// Assegno il senso di rotazione della curva (visto dalla punta del vettore estrusione)
|
|
bool bCCW = ( dArea > 0) ;
|
|
// Recupero Bounding-box della trimesh
|
|
BBox3d b3SurfBox ;
|
|
GetLocalBBox( b3SurfBox) ;
|
|
// Trovo minima e massima distanza dei vertici del bounding-box della TriMesh dal piano della curva
|
|
b3SurfBox.ToLoc( frCurve) ;
|
|
Point3d ptMin, ptMax ;
|
|
b3SurfBox.GetMinMax( ptMin, ptMax) ;
|
|
Vector3d vtMax = ( ptMax.z + 10) * vtExtr ;
|
|
Vector3d vtMin = ( ptMin.z - 10) * vtExtr ;
|
|
|
|
// Ciclo sui triangoli
|
|
bool bModif = false ;
|
|
int nNumTria = GetTriangleSize() ;
|
|
for ( int nT = 0 ; nT < nNumTria ; ++ nT) {
|
|
// Recupero il triangolo
|
|
Triangle3d trTria ;
|
|
if ( ! GetTriangle( nT, trTria))
|
|
continue ;
|
|
// Box del triangolo nel riferimento locale della curva
|
|
BBox3d b3Tria ;
|
|
trTria.GetLocalBBox( b3Tria) ;
|
|
b3Tria.ToLoc( frCurve) ;
|
|
// Se il box del triangolo non interseca quello locale della curva
|
|
if ( ! b3Crv.OverlapsXY( b3Tria)) {
|
|
// Se la parte da conservare è quella all'interno della curva, elimino il triangolo
|
|
if ( bCCW) {
|
|
RemoveTriangle( nT) ;
|
|
bModif = true ;
|
|
}
|
|
continue ;
|
|
}
|
|
// Determino il numero di vertici del triangolo che cadono all'interno della curva
|
|
int nVertInside = 0 ;
|
|
for ( int nV = 0 ; nV < 3 ; ++ nV) {
|
|
// Determino se il vertice cade dentro la curva
|
|
DistPointCurve dstPC( trTria.GetP( nV), cvCompo) ;
|
|
int nSide ;
|
|
dstPC.GetSideAtMinDistPoint( 0, vtExtr, nSide) ;
|
|
if ( nSide == MDS_LEFT || nSide == MDS_ON)
|
|
++ nVertInside ;
|
|
}
|
|
// Vettore di catene di punti
|
|
CHAINVECTOR vChain ;
|
|
// Ciclo sui segmenti
|
|
bool bStartInside = false ;
|
|
int nChainCnt = 0 ;
|
|
bool bChain = false ;
|
|
Point3d ptChSt, ptChEn ;
|
|
const ICurve* pCrv = cvCompo.GetFirstCurve() ;
|
|
while ( pCrv != nullptr) {
|
|
// estremi del segmento
|
|
Point3d ptSt ; pCrv->GetStartPoint( ptSt) ;
|
|
Point3d ptEn ; pCrv->GetEndPoint( ptEn) ;
|
|
// Intersezione fra il rettangolo (ottenuto dall'estrusione del segmento corrente) e il triangolo
|
|
Point3d ptSegSt, ptSegEn ;
|
|
int nInt = IntersRectangleTriangle( ptSt + vtMin, ptEn - ptSt, vtMax - vtMin, trTria, ptSegSt, ptSegEn) ;
|
|
if ( nInt != 0) {
|
|
// Creo nuova catena se non c'è già o se discontinuità
|
|
if ( ! bChain || ( ! AreSamePointApprox( ptSegSt, ptChEn) && ! AreSamePointApprox( ptSegEn, ptChSt))) {
|
|
++ nChainCnt ;
|
|
vChain.resize( nChainCnt) ;
|
|
bChain = false ;
|
|
}
|
|
// Assegno i dati di intersezione
|
|
IntSegment CurInters ;
|
|
if ( nInt == 2) {
|
|
CurInters.ptSt = ptSegSt ;
|
|
CurInters.ptEn = ptSegEn ;
|
|
CurInters.bDegenerate = false ;
|
|
}
|
|
else {
|
|
CurInters.ptSt = ptSegSt ;
|
|
CurInters.ptEn = ptSegSt ;
|
|
CurInters.bDegenerate = true ;
|
|
}
|
|
CurInters.vtOuter = ( ptEn - ptSt) ^ vtExtr ;
|
|
CurInters.vtOuter.Normalize() ;
|
|
// Inserisco nella catena
|
|
if ( ! bChain) {
|
|
vChain[nChainCnt - 1].emplace_back( CurInters) ;
|
|
ptChSt = CurInters.ptSt ;
|
|
ptChEn = CurInters.ptEn ;
|
|
}
|
|
else if ( AreSamePointApprox( ptSegSt, ptChEn)) {
|
|
vChain[nChainCnt - 1].emplace_back( CurInters) ;
|
|
ptChEn = CurInters.ptEn ;
|
|
}
|
|
else {
|
|
vChain[nChainCnt - 1].insert( vChain[nChainCnt - 1].begin(), CurInters) ;
|
|
ptChSt = CurInters.ptSt ;
|
|
}
|
|
bChain = true ;
|
|
}
|
|
else {
|
|
bChain = false ;
|
|
}
|
|
pCrv = cvCompo.GetNextCurve() ;
|
|
}
|
|
// unisco eventuali catene estreme che sono parte di una stessa catena
|
|
if ( nChainCnt > 1) {
|
|
if ( AreSamePointApprox( vChain[0].front().ptSt, vChain[nChainCnt-1].back().ptEn)) {
|
|
vChain[0].insert( vChain[0].begin(), vChain[nChainCnt-1].begin(), vChain[nChainCnt-1].end()) ;
|
|
vChain.pop_back() ;
|
|
-- nChainCnt ;
|
|
}
|
|
else if ( AreSamePointApprox( vChain[0].back().ptEn, vChain[nChainCnt-1].front().ptSt)) {
|
|
vChain[0].insert( vChain[0].end(), vChain[nChainCnt-1].begin(), vChain[nChainCnt-1].end()) ;
|
|
vChain.pop_back() ;
|
|
-- nChainCnt ;
|
|
}
|
|
}
|
|
// semplifico catene formate da punti degeneri
|
|
for ( int nCh = 0 ; nCh < nChainCnt ; ++ nCh) {
|
|
if ( vChain[nCh].size() == 2 && ( vChain[nCh][0].bDegenerate || vChain[nCh][1].bDegenerate)) {
|
|
vChain[nCh][0].ptEn = vChain[nCh][1].ptEn ;
|
|
vChain[nCh][0].vtOuter = ( vChain[nCh][0].bDegenerate ? vChain[nCh][1].vtOuter : vChain[nCh][0].vtOuter) ;
|
|
vChain[nCh][0].bDegenerate = AreSamePointApprox( vChain[nCh][0].ptSt, vChain[nCh][0].ptEn) ;
|
|
vChain[nCh].resize( 1) ;
|
|
}
|
|
}
|
|
// Elimino la seconda copia di catene doppie
|
|
for ( int nI = 0 ; nI < nChainCnt ; ++ nI) {
|
|
for ( int nJ = nI + 1 ; nJ < nChainCnt ; ++ nJ) {
|
|
if ( vChain[nI].size() == vChain[nJ].size()) {
|
|
bool bSame = true ;
|
|
for ( int nK = 0 ; nK < int( vChain[nI].size()) ; ++ nK) {
|
|
if ( ! AreSamePointApprox( vChain[nI][nK].ptSt, vChain[nJ][nK].ptSt) ||
|
|
! AreSamePointApprox( vChain[nI][nK].ptEn, vChain[nJ][nK].ptEn)) {
|
|
bSame = false ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( bSame) {
|
|
vChain.erase( vChain.begin() + nJ) ;
|
|
-- nChainCnt ;
|
|
-- nJ ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fra le catene trovate separo le aperte dalle chiuse
|
|
int nDegenerateChainNum = 0 ;
|
|
INTVECTOR vnDegVec ;
|
|
CHAINVECTOR cvClosedChain ;
|
|
CHAINVECTOR cvOpenChain ;
|
|
for ( int nL = 0 ; nL < int( vChain.size()) ; ++ nL) {
|
|
bool bChainDegenerate = false ;
|
|
if ( vChain[nL].size() == 1 && AreSamePointApprox( vChain[nL][0].ptSt, vChain[nL][0].ptEn)) {
|
|
bChainDegenerate = true ;
|
|
}
|
|
|
|
if ( bChainDegenerate)
|
|
++ nDegenerateChainNum ;
|
|
int nCurLoopLast = max( int( vChain[nL].size()) - 1, 0) ;
|
|
if ( ( ! bChainDegenerate) && AreSamePointApprox( vChain[nL][0].ptSt, vChain[nL][nCurLoopLast].ptEn))
|
|
cvClosedChain.emplace_back( vChain[nL]) ;
|
|
else {
|
|
cvOpenChain.emplace_back( vChain[nL]) ;
|
|
if ( bChainDegenerate)
|
|
vnDegVec.emplace_back( 0) ;
|
|
else
|
|
vnDegVec.emplace_back( 1) ;
|
|
}
|
|
}
|
|
|
|
// Se più di una catena chiusa oppure catene chiuse e aperte, errore
|
|
if ( cvClosedChain.size() > 1 ||
|
|
( cvClosedChain.size() > 0 && int( cvOpenChain.size()) > nDegenerateChainNum))
|
|
return false ;
|
|
|
|
// Se c'è una catena chiusa
|
|
if ( cvClosedChain.size() == 1) {
|
|
// Ne ricavo una PolyLine
|
|
PolyLine plInLoop ;
|
|
for ( int nLine = 0 ; nLine < int( cvClosedChain[0].size()) ; ++ nLine) {
|
|
plInLoop.AddUPoint( 0., cvClosedChain[0][nLine].ptSt) ;
|
|
plInLoop.AddUPoint( 0., cvClosedChain[0][nLine].ptEn) ;
|
|
}
|
|
// I tre vertici sono dalla parte interna della curva (triangolo con buco)
|
|
if ( ! bCCW) {
|
|
// Rimuovo il triangolo corrente
|
|
RemoveTriangle( nT) ;
|
|
// Definisco il loop esterno (è il triangolo)
|
|
PolyLine plExtLoop ;
|
|
plExtLoop.AddUPoint( 0., trTria.GetP( 0)) ;
|
|
plExtLoop.AddUPoint( 0., trTria.GetP( 1)) ;
|
|
plExtLoop.AddUPoint( 0., trTria.GetP( 2)) ;
|
|
plExtLoop.AddUPoint( 0., trTria.GetP( 0)) ;
|
|
// Eseguo triangolazione
|
|
POLYLINEVECTOR vPL ;
|
|
vPL.emplace_back( plExtLoop) ;
|
|
vPL.emplace_back( plInLoop) ;
|
|
PNTVECTOR vPt ;
|
|
INTVECTOR vTr ;
|
|
if ( Triangulate().Make( vPL, 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]]) } ;
|
|
AddTriangle( nNewId) ;
|
|
bModif = true ;
|
|
}
|
|
}
|
|
}
|
|
// Se nessun vertice dalla parte interna della curva (rimane solo l'area della curva)
|
|
else {
|
|
// Rimuovo il triangolo corrente
|
|
RemoveTriangle( nT) ;
|
|
// Eseguo triangolazione
|
|
PNTVECTOR vPt ;
|
|
INTVECTOR vTr ;
|
|
if ( Triangulate().Make( plInLoop, 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]]) } ;
|
|
AddTriangle( nNewId) ;
|
|
bModif = true ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Loop aperti, devo chiuderli
|
|
else if ( cvOpenChain.size() > 0) {
|
|
|
|
// Creo il loop chiuso padre di tutti, il perimetro del triangolo.
|
|
// Questo viene diviso in sotto-loop chiusi mediante quelli aperti.
|
|
// I loop chiusi trovati precedentemente sono interni a uno dei sotto-loop
|
|
// chiusi di cui è formato il perimetro.
|
|
PNTVECTOR cvFirstLoop ;
|
|
cvFirstLoop.emplace_back( trTria.GetP( 0)) ;
|
|
cvFirstLoop.emplace_back( trTria.GetP( 1)) ;
|
|
cvFirstLoop.emplace_back( trTria.GetP( 2)) ;
|
|
|
|
vector<PNTVECTOR> cvBoundClosedLoopVec ;
|
|
cvBoundClosedLoopVec.emplace_back(cvFirstLoop);
|
|
BOOLVECTOR vbInOut ;
|
|
vbInOut.push_back( true) ;
|
|
// Divido il loop di partenza in sotto-loop
|
|
while ( cvOpenChain.size() > 0) {
|
|
int nLastOpenLoopN = int( cvOpenChain.size()) - 1 ;
|
|
if ( vnDegVec[nLastOpenLoopN] == 1) {
|
|
for ( int nLoop = 0 ; nLoop < int( cvBoundClosedLoopVec.size()) ; ++ nLoop) {
|
|
// Estremi del loop aperto
|
|
int nLastOpenLoopPoint = max( int( cvOpenChain[nLastOpenLoopN].size()) - 1, 0) ;
|
|
Point3d ptOpenLoopStP = cvOpenChain[nLastOpenLoopN][0].ptSt ;
|
|
Point3d ptOpenLoopEnP = cvOpenChain[nLastOpenLoopN][nLastOpenLoopPoint].ptEn ;
|
|
PNTVECTOR Loop1, Loop2 ;
|
|
bool bChangedStart = ChangeStart( ptOpenLoopStP, cvBoundClosedLoopVec[nLoop]) ;
|
|
bool bSplitted = SplitAtPoint( ptOpenLoopEnP, cvBoundClosedLoopVec[nLoop], Loop1, Loop2) ;
|
|
if ( ! ( bChangedStart && bSplitted))
|
|
continue ;
|
|
Chain cvCounterChain ;
|
|
for ( int nPt = int( cvOpenChain[nLastOpenLoopN].size()) - 1 ; nPt >= 0 ; -- nPt) {
|
|
IntSegment CurSeg ;
|
|
CurSeg.ptSt = cvOpenChain[nLastOpenLoopN][nPt].ptEn ;
|
|
CurSeg.ptEn = cvOpenChain[nLastOpenLoopN][nPt].ptSt ;
|
|
CurSeg.vtOuter = - cvOpenChain[nLastOpenLoopN][nPt].vtOuter ;
|
|
CurSeg.bDegenerate = cvOpenChain[nLastOpenLoopN][nPt].bDegenerate ;
|
|
cvCounterChain.emplace_back( CurSeg) ;
|
|
}
|
|
bool bAdded1 = AddChainToChain( cvCounterChain, Loop1) ;
|
|
bool bAdded2 = AddChainToChain( cvOpenChain[nLastOpenLoopN], Loop2) ;
|
|
if ( ! ( bAdded1 && bAdded2))
|
|
continue ;
|
|
// Aggiungo i nuovi loop nel vettore
|
|
int nCurSize = int( cvBoundClosedLoopVec.size()) ;
|
|
cvBoundClosedLoopVec.resize( nCurSize + 1) ;
|
|
vbInOut.resize( nCurSize + 1) ;
|
|
for ( int nCL = nCurSize - 1 ; nCL > nLoop ; -- nCL) {
|
|
cvBoundClosedLoopVec[nCL + 1] = cvBoundClosedLoopVec[nCL] ;
|
|
vbInOut[nCL + 1] = vbInOut[nCL] ;
|
|
}
|
|
int nLastPointLoop2 = int( Loop2.size()) - 1 ;
|
|
Vector3d vtTest = Loop1[1] - Loop1[0] ;
|
|
vtTest.Normalize() ;
|
|
bool bSecondInside = vtTest * cvOpenChain[nLastOpenLoopN][0].vtOuter < 0. ;
|
|
cvBoundClosedLoopVec[nLoop] = Loop1 ;
|
|
cvBoundClosedLoopVec[nLoop + 1] = Loop2 ;
|
|
vbInOut[nLoop] = bSecondInside ;
|
|
vbInOut[nLoop + 1] = ! bSecondInside ;
|
|
++ nLoop ;
|
|
}
|
|
}
|
|
// Degenere
|
|
else {
|
|
Point3d ptProva = 0.5 * ( cvOpenChain[nLastOpenLoopN][0].ptSt + cvOpenChain[nLastOpenLoopN][0].ptEn) ;
|
|
Vector3d vtVecProva = cvOpenChain[nLastOpenLoopN][0].vtOuter ;
|
|
vtVecProva.Normalize( EPS_ZERO) ;
|
|
for ( int nLoop = 0 ; nLoop < int( cvBoundClosedLoopVec.size()) ; ++ nLoop) {
|
|
// Estremi del loop aperto
|
|
int nLastOpenLoopPoint = max(int(cvOpenChain[nLastOpenLoopN].size()) - 1, 0) ;
|
|
Point3d ptOpenLoopStP = cvOpenChain[nLastOpenLoopN][0].ptSt ;
|
|
Point3d ptOpenLoopEnP = cvOpenChain[nLastOpenLoopN][0].ptEn ;
|
|
// Cerco se esistono dei tratti del loop chiuso corrente che sono
|
|
// toccati dagli estremi del loop aperto corrente
|
|
int nCvFirst = -1 ;
|
|
int nCvSecond = -1 ;
|
|
for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) && nCvSecond == -1 ; ++ nLine) {
|
|
// Estremi del segmento corrente del loop chiuso corrente
|
|
Point3d ptSegSt = cvBoundClosedLoopVec[nLoop][nLine] ;
|
|
Point3d ptSegEn = cvBoundClosedLoopVec[nLoop][( nLine + 1) % int( cvBoundClosedLoopVec[nLoop].size())] ;
|
|
// Vettore congiungente i su definiti punti
|
|
Vector3d vtClosedLoopSeg = ptSegEn - ptSegSt ;
|
|
vtClosedLoopSeg.Normalize() ;
|
|
// Vedo se gli estremi del loop aperto stanno su un segmento del chiuso
|
|
DistPointLine DistCalc( ptProva, ptSegSt, ptSegEn) ;
|
|
double dSqDist ;
|
|
DistCalc.GetSqDist( dSqDist) ;
|
|
if ( dSqDist < 2 * SQ_EPS_SMALL) {
|
|
if ( nCvFirst == -1)
|
|
nCvFirst = nLine ;
|
|
else
|
|
nCvSecond = nLine ;
|
|
}
|
|
}
|
|
|
|
if ( nCvFirst != nCvSecond && nCvSecond != -1) {
|
|
// li ordino in senso crescente
|
|
if ( nCvFirst > nCvSecond)
|
|
swap( nCvFirst, nCvSecond) ;
|
|
// punto medio tra primo e secondo
|
|
int nCount = 0 ;
|
|
Point3d ptM12 ;
|
|
for ( int i = nCvFirst + 1 ; i <= nCvSecond ; ++ i) {
|
|
ptM12 += cvBoundClosedLoopVec[nLoop][i] ;
|
|
++ nCount ;
|
|
}
|
|
ptM12 /= nCount ;
|
|
// Distanza quadrata media dei punti tra primo e secondo dal baricentro
|
|
double dVar12 = 0. ;
|
|
for ( int i = nCvFirst + 1 ; i <= nCvSecond ; ++ i) {
|
|
dVar12 += ( cvBoundClosedLoopVec[nLoop][i] - ptM12) * ( cvBoundClosedLoopVec[nLoop][i] - ptM12) ;
|
|
}
|
|
dVar12 /= nCount ;
|
|
// punto medio fra secondo e primo
|
|
nCount = 0 ;
|
|
Point3d ptM21 ;
|
|
for ( int i = nCvSecond + 1 ; i % int( cvBoundClosedLoopVec[nLoop].size()) ; ++ i) {
|
|
ptM21 += cvBoundClosedLoopVec[nLoop][i] ;
|
|
++ nCount ;
|
|
}
|
|
for ( int i = 0 ; i <= nCvFirst ; ++ i) {
|
|
ptM21 += cvBoundClosedLoopVec[nLoop][i] ;
|
|
++ nCount ;
|
|
}
|
|
ptM21 /= nCount ;
|
|
// Distanza quadrata media dei punti tra secondo e primo dal baricentro
|
|
double dVar21 = 0. ;
|
|
for ( int i = nCvSecond ; i < i % int( cvBoundClosedLoopVec[nLoop].size()) ; ++ i) {
|
|
dVar21 += ( cvBoundClosedLoopVec[nLoop][i] - ptM21) * ( cvBoundClosedLoopVec[nLoop][i] - ptM21) ;
|
|
++ nCount ;
|
|
}
|
|
for ( int i = 0 ; i <= nCvFirst ; ++ i) {
|
|
dVar21 += ( cvBoundClosedLoopVec[nLoop][i] - ptM21) * ( cvBoundClosedLoopVec[nLoop][i] - ptM21) ;
|
|
++ nCount ;
|
|
}
|
|
dVar21 /= nCount ;
|
|
// elimino i punti dalla parte non valida
|
|
if ( dVar12 > dVar21) {
|
|
// assegno i nuovi valori
|
|
cvBoundClosedLoopVec[nLoop][nCvFirst] = ptProva ;
|
|
cvBoundClosedLoopVec[nLoop][( nCvSecond + 1) % int(cvBoundClosedLoopVec[nLoop].size())] = ptProva ;
|
|
// numero totale di punti
|
|
int nPntTot = int( cvBoundClosedLoopVec[nLoop].size());
|
|
// elimino i punti superflui dopo
|
|
for ( int i = nPntTot - 1 ; i > nCvSecond + 1 ; -- i)
|
|
cvBoundClosedLoopVec[nLoop].pop_back() ;
|
|
// elimino i punti superflui prima
|
|
for ( int i = 0 ; i < nCvFirst ; ++ i)
|
|
cvBoundClosedLoopVec[nLoop].erase( cvBoundClosedLoopVec[nLoop].begin()) ;
|
|
// verifico se questo punto è dalla parte valida o no
|
|
bool bC12 = ( ( ptM12 - ptProva) * vtVecProva < 0) ;
|
|
vbInOut[nLoop] = bC12 ;
|
|
}
|
|
else {
|
|
// assegno i nuovi valori
|
|
cvBoundClosedLoopVec[nLoop][nCvFirst + 1] = ptProva ;
|
|
cvBoundClosedLoopVec[nLoop][nCvSecond] = ptProva ;
|
|
// elimino i punti superflui intermedi
|
|
for ( int i = nCvFirst + 2 ; i < nCvSecond ; ++ i)
|
|
cvBoundClosedLoopVec[nLoop].erase( cvBoundClosedLoopVec[nLoop].begin() + nCvFirst + 2) ;
|
|
// verifico se questo punto è dalla parte valida o no
|
|
bool bC21 = ( ( ptM21 - ptProva) * vtVecProva < 0) ;
|
|
vbInOut[nLoop] = bC21 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
vnDegVec.resize( nLastOpenLoopN) ;
|
|
cvOpenChain.resize( nLastOpenLoopN) ;
|
|
}
|
|
// Rimuovo il triangolo corrente
|
|
RemoveTriangle( nT) ;
|
|
// Trasformo i loop compositi in loop polyline
|
|
POLYLINEVECTOR vplPolyVec ;
|
|
vplPolyVec.resize( cvBoundClosedLoopVec.size()) ;
|
|
for ( int nLoop = 0 ; nLoop < int( vplPolyVec.size()) ; ++ nLoop) {
|
|
for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) ; ++ nLine) {
|
|
vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][nLine]) ;
|
|
}
|
|
vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][0]) ;
|
|
if ( vbInOut[nLoop]) {
|
|
// Eseguo triangolazione
|
|
Triangulate CreateTriangulation ;
|
|
PNTVECTOR vPt ;
|
|
INTVECTOR vTr ;
|
|
if ( Triangulate().Make( vplPolyVec[nLoop], 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]]) } ;
|
|
AddTriangle( nNewId) ;
|
|
bModif = true ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( nVertInside == 0)
|
|
RemoveTriangle( nT) ;
|
|
}
|
|
|
|
// Se avvenuta modifica, aggiorno tutto
|
|
if ( bModif)
|
|
return ( AdjustVertices() && DoCompacting()) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::DecomposeLoop( CHAINVECTOR& cvOpenChain, INTVECTOR& vnDegVec, vector<PNTVECTOR>& cvBoundClosedLoopVec, BOOLVECTOR& vbInOut)
|
|
{
|
|
// Divido il loop di partenza in sotto-loop
|
|
int nIterationCount = 0 ;
|
|
while ( cvOpenChain.size() > 0) {
|
|
bool bLoopSplitted = false ;
|
|
int nLastOpenLoopN = int( cvOpenChain.size()) - 1 ;
|
|
if ( vnDegVec[nLastOpenLoopN] == 1) {
|
|
for ( int nLoop = 0 ; nLoop < int( cvBoundClosedLoopVec.size()) ; ++ nLoop) {
|
|
// Estremi del loop aperto
|
|
int nLastOpenLoopPoint = max( int( cvOpenChain[nLastOpenLoopN].size()) - 1, 0) ;
|
|
Point3d ptOpenLoopStP = cvOpenChain[nLastOpenLoopN][0].ptSt ;
|
|
Point3d ptOpenLoopEnP = cvOpenChain[nLastOpenLoopN][nLastOpenLoopPoint].ptEn ;
|
|
PNTVECTOR Loop1, Loop2 ;
|
|
bool bChangedStart = ChangeStart( ptOpenLoopStP, cvBoundClosedLoopVec[nLoop]) ;
|
|
bool bSplitted = SplitAtPoint( ptOpenLoopEnP, cvBoundClosedLoopVec[nLoop], Loop1, Loop2) ;
|
|
if ( ! ( bChangedStart && bSplitted))
|
|
continue ;
|
|
bLoopSplitted = true ;
|
|
Chain cvCounterChain ;
|
|
for ( int nPt = int( cvOpenChain[nLastOpenLoopN].size()) - 1 ; nPt >= 0 ; -- nPt) {
|
|
IntSegment CurSeg ;
|
|
CurSeg.ptSt = cvOpenChain[nLastOpenLoopN][nPt].ptEn ;
|
|
CurSeg.ptEn = cvOpenChain[nLastOpenLoopN][nPt].ptSt ;
|
|
CurSeg.vtOuter = - cvOpenChain[nLastOpenLoopN][nPt].vtOuter ;
|
|
CurSeg.bDegenerate = cvOpenChain[nLastOpenLoopN][nPt].bDegenerate ;
|
|
cvCounterChain.emplace_back( CurSeg) ;
|
|
}
|
|
bool bAdded1 = AddChainToChain( cvCounterChain, Loop1) ;
|
|
bool bAdded2 = AddChainToChain( cvOpenChain[nLastOpenLoopN], Loop2) ;
|
|
if ( ! ( bAdded1 && bAdded2))
|
|
continue ;
|
|
// Aggiungo i nuovi loop nel vettore
|
|
int nCurSize = int( cvBoundClosedLoopVec.size()) ;
|
|
cvBoundClosedLoopVec.resize( nCurSize + 1) ;
|
|
vbInOut.resize( nCurSize + 1) ;
|
|
for ( int nCL = nCurSize - 1 ; nCL > nLoop ; -- nCL) {
|
|
cvBoundClosedLoopVec[nCL + 1] = cvBoundClosedLoopVec[nCL] ;
|
|
vbInOut[nCL + 1] = vbInOut[nCL] ;
|
|
}
|
|
int nLastPointLoop2 = int( Loop2.size()) - 1 ;
|
|
Vector3d vtTest = Loop1[1] - Loop1[0] ;
|
|
vtTest.Normalize() ;
|
|
bool bSecondInside = vtTest * cvOpenChain[nLastOpenLoopN][0].vtOuter < 0. ;
|
|
cvBoundClosedLoopVec[nLoop] = Loop1 ;
|
|
cvBoundClosedLoopVec[nLoop + 1] = Loop2 ;
|
|
vbInOut[nLoop] = bSecondInside ;
|
|
vbInOut[nLoop + 1] = ! bSecondInside ;
|
|
++ nLoop ;
|
|
}
|
|
}
|
|
// Degenere
|
|
else {
|
|
Point3d ptProva = 0.5 * ( cvOpenChain[nLastOpenLoopN][0].ptSt + cvOpenChain[nLastOpenLoopN][0].ptEn) ;
|
|
Vector3d vtVecProva = cvOpenChain[nLastOpenLoopN][0].vtOuter ;
|
|
vtVecProva.Normalize( EPS_ZERO) ;
|
|
for ( int nLoop = 0 ; nLoop < int( cvBoundClosedLoopVec.size()) ; ++ nLoop) {
|
|
// Estremi del loop aperto
|
|
int nLastOpenLoopPoint = max( int( cvOpenChain[nLastOpenLoopN].size()) - 1, 0) ;
|
|
Point3d ptOpenLoopStP = cvOpenChain[nLastOpenLoopN][0].ptSt ;
|
|
Point3d ptOpenLoopEnP = cvOpenChain[nLastOpenLoopN][0].ptEn ;
|
|
// Cerco se esistono dei tratti del loop chiuso corrente che sono
|
|
// toccati dagli estremi del loop aperto corrente
|
|
int nCvFirst = - 1 ;
|
|
int nCvSecond = - 1 ;
|
|
for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) && nCvSecond == - 1 ; ++ nLine) {
|
|
// Estremi del segmento corrente del loop chiuso corrente
|
|
Point3d ptSegSt = cvBoundClosedLoopVec[nLoop][nLine] ;
|
|
Point3d ptSegEn = cvBoundClosedLoopVec[nLoop][( nLine + 1) % int(cvBoundClosedLoopVec[nLoop].size())] ;
|
|
// Vettore congiungente i su definiti punti
|
|
Vector3d vtClosedLoopSeg = ptSegEn - ptSegSt ;
|
|
vtClosedLoopSeg.Normalize() ;
|
|
// Vedo se gli estremi del loop aperto stanno su un segmento del chiuso
|
|
DistPointLine DistCalc( ptProva, ptSegSt, ptSegEn) ;
|
|
double dSqDist ;
|
|
DistCalc.GetSqDist( dSqDist) ;
|
|
if ( dSqDist < 2 * SQ_EPS_SMALL) {
|
|
if ( nCvFirst == - 1)
|
|
nCvFirst = nLine ;
|
|
else
|
|
nCvSecond = nLine ;
|
|
}
|
|
}
|
|
|
|
if ( nCvFirst != nCvSecond && nCvSecond != - 1) {
|
|
// li ordino in senso crescente
|
|
if ( nCvFirst > nCvSecond)
|
|
swap( nCvFirst, nCvSecond) ;
|
|
// punto medio tra primo e secondo
|
|
int nCount = 0 ;
|
|
Point3d ptM12 ;
|
|
for ( int i = nCvFirst + 1 ; i <= nCvSecond ; ++ i) {
|
|
ptM12 += cvBoundClosedLoopVec[nLoop][i] ;
|
|
++ nCount ;
|
|
}
|
|
ptM12 /= nCount ;
|
|
// Distanza quadrata media dei punti tra primo e secondo dal baricentro
|
|
double dVar12 = 0. ;
|
|
for ( int i = nCvFirst + 1 ; i <= nCvSecond ; ++ i) {
|
|
dVar12 += ( cvBoundClosedLoopVec[nLoop][i] - ptM12) * ( cvBoundClosedLoopVec[nLoop][i] - ptM12) ;
|
|
}
|
|
dVar12 /= nCount ;
|
|
// punto medio fra secondo e primo
|
|
nCount = 0 ;
|
|
Point3d ptM21 ;
|
|
for ( int i = nCvSecond + 1 ; i % int( cvBoundClosedLoopVec[nLoop].size()) ; ++ i) {
|
|
ptM21 += cvBoundClosedLoopVec[nLoop][i] ;
|
|
++ nCount ;
|
|
}
|
|
for ( int i = 0 ; i <= nCvFirst ; ++ i) {
|
|
ptM21 += cvBoundClosedLoopVec[nLoop][i] ;
|
|
++ nCount ;
|
|
}
|
|
ptM21 /= nCount ;
|
|
// Distanza quadrata media dei punti tra secondo e primo dal baricentro
|
|
double dVar21 = 0. ;
|
|
for ( int i = nCvSecond ; i < i % int( cvBoundClosedLoopVec[nLoop].size()) ; ++ i) {
|
|
dVar21 += ( cvBoundClosedLoopVec[nLoop][i] - ptM21) * ( cvBoundClosedLoopVec[nLoop][i] - ptM21) ;
|
|
++ nCount ;
|
|
}
|
|
for ( int i = 0 ; i <= nCvFirst ; ++ i) {
|
|
dVar21 += ( cvBoundClosedLoopVec[nLoop][i] - ptM21) * ( cvBoundClosedLoopVec[nLoop][i] - ptM21) ;
|
|
++ nCount ;
|
|
}
|
|
dVar21 /= nCount ;
|
|
// elimino i punti dalla parte non valida
|
|
if ( dVar12 > dVar21) {
|
|
// assegno i nuovi valori
|
|
cvBoundClosedLoopVec[nLoop][nCvFirst] = ptProva ;
|
|
cvBoundClosedLoopVec[nLoop][( nCvSecond + 1) % int( cvBoundClosedLoopVec[nLoop].size())] = ptProva ;
|
|
// numero totale di punti
|
|
int nPntTot = int( cvBoundClosedLoopVec[nLoop].size()) ;
|
|
// elimino i punti superflui dopo
|
|
for ( int i = nPntTot - 1 ; i > nCvSecond + 1 ; -- i)
|
|
cvBoundClosedLoopVec[nLoop].pop_back() ;
|
|
// elimino i punti superflui prima
|
|
for ( int i = 0 ; i < nCvFirst ; ++ i)
|
|
cvBoundClosedLoopVec[nLoop].erase( cvBoundClosedLoopVec[nLoop].begin()) ;
|
|
// verifico se questo punto è dalla parte valida o no
|
|
bool bC12 = ( ( ptM12 - ptProva) * vtVecProva < 0) ;
|
|
vbInOut[nLoop] = bC12 ;
|
|
}
|
|
else {
|
|
// assegno i nuovi valori
|
|
cvBoundClosedLoopVec[nLoop][nCvFirst + 1] = ptProva ;
|
|
cvBoundClosedLoopVec[nLoop][nCvSecond] = ptProva ;
|
|
// elimino i punti superflui intermedi
|
|
for ( int i = nCvFirst + 2 ; i < nCvSecond ; ++ i)
|
|
cvBoundClosedLoopVec[nLoop].erase( cvBoundClosedLoopVec[nLoop].begin() + nCvFirst + 2) ;
|
|
// verifico se questo punto è dalla parte valida o no
|
|
bool bC21 = ( ( ptM21 - ptProva) * vtVecProva < 0) ;
|
|
vbInOut[nLoop] = bC21 ;
|
|
}
|
|
bLoopSplitted = true ;
|
|
}
|
|
}
|
|
}
|
|
if ( ! bLoopSplitted) {
|
|
int nCurDeg = vnDegVec[nLastOpenLoopN] ;
|
|
vnDegVec.emplace( vnDegVec.begin(), nCurDeg) ;
|
|
Chain CurChain ;
|
|
for ( int nCrChSeg = 0 ; nCrChSeg < int( cvOpenChain[nLastOpenLoopN].size()) ; ++ nCrChSeg) {
|
|
IntSegment CurChainSeg ;
|
|
CurChainSeg.ptSt = cvOpenChain[nLastOpenLoopN][nCrChSeg].ptSt ;
|
|
CurChainSeg.ptEn = cvOpenChain[nLastOpenLoopN][nCrChSeg].ptEn ;
|
|
CurChainSeg.vtOuter = cvOpenChain[nLastOpenLoopN][nCrChSeg].vtOuter ;
|
|
CurChainSeg.bDegenerate = cvOpenChain[nLastOpenLoopN][nCrChSeg].bDegenerate ;
|
|
CurChain.emplace_back( CurChainSeg) ;
|
|
}
|
|
cvOpenChain.emplace( cvOpenChain.begin(), CurChain) ;
|
|
++ nLastOpenLoopN ;
|
|
++ nIterationCount ;
|
|
}
|
|
else
|
|
nIterationCount = 0 ;
|
|
vnDegVec.resize( nLastOpenLoopN) ;
|
|
cvOpenChain.resize( nLastOpenLoopN) ;
|
|
if ( nIterationCount > int( cvOpenChain.size()) + 2)
|
|
return false ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other)
|
|
{
|
|
bool bModif = false ;
|
|
SurfTriMesh& SurfB = Other ;
|
|
// Le superfici devono essere valide
|
|
if ( m_nStatus != OK || ! SurfB.IsValid())
|
|
return false ;
|
|
// Unordered map dei segmenti di intersezione
|
|
std::unordered_map <int, Chain> LineMapA ;
|
|
std::unordered_map <int, Chain> LineMapB ;
|
|
// Unordered map dei triangoli ambigui (intersezione edge-edge)
|
|
std::unordered_map <int, std::vector <Triangle3d>> AmbiguosA ;
|
|
std::unordered_map <int, std::vector <Triangle3d>> AmbiguosB ;
|
|
// Ciclo sui triangoli delle mesh
|
|
int nTriaNumA = GetTriangleSize() ;
|
|
int nTriaNumB = SurfB.GetTriangleSize() ;
|
|
// Setto il triangolo come né fuori né dentro
|
|
for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA)
|
|
m_vTria[nTA].nTempPart = 0 ;
|
|
for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB)
|
|
SurfB.m_vTria[nTB].nTempPart = 0 ;
|
|
for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) {
|
|
// Se il triangolo A non è valido, continuo
|
|
Triangle3d trTriaA ;
|
|
if ( ! ( GetTriangle( nTA, trTriaA) && trTriaA.Validate( true)))
|
|
continue ;
|
|
// Box del triangolo A
|
|
BBox3d b3dTriaA ;
|
|
trTriaA.GetLocalBBox( b3dTriaA) ;
|
|
bool bNewTriaA = true ;
|
|
for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) {
|
|
// Se il triangolo B non è valido, continuo
|
|
Triangle3d trTriaB ;
|
|
if ( ! ( SurfB.GetTriangle( nTB, trTriaB) && trTriaB.Validate( true)))
|
|
continue ;
|
|
// Box del triangolo B
|
|
BBox3d b3dTriaB ;
|
|
trTriaB.GetLocalBBox( b3dTriaB) ;
|
|
// Se i box non si sovrappongono, contiuno
|
|
if ( ! b3dTriaA.Overlaps( b3dTriaB))
|
|
continue ;
|
|
// Interseco i triangoli
|
|
if ( abs( trTriaA.GetN() * trTriaB.GetN()) < 1 - EPS_ZERO) {
|
|
Point3d ptSegSt, ptSegEn ;
|
|
TRIA3DVECTOR vTria ;
|
|
int nIntType = IntersTriaTria( trTriaA, trTriaB, ptSegSt, ptSegEn, vTria) ;
|
|
if ( ! ( FromSpecialToNormal( nIntType) == ITTT_NO ||
|
|
FromSpecialToNormal( nIntType) == ITTT_OVERLAPS ||
|
|
FromSpecialToNormal( nIntType) == ITTTS_VERT_VERT)) {
|
|
// Assegno i dati di intersezione
|
|
IntSegment CurInters ;
|
|
if ( FromSpecialToNormal( nIntType) == ITTT_EDGE || FromSpecialToNormal( nIntType) == ITTT_YES) {
|
|
CurInters.ptSt = ptSegSt ;
|
|
CurInters.ptEn = ptSegEn ;
|
|
CurInters.bDegenerate = false ;
|
|
}
|
|
else {
|
|
CurInters.ptSt = ptSegSt ;
|
|
CurInters.ptEn = ptSegSt ;
|
|
CurInters.bDegenerate = true ;
|
|
}
|
|
CurInters.vtOuter = trTriaB.GetN() ;
|
|
CurInters.vtOuter -= ( ( CurInters.vtOuter * trTriaA.GetN()) * trTriaA.GetN()) ;
|
|
CurInters.vtOuter.Normalize() ;
|
|
// Salvo intersezione per superficie A
|
|
bool bIntOnEndgeA = false ;
|
|
if ( ! ( nIntType == ITTTS_EDGE_EDGE_SEG || nIntType == ITTTS_EDGE_INT)) {
|
|
auto itA = LineMapA.find( nTA) ;
|
|
if ( itA != LineMapA.end()) {
|
|
itA->second.emplace_back( CurInters) ;
|
|
}
|
|
else {
|
|
Chain chTemp ;
|
|
chTemp.emplace_back( CurInters) ;
|
|
LineMapA.emplace( nTA, chTemp) ;
|
|
}
|
|
}
|
|
else
|
|
bIntOnEndgeA = true ;
|
|
|
|
CurInters.vtOuter = trTriaA.GetN() ;
|
|
CurInters.vtOuter -= ( ( CurInters.vtOuter * trTriaB.GetN()) * trTriaB.GetN()) ;
|
|
CurInters.vtOuter.Normalize() ;
|
|
|
|
// Salvo intersezione per superficie B
|
|
bool bIntOnEndgeB = false ;
|
|
if ( ! ( nIntType == ITTTS_EDGE_EDGE_SEG || nIntType == ITTTS_INT_EDGE)) {
|
|
auto itB = LineMapB.find( nTB) ;
|
|
if ( itB != LineMapB.end()) {
|
|
itB->second.emplace_back( CurInters) ;
|
|
}
|
|
else {
|
|
Chain chTemp ;
|
|
chTemp.emplace_back( CurInters) ;
|
|
LineMapB.emplace( nTB, chTemp) ;
|
|
}
|
|
}
|
|
else
|
|
bIntOnEndgeB = true ;
|
|
// Intersezione edge-interno
|
|
if ( bIntOnEndgeA && ! bIntOnEndgeB) {
|
|
double dMaxDist = 0. ;
|
|
int nSegMaxDist = - 1 ;
|
|
for ( int nVA = 0 ; nVA < 3 ; ++ nVA) {
|
|
double dDist = abs( ( trTriaA.GetP( nVA) - trTriaB.GetP( 0)) * trTriaB.GetN()) ;
|
|
if ( dMaxDist < dDist) {
|
|
nSegMaxDist = nVA ;
|
|
dMaxDist = dDist ;
|
|
}
|
|
}
|
|
if ( nSegMaxDist >= 0) {
|
|
m_vTria[nTA].nTempPart = ( ( trTriaA.GetP( nSegMaxDist) - trTriaB.GetP( 0)) * trTriaB.GetN() < - EPS_SMALL ? 1 : - 1) ;
|
|
}
|
|
}
|
|
// Intersezione interno-edge
|
|
else if ( ! bIntOnEndgeA && bIntOnEndgeB) {
|
|
double dMaxDist = 0. ;
|
|
int nSegMaxDist = - 1 ;
|
|
for ( int nVB = 0 ; nVB < 3 ; ++ nVB) {
|
|
double dDist = abs( ( trTriaB.GetP( nVB) - trTriaA.GetP( 0)) * trTriaA.GetN()) ;
|
|
if ( dMaxDist < dDist) {
|
|
nSegMaxDist = nVB ;
|
|
dMaxDist = dDist ;
|
|
}
|
|
}
|
|
if ( nSegMaxDist >= 0) {
|
|
SurfB.m_vTria[nTB].nTempPart = ( ( trTriaB.GetP( nSegMaxDist) - trTriaA.GetP( 0)) * trTriaA.GetN() < - EPS_SMALL ? 1 : - 1) ;
|
|
}
|
|
}
|
|
// Intersezione edge-edge
|
|
else if ( bIntOnEndgeA && bIntOnEndgeB) {
|
|
auto itA = AmbiguosA.find( nTA) ;
|
|
if ( itA == AmbiguosA.end()) {
|
|
std::vector <Triangle3d> vVecTriaB ;
|
|
vVecTriaB.emplace_back( trTriaB) ;
|
|
AmbiguosA.emplace( nTA, vVecTriaB) ;
|
|
}
|
|
else {
|
|
itA->second.emplace_back( trTriaB) ;
|
|
}
|
|
auto itB = AmbiguosB.find( nTB) ;
|
|
if ( itB == AmbiguosB.end()) {
|
|
std::vector <Triangle3d> vVecTriaA ;
|
|
vVecTriaA.emplace_back( trTriaA) ;
|
|
AmbiguosB.emplace( nTB, vVecTriaA) ;
|
|
}
|
|
else {
|
|
itB->second.emplace_back( trTriaA) ;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ritriangolarizzo i triangoli della superficie A
|
|
for ( auto it = LineMapA.begin() ; it != LineMapA.end() ; ++ it) {
|
|
for ( int nS1 = 0 ; nS1 < int( it->second.size()) - 1 ; ++ nS1) {
|
|
for ( int nS2 = nS1 + 1 ; nS2 < int( it->second.size()) ; ++ nS2) {
|
|
if ( AreSamePointApprox( it->second[nS1].ptSt, it->second[nS2].ptEn) &&
|
|
AreSamePointApprox( it->second[nS1].ptEn, it->second[nS2].ptSt) &&
|
|
it->second[nS1].vtOuter * it->second[nS2].vtOuter < - EPS_SMALL) {
|
|
it->second.erase( it->second.begin() + nS2) ;
|
|
it->second.erase( it->second.begin() + nS1) ;
|
|
-- nS1 ;
|
|
-- nS2 ;
|
|
}
|
|
}
|
|
}
|
|
if ( int( it->second.size()) == 0)
|
|
continue ;
|
|
// Se il triangolo è stato sottoposto a ritriangolazione, le sue componenti sono classificabili come dentro-fuori.
|
|
// Lo tolgo dall'insieme dei triangoli ambigui (intersezione edge-edge)
|
|
else {
|
|
auto itA = AmbiguosA.find( it->first) ;
|
|
if ( itA != AmbiguosA.end()) {
|
|
AmbiguosA.erase( itA) ;
|
|
}
|
|
}
|
|
|
|
// Recupero il triangolo
|
|
Triangle3d trTriaA ;
|
|
GetTriangle( it->first, trTriaA) ;
|
|
// Lo rimuovo dalla mesh
|
|
RemoveTriangle( it->first) ;
|
|
bModif = true ;
|
|
CHAINVECTOR vChain ;
|
|
// Creo i loop
|
|
ChainCurves LoopCreator ;
|
|
LoopCreator.Init( false, EPS_SMALL, int( it->second.size())) ;
|
|
// Carico le curve per concatenarle
|
|
for ( int nCv = 0 ; nCv < int( it->second.size()) ; ++ nCv) {
|
|
Point3d ptSt = it->second[nCv].ptSt ;
|
|
Point3d ptEn = it->second[nCv].ptEn ;
|
|
Vector3d vtDir = ptEn - ptSt ;
|
|
vtDir.Normalize() ;
|
|
LoopCreator.AddCurve( nCv + 1, ptSt, vtDir, ptEn, vtDir) ;
|
|
}
|
|
// Recupero i concatenamenti
|
|
INTVECTOR vIds ;
|
|
Point3d ptNearStart ;
|
|
while ( LoopCreator.GetChainFromNear( ptNearStart, false, vIds)) {
|
|
Chain chTemp ;
|
|
for ( auto i : vIds) {
|
|
// Aggiungo la linea alla curva composta.
|
|
chTemp.emplace_back( it->second[i - 1]) ;
|
|
}
|
|
vChain.emplace_back( chTemp) ;
|
|
}
|
|
// Lavoro su loop e catene per regolarizzarle
|
|
int nChainCnt = int( vChain.size()) ;
|
|
// unisco eventuali catene estreme che sono parte di una stessa catena
|
|
if ( nChainCnt > 1) {
|
|
if ( AreSamePointApprox( vChain[0].front().ptSt, vChain[nChainCnt - 1].back().ptEn)) {
|
|
vChain[0].insert( vChain[0].begin(), vChain[nChainCnt - 1].begin(), vChain[nChainCnt - 1].end()) ;
|
|
vChain.pop_back() ;
|
|
-- nChainCnt ;
|
|
}
|
|
else if ( AreSamePointApprox(vChain[0].back().ptEn, vChain[nChainCnt - 1].front().ptSt)) {
|
|
vChain[0].insert(vChain[0].end(), vChain[nChainCnt - 1].begin(), vChain[nChainCnt - 1].end()) ;
|
|
vChain.pop_back() ;
|
|
-- nChainCnt ;
|
|
}
|
|
}
|
|
// semplifico catene formate da punti degeneri
|
|
for ( int nCh = 0 ; nCh < nChainCnt ; ++ nCh) {
|
|
if ( vChain[nCh].size() == 2 && ( vChain[nCh][0].bDegenerate || vChain[nCh][1].bDegenerate)) {
|
|
vChain[nCh][0].ptEn = vChain[nCh][1].ptEn ;
|
|
vChain[nCh][0].vtOuter = ( vChain[nCh][0].bDegenerate ? vChain[nCh][1].vtOuter : vChain[nCh][0].vtOuter) ;
|
|
vChain[nCh][0].bDegenerate = AreSamePointApprox( vChain[nCh][0].ptSt, vChain[nCh][0].ptEn) ;
|
|
vChain[nCh].resize( 1) ;
|
|
}
|
|
}
|
|
// Elimino la seconda copia di catene doppie
|
|
for ( int nI = 0 ; nI < nChainCnt ; ++ nI) {
|
|
for ( int nJ = nI + 1 ; nJ < nChainCnt ; ++ nJ) {
|
|
if ( vChain[nI].size() == vChain[nJ].size()) {
|
|
bool bSame = true ;
|
|
for ( int nK = 0 ; nK < int( vChain[nI].size()) ; ++ nK) {
|
|
if ( ! AreSamePointApprox( vChain[nI][nK].ptSt, vChain[nJ][nK].ptSt) ||
|
|
! AreSamePointApprox( vChain[nI][nK].ptEn, vChain[nJ][nK].ptEn)) {
|
|
bSame = false ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( bSame) {
|
|
vChain.erase( vChain.begin() + nJ) ;
|
|
-- nChainCnt ;
|
|
-- nJ ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fra le catene trovate separo le aperte dalle chiuse
|
|
int nDegenerateChainNum = 0 ;
|
|
INTVECTOR vnDegVec ;
|
|
CHAINVECTOR cvClosedChain ;
|
|
CHAINVECTOR cvOpenChain ;
|
|
for ( int nL = 0 ; nL < int( vChain.size()) ; ++ nL) {
|
|
bool bChainDegenerate = false ;
|
|
if ( vChain[nL].size() == 1 && AreSamePointApprox( vChain[nL][0].ptSt, vChain[nL][0].ptEn)) {
|
|
bChainDegenerate = true ;
|
|
}
|
|
|
|
if ( bChainDegenerate)
|
|
++ nDegenerateChainNum ;
|
|
int nCurLoopLast = max( int( vChain[nL].size()) - 1, 0) ;
|
|
if ( ( ! bChainDegenerate) && AreSamePointApprox( vChain[nL][0].ptSt, vChain[nL][nCurLoopLast].ptEn))
|
|
cvClosedChain.emplace_back( vChain[nL]) ;
|
|
else {
|
|
cvOpenChain.emplace_back( vChain[nL]) ;
|
|
if ( bChainDegenerate)
|
|
vnDegVec.emplace_back( 0) ;
|
|
else
|
|
vnDegVec.emplace_back( 1) ;
|
|
}
|
|
}
|
|
for ( int nCh1 = 0 ; nCh1 < int( cvOpenChain.size()) - 1 ; ++ nCh1) {
|
|
for ( int nCh2 = nCh1 + 1 ; nCh2 < int( cvOpenChain.size()) ; ++ nCh2) {
|
|
int nChainSize1 = int( cvOpenChain[nCh1].size()) ;
|
|
int nChainSize2 = int( cvOpenChain[nCh2].size()) ;
|
|
int nSameSeg = 0 ;
|
|
for ( int nSeg1 = 0 ; nSeg1 < nChainSize1 ; ++ nSeg1) {
|
|
for ( int nSeg2 = 0 ; nSeg2 < nChainSize2 ; ++ nSeg2) {
|
|
if ( AreSamePointExact( cvOpenChain[nCh1][nSeg1].ptSt, cvOpenChain[nCh2][nSeg2].ptSt) &&
|
|
AreSamePointExact( cvOpenChain[nCh1][nSeg1].ptEn, cvOpenChain[nCh2][nSeg2].ptEn) &&
|
|
AreSameVectorExact( cvOpenChain[nCh1][nSeg1].vtOuter, cvOpenChain[nCh2][nSeg2].vtOuter)) {
|
|
++ nSameSeg ;
|
|
}
|
|
}
|
|
}
|
|
if ( nChainSize1 == nSameSeg) {
|
|
cvOpenChain.erase( cvOpenChain.begin() + nCh1) ;
|
|
vnDegVec.erase( vnDegVec.begin() + nCh1) ;
|
|
-- nCh1 ;
|
|
}
|
|
else if ( nChainSize2 == nSameSeg) {
|
|
cvOpenChain.erase( cvOpenChain.begin() + nCh2) ;
|
|
vnDegVec.erase( vnDegVec.begin() + nCh2) ;
|
|
-- nCh2 ;
|
|
}
|
|
}
|
|
}
|
|
// Creo il loop chiuso padre di tutti, il perimetro del triangolo.
|
|
// Questo viene diviso in sotto-loop chiusi mediante quelli aperti.
|
|
// I loop chiusi trovati precedentemente sono interni a uno dei sotto-loop
|
|
// chiusi di cui è formato il perimetro.
|
|
PNTVECTOR cvFirstLoop ;
|
|
cvFirstLoop.emplace_back( trTriaA.GetP( 0)) ;
|
|
cvFirstLoop.emplace_back( trTriaA.GetP( 1)) ;
|
|
cvFirstLoop.emplace_back( trTriaA.GetP( 2)) ;
|
|
|
|
vector<PNTVECTOR> cvBoundClosedLoopVec ;
|
|
cvBoundClosedLoopVec.emplace_back( cvFirstLoop) ;
|
|
BOOLVECTOR vbInOut ;
|
|
vbInOut.push_back( true) ;
|
|
|
|
// Divido il loop usando le catene
|
|
bool bDecomposed = DecomposeLoop( cvOpenChain, vnDegVec, cvBoundClosedLoopVec, vbInOut) ;
|
|
// Rimuovo il triangolo corrente
|
|
RemoveTriangle( it->first) ;
|
|
// Trasformo i loop compositi in loop polyline
|
|
POLYLINEVECTOR vplPolyVec ;
|
|
vplPolyVec.resize( cvBoundClosedLoopVec.size()) ;
|
|
for ( int nLoop = 0 ; nLoop < int( vplPolyVec.size()) ; ++ nLoop) {
|
|
for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) ; ++ nLine) {
|
|
vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][nLine]) ;
|
|
}
|
|
vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][0]) ;
|
|
|
|
// Assegno ai loop trovati i rispettivi interni
|
|
// Assumo che i loop interni a uno dei loop creati fino ad'ora siano tutti sullo stesso livello.
|
|
// Il caso generale si risolve con una struttura ad albero in cui il nodi corrispondente a un
|
|
// loop è figlio del nodo corrispondente al loop che lo contiene.
|
|
vector<int> vInnerLoop ;
|
|
for ( int nCLI = 0 ; nCLI < int( cvClosedChain.size()) ; ++ nCLI) {
|
|
Point3d ptLoopStart = cvClosedChain[nCLI][0].ptSt ;
|
|
double dMinDist = DBL_MAX ;
|
|
Point3d ptMinDist ;
|
|
bool bPointOnSt = false ;
|
|
bool bPointOnEn = false ;
|
|
int nSegNum = 0 ;
|
|
int nSegMin ;
|
|
Point3d ptS, ptE ;
|
|
bool bContinueS = vplPolyVec[nLoop].GetFirstPoint( ptS) ;
|
|
bool bContinueE = vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
while ( bContinueS && bContinueE) {
|
|
++ nSegNum ;
|
|
DistPointLine DistCalculator( ptLoopStart, ptS, ptE) ;
|
|
double dDist ;
|
|
DistCalculator.GetDist( dDist) ;
|
|
if ( dDist < dMinDist) {
|
|
DistCalculator.GetMinDistPoint( ptMinDist) ;
|
|
bPointOnSt = AreSamePointExact( ptMinDist, ptS) ;
|
|
bPointOnEn = AreSamePointExact( ptMinDist, ptE) ;
|
|
dMinDist = dDist ;
|
|
nSegMin = nSegNum ;
|
|
}
|
|
ptS = ptE ;
|
|
bContinueS = bContinueE ;
|
|
bContinueE = vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
}
|
|
if ( ! ( bPointOnSt || bPointOnEn)) {
|
|
vplPolyVec[nLoop].GetFirstPoint( ptS) ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
for ( int nSeg = 1 ; nSeg < nSegMin ; ++ nSeg) {
|
|
ptS = ptE ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
}
|
|
Vector3d vtTan = ptE - ptS ;
|
|
vtTan.Normalize() ;
|
|
Vector3d vtOut = vtTan ^ trTriaA.GetN() ;
|
|
Point3d ptMinDist ;
|
|
DistPointLine DistCalculator( ptLoopStart, ptS, ptE) ;
|
|
DistCalculator.GetMinDistPoint( ptMinDist) ;
|
|
double dMinDistDot = ( ptLoopStart - ptMinDist) * vtOut ;
|
|
if ( dMinDistDot < 0.)
|
|
vInnerLoop.emplace_back( nCLI) ;
|
|
}
|
|
else if ( bPointOnSt) {
|
|
Point3d ptPrevS, ptPrevE ;
|
|
if ( nSegMin == 1) {
|
|
vplPolyVec[nLoop].GetFirstPoint( ptS) ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
vplPolyVec[nLoop].GetLastPoint( ptPrevE) ;
|
|
vplPolyVec[nLoop].GetPrevPoint( ptPrevS) ;
|
|
}
|
|
else {
|
|
-- nSegMin ;
|
|
vplPolyVec[nLoop].GetFirstPoint( ptPrevS) ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptPrevE) ;
|
|
for ( int nSeg = 1 ; nSeg < nSegMin ; ++ nSeg) {
|
|
ptPrevS = ptPrevE ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptPrevE) ;
|
|
}
|
|
ptS = ptPrevE ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
}
|
|
Vector3d vtTan = ptE - ptS ;
|
|
vtTan.Normalize() ;
|
|
Vector3d vtTanPrev = ptPrevE - ptPrevS ;
|
|
vtTanPrev.Normalize() ;
|
|
Vector3d vtBisector = 0.5 * ( vtTan + vtTanPrev) ^ trTriaA.GetN() ;
|
|
vtBisector.Normalize() ;
|
|
double dMinDistDot = ( ptLoopStart - ptMinDist) * vtBisector ;
|
|
if ( dMinDistDot < 0.)
|
|
vInnerLoop.emplace_back(nCLI) ;
|
|
}
|
|
else if ( bPointOnEn) {
|
|
Point3d ptLast ;
|
|
vplPolyVec[nLoop].GetLastPoint( ptLast) ;
|
|
vplPolyVec[nLoop].GetFirstPoint( ptS) ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
for ( int nSeg = 1 ; nSeg < nSegMin ; ++ nSeg) {
|
|
ptS = ptE ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
}
|
|
Point3d ptNextS, ptNextE ;
|
|
if ( AreSamePointExact( ptE, ptLast)) {
|
|
vplPolyVec[nLoop].GetFirstPoint( ptNextS) ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptNextE) ;
|
|
}
|
|
else {
|
|
vplPolyVec[nLoop].GetNextPoint( ptNextS) ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptNextE) ;
|
|
}
|
|
Vector3d vtTan = ptE - ptS ;
|
|
vtTan.Normalize() ;
|
|
Vector3d vtTanNext = ptNextE - ptNextS ;
|
|
vtTanNext.Normalize() ;
|
|
Vector3d vtBisector = 0.5 * ( vtTan + vtTanNext) ^ trTriaA.GetN() ;
|
|
vtBisector.Normalize() ;
|
|
double dMinDistDot = ( ptLoopStart - ptMinDist) * vtBisector ;
|
|
if ( dMinDistDot < 0.)
|
|
vInnerLoop.emplace_back( nCLI) ;
|
|
}
|
|
}
|
|
|
|
if ( vInnerLoop.size() == 0) {
|
|
// Eseguo triangolazione
|
|
Triangulate CreateTriangulation ;
|
|
PNTVECTOR vPt ;
|
|
INTVECTOR vTr ;
|
|
if ( Triangulate().Make( vplPolyVec[nLoop], 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]]) } ;
|
|
int nNewTriaNum = AddTriangle( nNewId) ;
|
|
if ( vbInOut[nLoop])
|
|
m_vTria[nNewTriaNum].nTempPart = 1 ;
|
|
else
|
|
m_vTria[nNewTriaNum].nTempPart = - 1 ;
|
|
bModif = true ;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
|
|
POLYLINEVECTOR vPolygons ;
|
|
vPolygons.emplace_back( vplPolyVec[nLoop]) ;
|
|
|
|
for ( int nL = 0 ; nL < int( vInnerLoop.size()) ; ++ nL) {
|
|
PolyLine CurLoop ;
|
|
for ( int nV = 0 ; nV < int( cvClosedChain[vInnerLoop[nL]].size()) ; ++ nV) {
|
|
CurLoop.AddUPoint( 0., cvClosedChain[vInnerLoop[nL]][nV].ptSt) ;
|
|
}
|
|
CurLoop.AddUPoint( 0., cvClosedChain[vInnerLoop[nL]][0].ptSt) ;
|
|
vPolygons.emplace_back( CurLoop) ;
|
|
}
|
|
|
|
Polygon3d pgPol ;
|
|
pgPol.FromPolyLine( vPolygons[1]) ;
|
|
|
|
if ( trTriaA.GetN() * pgPol.GetVersN() > 0.) {
|
|
for (int nL = 1; nL < int(vPolygons.size()); ++nL) {
|
|
vPolygons[nL].Invert();
|
|
}
|
|
|
|
PNTVECTOR vPt;
|
|
INTVECTOR vTr;
|
|
if (Triangulate().Make(vPolygons, 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]]) };
|
|
int nNewTriaNum = AddTriangle(nNewId);
|
|
m_vTria[nNewTriaNum].nTempPart = -1;
|
|
bModif = true;
|
|
}
|
|
}
|
|
|
|
for (int nL = 1; nL < int(vPolygons.size()); ++nL) {
|
|
vPolygons[nL].Invert();
|
|
if (Triangulate().Make(vPolygons[nL], 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]]) };
|
|
int nNewTriaNum = AddTriangle(nNewId);
|
|
m_vTria[nNewTriaNum].nTempPart = 1;
|
|
bModif = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
PNTVECTOR vPt;
|
|
INTVECTOR vTr;
|
|
if (Triangulate().Make(vPolygons, 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]]) };
|
|
int nNewTriaNum = AddTriangle(nNewId);
|
|
m_vTria[nNewTriaNum].nTempPart = 1;
|
|
bModif = true;
|
|
}
|
|
}
|
|
|
|
for (int nL = 1; nL < int(vPolygons.size()); ++nL) {
|
|
vPolygons[nL].Invert();
|
|
if (Triangulate().Make(vPolygons[nL], 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]]) };
|
|
int nNewTriaNum = AddTriangle(nNewId);
|
|
m_vTria[nNewTriaNum].nTempPart = -1;
|
|
bModif = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
vInnerLoop.resize( 0) ;
|
|
}
|
|
}
|
|
|
|
// Ritriangolarizzo i triangoli della superficie B
|
|
for ( auto it = LineMapB.begin() ; it != LineMapB.end() ; ++ it) {
|
|
for ( int nS1 = 0 ; nS1 < int( it->second.size()) - 1 ; ++ nS1) {
|
|
for ( int nS2 = nS1 + 1 ; nS2 < int( it->second.size()) ; ++ nS2) {
|
|
if ( AreSamePointApprox( it->second[nS1].ptSt, it->second[nS2].ptEn) &&
|
|
AreSamePointApprox( it->second[nS1].ptEn, it->second[nS2].ptSt) &&
|
|
it->second[nS1].vtOuter * it->second[nS2].vtOuter < - EPS_SMALL) {
|
|
it->second.erase( it->second.begin() + nS2) ;
|
|
it->second.erase( it->second.begin() + nS1) ;
|
|
-- nS1 ;
|
|
-- nS2 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( int( it->second.size()) == 0)
|
|
continue ;
|
|
// Se il triangolo è stato sottoposto a ritriangolazione, le sue componenti sono classificabili come dentro-fuori.
|
|
// Lo tolgo dall'insieme dei triangoli ambigui (intersezione edge-edge)
|
|
else {
|
|
auto itB = AmbiguosB.find( it->first) ;
|
|
if ( itB != AmbiguosB.end()) {
|
|
AmbiguosB.erase( itB) ;
|
|
}
|
|
}
|
|
|
|
// Recupero il triangolo
|
|
Triangle3d trTriaB ;
|
|
SurfB.GetTriangle( it->first, trTriaB) ;
|
|
// Lo rimuovo dalla mesh
|
|
SurfB.RemoveTriangle( it->first) ;
|
|
bModif = true ;
|
|
CHAINVECTOR vChain ;
|
|
// Creo i loop
|
|
ChainCurves LoopCreator ;
|
|
LoopCreator.Init( false, EPS_SMALL, int( it->second.size())) ;
|
|
// Carico le curve per concatenarle
|
|
for ( int nCv = 0 ; nCv < int( it->second.size()) ; ++ nCv) {
|
|
Point3d ptSt = it->second[nCv].ptSt ;
|
|
Point3d ptEn = it->second[nCv].ptEn ;
|
|
Vector3d vtDir = ptEn - ptSt ;
|
|
vtDir.Normalize() ;
|
|
LoopCreator.AddCurve( nCv + 1, ptSt, vtDir, ptEn, vtDir) ;
|
|
}
|
|
// Recupero i concatenamenti
|
|
INTVECTOR vIds ;
|
|
Point3d ptNearStart ;
|
|
while ( LoopCreator.GetChainFromNear( ptNearStart, false, vIds)) {
|
|
Chain chTemp ;
|
|
for ( auto i : vIds) {
|
|
// Aggiungo la linea alla curva composta.
|
|
chTemp.emplace_back( it->second[i - 1]) ;
|
|
}
|
|
vChain.emplace_back( chTemp) ;
|
|
}
|
|
// Lavoro su loop e catene per regolarizzarle
|
|
int nChainCnt = int( vChain.size()) ;
|
|
// unisco eventuali catene estreme che sono parte di una stessa catena
|
|
if ( nChainCnt > 1) {
|
|
if ( AreSamePointApprox( vChain[0].front().ptSt, vChain[nChainCnt - 1].back().ptEn)) {
|
|
vChain[0].insert( vChain[0].begin(), vChain[nChainCnt - 1].begin(), vChain[nChainCnt - 1].end()) ;
|
|
vChain.pop_back() ;
|
|
-- nChainCnt ;
|
|
}
|
|
else if ( AreSamePointApprox( vChain[0].back().ptEn, vChain[nChainCnt - 1].front().ptSt)) {
|
|
vChain[0].insert( vChain[0].end(), vChain[nChainCnt - 1].begin(), vChain[nChainCnt - 1].end()) ;
|
|
vChain.pop_back() ;
|
|
-- nChainCnt ;
|
|
}
|
|
}
|
|
// semplifico catene formate da punti degeneri
|
|
for ( int nCh = 0 ; nCh < nChainCnt ; ++ nCh) {
|
|
if ( vChain[nCh].size() == 2 && ( vChain[nCh][0].bDegenerate || vChain[nCh][1].bDegenerate)) {
|
|
vChain[nCh][0].ptEn = vChain[nCh][1].ptEn ;
|
|
vChain[nCh][0].vtOuter = ( vChain[nCh][0].bDegenerate ? vChain[nCh][1].vtOuter : vChain[nCh][0].vtOuter) ;
|
|
vChain[nCh][0].bDegenerate = AreSamePointApprox( vChain[nCh][0].ptSt, vChain[nCh][0].ptEn) ;
|
|
vChain[nCh].resize( 1) ;
|
|
}
|
|
}
|
|
// Elimino la seconda copia di catene doppie
|
|
for ( int nI = 0 ; nI < nChainCnt ; ++ nI) {
|
|
for ( int nJ = nI + 1 ; nJ < nChainCnt ; ++ nJ) {
|
|
if ( vChain[nI].size() == vChain[nJ].size()) {
|
|
bool bSame = true ;
|
|
for ( int nK = 0 ; nK < int( vChain[nI].size()) ; ++ nK) {
|
|
if ( ! AreSamePointApprox( vChain[nI][nK].ptSt, vChain[nJ][nK].ptSt) ||
|
|
! AreSamePointApprox( vChain[nI][nK].ptEn, vChain[nJ][nK].ptEn)) {
|
|
bSame = false ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( bSame) {
|
|
vChain.erase( vChain.begin() + nJ) ;
|
|
-- nChainCnt ;
|
|
-- nJ ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fra le catene trovate separo le aperte dalle chiuse
|
|
int nDegenerateChainNum = 0 ;
|
|
INTVECTOR vnDegVec ;
|
|
CHAINVECTOR cvClosedChain ;
|
|
CHAINVECTOR cvOpenChain ;
|
|
for ( int nL = 0 ; nL < int( vChain.size()) ; ++ nL) {
|
|
bool bChainDegenerate = false ;
|
|
if ( vChain[nL].size() == 1 && AreSamePointApprox( vChain[nL][0].ptSt, vChain[nL][0].ptEn)) {
|
|
bChainDegenerate = true ;
|
|
}
|
|
|
|
if ( bChainDegenerate)
|
|
++ nDegenerateChainNum ;
|
|
int nCurLoopLast = max( int( vChain[nL].size()) - 1, 0) ;
|
|
if ( ( ! bChainDegenerate) && AreSamePointApprox( vChain[nL][0].ptSt, vChain[nL][nCurLoopLast].ptEn))
|
|
cvClosedChain.emplace_back( vChain[nL]) ;
|
|
else {
|
|
cvOpenChain.emplace_back( vChain[nL]) ;
|
|
if ( bChainDegenerate)
|
|
vnDegVec.emplace_back( 0) ;
|
|
else
|
|
vnDegVec.emplace_back( 1) ;
|
|
}
|
|
}
|
|
|
|
for ( int nCh1 = 0 ; nCh1 < int( cvOpenChain.size()) - 1 ; ++ nCh1) {
|
|
for ( int nCh2 = nCh1 + 1 ; nCh2 < int( cvOpenChain.size()) ; ++ nCh2) {
|
|
int nChainSize1 = int( cvOpenChain[nCh1].size()) ;
|
|
int nChainSize2 = int( cvOpenChain[nCh2].size()) ;
|
|
int nSameSeg = 0 ;
|
|
for ( int nSeg1 = 0 ; nSeg1 < nChainSize1 ; ++ nSeg1) {
|
|
for ( int nSeg2 = 0 ; nSeg2 < nChainSize2 ; ++ nSeg2) {
|
|
if ( AreSamePointExact( cvOpenChain[nCh1][nSeg1].ptSt, cvOpenChain[nCh2][nSeg2].ptSt) &&
|
|
AreSamePointExact( cvOpenChain[nCh1][nSeg1].ptEn, cvOpenChain[nCh2][nSeg2].ptEn) &&
|
|
AreSameVectorExact( cvOpenChain[nCh1][nSeg1].vtOuter, cvOpenChain[nCh2][nSeg2].vtOuter)) {
|
|
++ nSameSeg ;
|
|
}
|
|
}
|
|
}
|
|
if ( nChainSize1 == nSameSeg) {
|
|
cvOpenChain.erase( cvOpenChain.begin() + nCh1) ;
|
|
vnDegVec.erase( vnDegVec.begin() + nCh1) ;
|
|
}
|
|
else if ( nChainSize2 == nSameSeg) {
|
|
cvOpenChain.erase( cvOpenChain.begin() + nCh2) ;
|
|
vnDegVec.erase( vnDegVec.begin() + nCh2) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Creo il loop chiuso padre di tutti, il perimetro del triangolo.
|
|
// Questo viene diviso in sotto-loop chiusi mediante quelli aperti.
|
|
// I loop chiusi trovati precedentemente sono interni a uno dei sotto-loop
|
|
// chiusi di cui è formato il perimetro.
|
|
PNTVECTOR cvFirstLoop ;
|
|
cvFirstLoop.emplace_back( trTriaB.GetP( 0)) ;
|
|
cvFirstLoop.emplace_back( trTriaB.GetP( 1)) ;
|
|
cvFirstLoop.emplace_back( trTriaB.GetP( 2)) ;
|
|
|
|
vector<PNTVECTOR> cvBoundClosedLoopVec ;
|
|
cvBoundClosedLoopVec.emplace_back( cvFirstLoop) ;
|
|
BOOLVECTOR vbInOut ;
|
|
vbInOut.push_back( true) ;
|
|
// Divido il loop usando le catene
|
|
bool bDecomposed = DecomposeLoop( cvOpenChain, vnDegVec, cvBoundClosedLoopVec, vbInOut) ;
|
|
// Rimuovo il triangolo corrente
|
|
SurfB.RemoveTriangle( it->first) ;
|
|
// Trasformo i loop compositi in loop polyline
|
|
POLYLINEVECTOR vplPolyVec ;
|
|
vplPolyVec.resize( cvBoundClosedLoopVec.size()) ;
|
|
for ( int nLoop = 0 ; nLoop < int( vplPolyVec.size()) ; ++ nLoop) {
|
|
for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) ; ++ nLine) {
|
|
vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][nLine]) ;
|
|
}
|
|
vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][0]) ;
|
|
|
|
// Assegno ai loop trovati i rispettivi interni
|
|
// Assumo che i loop interni a uno dei loop creati fino ad'ora siano tutti sullo stesso livello.
|
|
// Il caso generale si risolve con una struttura ad albero in cui il nodi corrispondente a un
|
|
// loop è figlio del nodo corrispondente al loop che lo contiene.
|
|
vector<int> vInnerLoop ;
|
|
for ( int nCLI = 0 ; nCLI < int( cvClosedChain.size()) ; ++ nCLI) {
|
|
Point3d ptLoopStart = cvClosedChain[nCLI][0].ptSt ;
|
|
double dMinDist = DBL_MAX ;
|
|
Point3d ptMinDist ;
|
|
bool bPointOnSt = false ;
|
|
bool bPointOnEn = false ;
|
|
int nSegNum = 0 ;
|
|
int nSegMin ;
|
|
Point3d ptS, ptE ;
|
|
bool bContinueS = vplPolyVec[nLoop].GetFirstPoint( ptS) ;
|
|
bool bContinueE = vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
while ( bContinueS && bContinueE) {
|
|
++ nSegNum ;
|
|
DistPointLine DistCalculator( ptLoopStart, ptS, ptE) ;
|
|
double dDist ;
|
|
DistCalculator.GetDist( dDist) ;
|
|
if ( dDist < dMinDist) {
|
|
DistCalculator.GetMinDistPoint( ptMinDist) ;
|
|
bPointOnSt = AreSamePointExact( ptMinDist, ptS) ;
|
|
bPointOnEn = AreSamePointExact( ptMinDist, ptE) ;
|
|
dMinDist = dDist ;
|
|
nSegMin = nSegNum ;
|
|
}
|
|
ptS = ptE ;
|
|
bContinueS = bContinueE ;
|
|
bContinueE = vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
}
|
|
if ( ! ( bPointOnSt || bPointOnEn)) {
|
|
vplPolyVec[nLoop].GetFirstPoint( ptS) ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
for ( int nSeg = 1 ; nSeg < nSegMin ; ++ nSeg) {
|
|
ptS = ptE ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
}
|
|
Vector3d vtTan = ptE - ptS ;
|
|
vtTan.Normalize() ;
|
|
Vector3d vtOut = vtTan ^ trTriaB.GetN() ;
|
|
Point3d ptMinDist ;
|
|
DistPointLine DistCalculator( ptLoopStart, ptS, ptE) ;
|
|
DistCalculator.GetMinDistPoint( ptMinDist) ;
|
|
double dMinDistDot = ( ptLoopStart - ptMinDist) * vtOut ;
|
|
if ( dMinDistDot < 0.)
|
|
vInnerLoop.emplace_back( nCLI) ;
|
|
}
|
|
else if ( bPointOnSt) {
|
|
Point3d ptPrevS, ptPrevE ;
|
|
if ( nSegMin == 1) {
|
|
vplPolyVec[nLoop].GetFirstPoint( ptS) ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
vplPolyVec[nLoop].GetLastPoint( ptPrevE) ;
|
|
vplPolyVec[nLoop].GetPrevPoint( ptPrevS) ;
|
|
}
|
|
else {
|
|
-- nSegMin ;
|
|
vplPolyVec[nLoop].GetFirstPoint( ptPrevS) ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptPrevE) ;
|
|
for ( int nSeg = 1 ; nSeg < nSegMin ; ++ nSeg) {
|
|
ptPrevS = ptPrevE ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptPrevE) ;
|
|
}
|
|
ptS = ptPrevE ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
}
|
|
Vector3d vtTan = ptE - ptS ;
|
|
vtTan.Normalize() ;
|
|
Vector3d vtTanPrev = ptPrevE - ptPrevS ;
|
|
vtTanPrev.Normalize() ;
|
|
Vector3d vtBisector = 0.5 * ( vtTan + vtTanPrev) ^ trTriaB.GetN() ;
|
|
vtBisector.Normalize() ;
|
|
double dMinDistDot = ( ptLoopStart - ptMinDist) * vtBisector ;
|
|
if ( dMinDistDot < 0.)
|
|
vInnerLoop.emplace_back( nCLI) ;
|
|
}
|
|
else if ( bPointOnEn) {
|
|
Point3d ptLast ;
|
|
vplPolyVec[nLoop].GetLastPoint( ptLast) ;
|
|
vplPolyVec[nLoop].GetFirstPoint( ptS) ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
for ( int nSeg = 1 ; nSeg < nSegMin ; ++ nSeg) {
|
|
ptS = ptE ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
}
|
|
Point3d ptNextS, ptNextE ;
|
|
if ( AreSamePointExact( ptE, ptLast)) {
|
|
vplPolyVec[nLoop].GetFirstPoint( ptNextS) ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptNextE) ;
|
|
}
|
|
else {
|
|
vplPolyVec[nLoop].GetNextPoint( ptNextS) ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptNextE) ;
|
|
}
|
|
Vector3d vtTan = ptE - ptS ;
|
|
vtTan.Normalize() ;
|
|
Vector3d vtTanNext = ptNextE - ptNextS ;
|
|
vtTanNext.Normalize() ;
|
|
Vector3d vtBisector = 0.5 * ( vtTan + vtTanNext) ^ trTriaB.GetN() ;
|
|
vtBisector.Normalize() ;
|
|
double dMinDistDot = ( ptLoopStart - ptMinDist) * vtBisector ;
|
|
if ( dMinDistDot < 0.)
|
|
vInnerLoop.emplace_back( nCLI) ;
|
|
}
|
|
}
|
|
|
|
if ( vInnerLoop.size() == 0) {
|
|
// Eseguo triangolazione
|
|
Triangulate CreateTriangulation ;
|
|
PNTVECTOR vPt ;
|
|
INTVECTOR vTr ;
|
|
if ( Triangulate().Make( vplPolyVec[nLoop], 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] = { SurfB.AddVertex(vPt[nNewTriaVertId[0]]),
|
|
SurfB.AddVertex(vPt[nNewTriaVertId[1]]),
|
|
SurfB.AddVertex(vPt[nNewTriaVertId[2]]) } ;
|
|
int nNewTriaNum = SurfB.AddTriangle( nNewId) ;
|
|
if ( vbInOut[nLoop])
|
|
SurfB.m_vTria[nNewTriaNum].nTempPart = 1 ;
|
|
else
|
|
SurfB.m_vTria[nNewTriaNum].nTempPart = - 1 ;
|
|
bModif = true ;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
POLYLINEVECTOR vPolygons ;
|
|
vPolygons.emplace_back( vplPolyVec[nLoop]) ;
|
|
if ( vbInOut[nLoop]) {
|
|
for ( int nL = 0 ; nL < int( vInnerLoop.size()) ; ++ nL) {
|
|
PolyLine CurLoop ;
|
|
for ( int nV = 0 ; nV < int( cvClosedChain[vInnerLoop[nL]].size()) ; ++ nV) {
|
|
CurLoop.AddUPoint( 0., cvClosedChain[vInnerLoop[nL]][nV].ptSt) ;
|
|
}
|
|
CurLoop.AddUPoint( 0., cvClosedChain[vInnerLoop[nL]][0].ptSt) ;
|
|
vPolygons.emplace_back( CurLoop) ;
|
|
}
|
|
|
|
PNTVECTOR vPt ;
|
|
INTVECTOR vTr ;
|
|
if ( Triangulate().Make( vPolygons, 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] = { SurfB.AddVertex(vPt[nNewTriaVertId[0]]),
|
|
SurfB.AddVertex(vPt[nNewTriaVertId[1]]),
|
|
SurfB.AddVertex(vPt[nNewTriaVertId[2]]) } ;
|
|
int nNewTriaNum = SurfB.AddTriangle( nNewId) ;
|
|
SurfB.m_vTria[nNewTriaNum].nTempPart = 1 ;
|
|
bModif = true ;
|
|
}
|
|
}
|
|
|
|
for ( int nL = 1 ; nL < int( vPolygons.size()) ; ++ nL) {
|
|
vPolygons[nL].Invert() ;
|
|
if ( Triangulate().Make(vPolygons[nL], 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] = { SurfB.AddVertex(vPt[nNewTriaVertId[0]]),
|
|
SurfB.AddVertex(vPt[nNewTriaVertId[1]]),
|
|
SurfB.AddVertex(vPt[nNewTriaVertId[2]]) } ;
|
|
int nNewTriaNum = SurfB.AddTriangle( nNewId) ;
|
|
SurfB.m_vTria[nNewTriaNum].nTempPart = - 1 ;
|
|
bModif = true ;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
else {
|
|
for ( int nL = 0 ; nL < int( vInnerLoop.size()); ++ nL) {
|
|
PolyLine CurLoop ;
|
|
for ( int nV = 0 ; nV < int( cvClosedChain[vInnerLoop[nL]].size()) ; ++ nV) {
|
|
CurLoop.AddUPoint( 0., cvClosedChain[vInnerLoop[nL]][nV].ptSt) ;
|
|
}
|
|
CurLoop.AddUPoint( 0., cvClosedChain[vInnerLoop[nL]][0].ptSt) ;
|
|
CurLoop.Invert() ;
|
|
vPolygons.emplace_back( CurLoop) ;
|
|
}
|
|
|
|
PNTVECTOR vPt ;
|
|
INTVECTOR vTr ;
|
|
|
|
if ( Triangulate().Make( vPolygons, 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] = { SurfB.AddVertex(vPt[nNewTriaVertId[0]]),
|
|
SurfB.AddVertex(vPt[nNewTriaVertId[1]]),
|
|
SurfB.AddVertex(vPt[nNewTriaVertId[2]]) } ;
|
|
int nNewTriaNum = SurfB.AddTriangle( nNewId) ;
|
|
SurfB.m_vTria[nNewTriaNum].nTempPart = 1 ;
|
|
bModif = true ;
|
|
}
|
|
}
|
|
|
|
for ( int nL = 1 ; nL < int( vPolygons.size()) ; ++ nL) {
|
|
vPolygons[nL].Invert() ;
|
|
if ( Triangulate().Make( vPolygons[nL], 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] = { SurfB.AddVertex(vPt[nNewTriaVertId[0]]),
|
|
SurfB.AddVertex(vPt[nNewTriaVertId[1]]),
|
|
SurfB.AddVertex(vPt[nNewTriaVertId[2]]) } ;
|
|
int nNewTriaNum = SurfB.AddTriangle( nNewId) ;
|
|
SurfB.m_vTria[nNewTriaNum].nTempPart = - 1 ;
|
|
bModif = true ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
vInnerLoop.resize( 0) ;
|
|
}
|
|
}
|
|
|
|
// Se i triangoli delle superfici non si intersecano, una delle due è totalmente interna o esterna all'altra.
|
|
bool bRetriangulated = true ;
|
|
if ( ! bModif) {
|
|
bRetriangulated = false ;
|
|
int nVertNum = 0 ;
|
|
Point3d ptFirstV ;
|
|
int nCurVert = GetFirstVertex( ptFirstV) ;
|
|
int nInOutNum = 0 ;
|
|
while ( nInOutNum == 0 && nCurVert != SVT_NULL) {
|
|
int nTriaNum = - 1 ;
|
|
double dMinDist = DBL_MAX ;
|
|
for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) {
|
|
// Se il triangolo B non è valido, continuo
|
|
Triangle3d trTriaB ;
|
|
if ( ! ( SurfB.GetTriangle( nTB, trTriaB) && trTriaB.Validate( true)))
|
|
continue ;
|
|
DistPointTriangle DistCalculator( ptFirstV, trTriaB) ;
|
|
double dDist ;
|
|
DistCalculator.GetDist( dDist) ;
|
|
if ( dDist < dMinDist) {
|
|
nTriaNum = nTB ;
|
|
dMinDist = dDist ;
|
|
}
|
|
}
|
|
if ( nTriaNum >= 0) {
|
|
Triangle3d trTriaB ;
|
|
SurfB.GetTriangle( nTriaNum, trTriaB) ;
|
|
|
|
if ( ( ptFirstV - trTriaB.GetP(0)) * trTriaB.GetN() < - EPS_SMALL) {
|
|
nInOutNum = 1 ;
|
|
}
|
|
else if ( ( ptFirstV - trTriaB.GetP(0)) * trTriaB.GetN() > EPS_SMALL) {
|
|
nInOutNum = - 1 ;
|
|
}
|
|
}
|
|
if ( nInOutNum == 0) {
|
|
nCurVert = GetNextVertex( nVertNum, ptFirstV) ;
|
|
++ nVertNum ;
|
|
}
|
|
}
|
|
for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) {
|
|
m_vTria[nTA].nTempPart = nInOutNum ;
|
|
}
|
|
nVertNum = 0 ;
|
|
ptFirstV ;
|
|
nCurVert = SurfB.GetFirstVertex( ptFirstV) ;
|
|
nInOutNum = 0 ;
|
|
while ( nInOutNum == 0 && nCurVert != SVT_NULL) {
|
|
int nTriaNum = - 1 ;
|
|
double dMinDist = DBL_MAX ;
|
|
for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) {
|
|
// Se il triangolo A non è valido, continuo
|
|
Triangle3d trTriaA ;
|
|
if ( ! ( GetTriangle( nTA, trTriaA) && trTriaA.Validate( true)))
|
|
continue ;
|
|
DistPointTriangle DistCalculator( ptFirstV, trTriaA) ;
|
|
double dDist ;
|
|
DistCalculator.GetDist( dDist) ;
|
|
if ( dDist < dMinDist) {
|
|
nTriaNum = nTA ;
|
|
dMinDist = dDist ;
|
|
}
|
|
}
|
|
if ( nTriaNum >= 0) {
|
|
Triangle3d trTriaA ;
|
|
GetTriangle( nTriaNum, trTriaA) ;
|
|
|
|
if ( ( ptFirstV - trTriaA.GetP( 0)) * trTriaA.GetN() < - EPS_SMALL) {
|
|
nInOutNum = 1 ;
|
|
}
|
|
else if ( ( ptFirstV - trTriaA.GetP(0)) * trTriaA.GetN() > EPS_SMALL) {
|
|
nInOutNum = - 1 ;
|
|
}
|
|
}
|
|
if ( nInOutNum == 0) {
|
|
nCurVert = SurfB.GetNextVertex( nVertNum, ptFirstV) ;
|
|
++ nVertNum ;
|
|
}
|
|
}
|
|
for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) {
|
|
SurfB.m_vTria[nTB].nTempPart = nInOutNum ;
|
|
}
|
|
}
|
|
// Se c'è stata una ritriangolazione di almeno un triangolo, NON siamo nel caso di tutto dentro o tutto fuori.
|
|
// Studio i triangoli ambigui.
|
|
if ( bRetriangulated) {
|
|
for ( auto it = AmbiguosA.begin() ; it != AmbiguosA.end() ; ++ it) {
|
|
Triangle3d trTriaA ;
|
|
GetTriangle( it->first, trTriaA) ;
|
|
trTriaA.Validate() ;
|
|
Point3d ptBarA = ( trTriaA.GetP( 0) + trTriaA.GetP( 1) + trTriaA.GetP( 2)) / 3 ;
|
|
double dMinDist = DBL_MAX ;
|
|
int nTriaIndex = - 1 ;
|
|
for ( int nTB = 0 ; nTB < int( it->second.size()) ; ++ nTB) {
|
|
Triangle3d trTriaB = it->second[nTB] ;
|
|
double dDot = ( ptBarA - trTriaB.GetP( 0)) * trTriaB.GetN() ;
|
|
if ( abs( dDot) > EPS_SMALL) {
|
|
DistPointTriangle DistCalc( ptBarA, trTriaB) ;
|
|
double dDist ;
|
|
DistCalc.GetDist( dDist) ;
|
|
if ( dDist < dMinDist) {
|
|
nTriaIndex = nTB ;
|
|
dMinDist = dDist ;
|
|
}
|
|
}
|
|
}
|
|
if ( nTriaIndex != - 1) {
|
|
Triangle3d trTriaB = it->second[nTriaIndex] ;
|
|
trTriaB.Validate() ;
|
|
double dDot = ( ptBarA - trTriaB.GetP( 0)) * trTriaB.GetN() ;
|
|
m_vTria[it->first].nTempPart = ( dDot < 0 ? 1 : - 1) ;
|
|
}
|
|
}
|
|
for ( auto it = AmbiguosB.begin() ; it != AmbiguosB.end() ; ++ it) {
|
|
Triangle3d trTriaB ;
|
|
SurfB.GetTriangle( it->first, trTriaB) ;
|
|
Point3d ptBarB = ( trTriaB.GetP( 0) + trTriaB.GetP( 1) + trTriaB.GetP( 2)) / 3 ;
|
|
double dMinDist = DBL_MAX ;
|
|
int nTriaIndex = - 1 ;
|
|
for ( int nTA = 0 ; nTA < int( it->second.size()) ; ++ nTA) {
|
|
Triangle3d trTriaA = it->second[nTA] ;
|
|
double dDot = ( ptBarB - trTriaA.GetP( 0)) * trTriaA.GetN() ;
|
|
if ( abs(dDot) > EPS_SMALL) {
|
|
DistPointTriangle DistCalc( ptBarB, trTriaA);
|
|
double dDist ;
|
|
DistCalc.GetDist( dDist) ;
|
|
if ( dDist < dMinDist) {
|
|
nTriaIndex = nTA ;
|
|
dMinDist = dDist ;
|
|
}
|
|
}
|
|
}
|
|
if ( nTriaIndex != - 1) {
|
|
Triangle3d trTriaA = it->second[nTriaIndex] ;
|
|
double dDot = ( ptBarB - trTriaA.GetP( 0)) * trTriaA.GetN() ;
|
|
SurfB.m_vTria[it->first].nTempPart = ( dDot < 0 ? 1 : -1) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool bContinue = true ;
|
|
// Se avvenuta modifica, aggiorno tutto
|
|
if ( bModif)
|
|
bContinue = ( AdjustVertices() && DoCompacting() && SurfB.AdjustVertices() && SurfB.DoCompacting()) ;
|
|
// Triangoli sovrapposti
|
|
if ( bContinue) {
|
|
int nTriaNumA = GetTriangleSize() ;
|
|
int nTriaNumB = SurfB.GetTriangleSize() ;
|
|
for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) {
|
|
// Se il triangolo A non è valido, continuo
|
|
Triangle3d trTriaA ;
|
|
if ( ! ( GetTriangle( nTA, trTriaA) && trTriaA.Validate( true)))
|
|
continue ;
|
|
// Box del triangolo A
|
|
BBox3d b3dTriaA ;
|
|
trTriaA.GetLocalBBox( b3dTriaA) ;
|
|
bool bNewTriaA = true ;
|
|
for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) {
|
|
// Se il triangolo B non è valido, continuo
|
|
Triangle3d trTriaB ;
|
|
if ( ! ( SurfB.GetTriangle( nTB, trTriaB) && trTriaB.Validate( true)))
|
|
continue ;
|
|
// Box del triangolo B
|
|
BBox3d b3dTriaB ;
|
|
trTriaB.GetLocalBBox( b3dTriaB) ;
|
|
// Se i box non si sovrappongono, contiuno
|
|
if ( ! b3dTriaA.Overlaps( b3dTriaB))
|
|
continue ;
|
|
// Se i triangoli sono sovrapposti
|
|
TRIA3DVECTOR vTriaAB ;
|
|
Point3d ptTempA, ptTempB ;
|
|
int nIntTypeAB = IntersTriaTria( trTriaA, trTriaB, ptTempA, ptTempB, vTriaAB) ;
|
|
if ( nIntTypeAB == ITTTS_OVERLAPS) {
|
|
bool bInvertB = trTriaA.GetN() * trTriaB.GetN() < 0. ;
|
|
m_vTria[nTA].nTempPart = ( bInvertB ? -2 : 2) ;
|
|
SurfB.m_vTria[nTB].nTempPart = ( bInvertB ? - 2 : 2) ;
|
|
}
|
|
}
|
|
}
|
|
return ( AdjustVertices() && DoCompacting() && SurfB.AdjustVertices() && SurfB.DoCompacting()) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::IdentifyParts( void) const
|
|
{
|
|
for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) {
|
|
// salto triangoli cancellati o già assegnati
|
|
if ( m_vTria[i].nIdVert[0] == SVT_DEL ||
|
|
abs( m_vTria[i].nTempPart) != 1)
|
|
continue ;
|
|
// set di triangoli da aggiornare
|
|
set<int> stTria ;
|
|
stTria.insert( i) ;
|
|
while ( ! stTria.empty()) {
|
|
// tolgo un triangolo dal set
|
|
const auto iIt = stTria.begin() ;
|
|
int nT = *iIt ;
|
|
stTria.erase( iIt) ;
|
|
// aggiorno i triangoli adiacenti
|
|
for ( int j = 0 ; j < 3 ; ++ j) {
|
|
int nAdjT = m_vTria[nT].nIdAdjac[j] ;
|
|
if ( nAdjT != SVT_NULL && m_vTria[nAdjT].nTempPart == 0) {
|
|
m_vTria[nAdjT].nTempPart = m_vTria[nT].nTempPart ;
|
|
stTria.insert( nAdjT) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::RemoveTJunction( void)
|
|
{
|
|
// Verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// Aggiorno timestamp dei triangoli
|
|
++ m_nTimeStamp ;
|
|
for ( auto& Tria : m_vTria)
|
|
Tria.nTemp = m_nTimeStamp ;
|
|
// Incremento time stamp
|
|
++ m_nTimeStamp ;
|
|
// Vettore di loop di T-Junction
|
|
TJuncLoopVec TJLVec ;
|
|
// Ciclo sui triangoli
|
|
for ( int nT = 0 ; nT < int( m_vTria.size()) ; ++ nT) {
|
|
// Se triangolo valido e non ancora visitato
|
|
if ( m_vTria[nT].nIdVert[0] != SVT_DEL && m_vTria[nT].nTemp != m_nTimeStamp) {
|
|
// Determino i triangoli adiacenti
|
|
int nAdjT[3] ;
|
|
for ( int j = 0 ; j < 3 ; ++ j)
|
|
nAdjT[j] = m_vTria[nT].nIdAdjac[j] ;
|
|
// Tre lati di contorno
|
|
if ( nAdjT[0] == SVT_NULL && nAdjT[1] == SVT_NULL && nAdjT[2] == SVT_NULL) {
|
|
m_vTria[nT].nTemp = m_nTimeStamp ;
|
|
}
|
|
// Lati 0 e 1 di contorno
|
|
else if ( nAdjT[0] == SVT_NULL && nAdjT[1] == SVT_NULL) {
|
|
// Ho trovato l'inizio di un loop
|
|
TJLVec.emplace_back() ;
|
|
TJLVec.back().emplace_back() ;
|
|
TJLVec.back().back().nTriaId = nT ;
|
|
TJLVec.back().back().nEdge = 0 ;
|
|
TJLVec.back().emplace_back() ;
|
|
TJLVec.back().back().nTriaId = nT ;
|
|
TJLVec.back().back().nEdge = 1 ;
|
|
// Marco il triangolo come verificato
|
|
m_vTria[nT].nTemp = m_nTimeStamp ;
|
|
// Cammino lungo il loop fino a chiuderlo
|
|
if ( ! MarchAlongFacetLoopForTJunc( nT, 2, m_nTimeStamp, TJLVec.back()))
|
|
return false ;
|
|
}
|
|
// Lati 1 e 2 di contorno
|
|
else if ( nAdjT[1] == SVT_NULL && nAdjT[2] == SVT_NULL) {
|
|
// Ho trovato l'inizio di un loop
|
|
TJLVec.emplace_back() ;
|
|
TJLVec.back().emplace_back() ;
|
|
TJLVec.back().back().nTriaId = nT ;
|
|
TJLVec.back().back().nEdge = 1 ;
|
|
TJLVec.back().emplace_back() ;
|
|
TJLVec.back().back().nTriaId = nT ;
|
|
TJLVec.back().back().nEdge = 2 ;
|
|
// Marco il triangolo come verificato
|
|
m_vTria[nT].nTemp = m_nTimeStamp ;
|
|
// Cammino lungo il loop fino a chiuderlo
|
|
if ( ! MarchAlongFacetLoopForTJunc( nT, 0, m_nTimeStamp, TJLVec.back()))
|
|
return false ;
|
|
}
|
|
// Lati 2 e 0 di contorno
|
|
else if ( nAdjT[2] == SVT_NULL && nAdjT[0] == SVT_NULL) {
|
|
// Ho trovato l'inizio di un loop
|
|
TJLVec.emplace_back() ;
|
|
TJLVec.back().emplace_back() ;
|
|
TJLVec.back().back().nTriaId = nT ;
|
|
TJLVec.back().back().nEdge = 2 ;
|
|
TJLVec.back().emplace_back() ;
|
|
TJLVec.back().back().nTriaId = nT ;
|
|
TJLVec.back().back().nEdge = 0 ;
|
|
// Marco il triangolo come verificato
|
|
m_vTria[nT].nTemp = m_nTimeStamp ;
|
|
// Cammino lungo il loop fino a chiuderlo
|
|
if ( ! MarchAlongFacetLoopForTJunc( nT, 1, m_nTimeStamp, TJLVec.back()))
|
|
return false ;
|
|
}
|
|
//Lato 0 di contorno
|
|
else if ( nAdjT[0] == SVT_NULL) {
|
|
// Ho trovato l'inizio di un loop
|
|
TJLVec.emplace_back() ;
|
|
TJLVec.back().emplace_back() ;
|
|
TJLVec.back().back().nTriaId = nT ;
|
|
TJLVec.back().back().nEdge = 0 ;
|
|
// Marco il triangolo come verificato
|
|
m_vTria[nT].nTemp = m_nTimeStamp ;
|
|
// Cammino lungo il loop fino a chiuderlo
|
|
if ( ! MarchAlongFacetLoopForTJunc( nT, 1, m_nTimeStamp, TJLVec.back()))
|
|
return false ;
|
|
}
|
|
// Lato 1 di contorno
|
|
else if ( nAdjT[1] == SVT_NULL) {
|
|
// Ho trovato l'inizio di un loop
|
|
TJLVec.emplace_back() ;
|
|
TJLVec.back().emplace_back() ;
|
|
TJLVec.back().back().nTriaId = nT ;
|
|
TJLVec.back().back().nEdge = 1 ;
|
|
// Marco il triangolo come verificato
|
|
m_vTria[nT].nTemp = m_nTimeStamp ;
|
|
// Cammino lungo il loop fino a chiuderlo
|
|
if ( ! MarchAlongFacetLoopForTJunc( nT, 2, m_nTimeStamp, TJLVec.back()))
|
|
return false ;
|
|
}
|
|
// Lato 2 di contorno
|
|
else if ( nAdjT[2] == SVT_NULL) {
|
|
// Ho trovato l'inizio di un loop
|
|
TJLVec.emplace_back() ;
|
|
TJLVec.back().emplace_back() ;
|
|
TJLVec.back().back().nTriaId = nT ;
|
|
TJLVec.back().back().nEdge = 2 ;
|
|
// Marco il triangolo come verificato
|
|
m_vTria[nT].nTemp = m_nTimeStamp ;
|
|
// Cammino lungo il loop fino a chiuderlo
|
|
if ( ! MarchAlongFacetLoopForTJunc( nT, 0, m_nTimeStamp, TJLVec.back()))
|
|
return false ;
|
|
}
|
|
// Altrimenti non c'è contorno
|
|
else {
|
|
// Marco il triangolo come verificato
|
|
m_vTria[nT].nTemp = m_nTimeStamp ;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<std::vector<TJEdgeSet>> vvIndexesSet ;
|
|
// Cerco delle T-Junction nei loop trovati
|
|
for ( int nL = 0 ; nL < int( TJLVec.size()) ; ++ nL) {
|
|
// Ciclo suigli edges per raggrupparli
|
|
for ( int nPos1 = 0 ; nPos1 < int( TJLVec[nL].size()) ; ++ nPos1) {
|
|
bool bNew = true ;
|
|
for ( int nPos2 = 0 ; nPos2 < int( TJLVec[nL].size()) ; ++ nPos2) {
|
|
if ( nPos1 == nPos2)
|
|
continue ;
|
|
// Punti estremi dei due edge correnti
|
|
Point3d ptS1, ptE1, ptS2, ptE2 ;
|
|
GetVertex( m_vTria[TJLVec[nL][nPos1].nTriaId].nIdVert[TJLVec[nL][nPos1].nEdge], ptS1) ;
|
|
GetVertex( m_vTria[TJLVec[nL][nPos1].nTriaId].nIdVert[( TJLVec[nL][nPos1].nEdge + 1) % 3], ptE1) ;
|
|
GetVertex( m_vTria[TJLVec[nL][nPos2].nTriaId].nIdVert[TJLVec[nL][nPos2].nEdge], ptS2) ;
|
|
GetVertex( m_vTria[TJLVec[nL][nPos2].nTriaId].nIdVert[( TJLVec[nL][nPos2].nEdge + 1) % 3], ptE2) ;
|
|
Vector3d vtV = ptE1 - ptS1 ;
|
|
double dLen = vtV.Len() ;
|
|
vtV.Normalize() ;
|
|
double dProjSt = ( ptS2 - ptS1) * vtV ;
|
|
double dProjEn = ( ptE2 - ptS1) * vtV ;
|
|
double dOrtSt = ( ( ptS2 - ptS1) - dProjSt * vtV).Len() ;
|
|
double dOrtEn = ( ( ptE2 - ptS1) - dProjEn * vtV).Len() ;
|
|
// Edge di posizione 2 forma una T-Junction su edge di posizione 1
|
|
if ( ( dProjSt > EPS_SMALL && dProjSt < dLen - EPS_SMALL && dOrtSt < EPS_SMALL) ||
|
|
( dProjEn > EPS_SMALL && dProjEn < dLen - EPS_SMALL && dOrtEn < EPS_SMALL)) {
|
|
// Edge di pos 1 non aveva ancora T-Junction con edge di pos 2
|
|
if ( bNew) {
|
|
// Aggiungo il vettore di tutti i gruppi di edge che formano T-Junction con endge di pos 1,
|
|
// aggiungo il gruppo con la normale di edge di pos 2 e aggiungo edge di pos due a tale gruppo.
|
|
vvIndexesSet.emplace_back() ;
|
|
vvIndexesSet[vvIndexesSet.size() - 1].emplace_back() ;
|
|
vvIndexesSet[vvIndexesSet.size() - 1][vvIndexesSet[vvIndexesSet.size() - 1].size() - 1].emplace( TJLVec[nL][nPos2]) ;
|
|
bNew = false ;
|
|
}
|
|
// Edge di pos 1 aveva già T-Junction con edge di pos 2
|
|
else {
|
|
// Cerco nei triangoli degli edge di pos 2 già trovati alcuni con la normale uguale al nuovo trovato
|
|
int nNorm ;
|
|
for ( nNorm = 0 ; nNorm < int( vvIndexesSet[vvIndexesSet.size() - 1].size()) ; ++ nNorm) {
|
|
auto TEdgePtr = vvIndexesSet[vvIndexesSet.size() - 1][nNorm].begin() ;
|
|
if ( AreSameVectorExact( m_vTria[TEdgePtr->nTriaId].vtN, m_vTria[TJLVec[nL][nPos2].nTriaId].vtN)) {
|
|
break ;
|
|
}
|
|
}
|
|
// Se non ho trovato tali triangoli aggiungo un nuovo gruppo
|
|
if ( nNorm == int( vvIndexesSet[vvIndexesSet.size() - 1].size())) {
|
|
vvIndexesSet[vvIndexesSet.size() - 1].emplace_back() ;
|
|
}
|
|
// Aggiungo il nuovo edge al suo gruppo
|
|
vvIndexesSet[vvIndexesSet.size() - 1][nNorm].emplace( TJLVec[nL][nPos2]) ;
|
|
}
|
|
// Fra i triangoli adiacenti al triangolo con l'edge di pos 2
|
|
// ne cerco altri con un vertice nella T-Junction
|
|
for ( int m = 0 ; m < 3 ; ++ m) {
|
|
// Triangolo adiacente e suo indice
|
|
int nAdjTriaIndex = m_vTria[TJLVec[nL][nPos2].nTriaId].nIdAdjac[m] ;
|
|
Triangle3d trAdjTria ;
|
|
if ( GetTriangle( nAdjTriaIndex, trAdjTria)) {
|
|
// Ciclo sugli edge del triangolo adiacente
|
|
for ( int nVrt = 0 ; nVrt < 3 ; ++ nVrt) {
|
|
double dAdjProjVrt = ( trAdjTria.GetP( nVrt) - ptS1) * vtV ;
|
|
double dAdjOrtVrt = ( ( trAdjTria.GetP( nVrt) - ptS1) - dAdjProjVrt * vtV).Len() ;
|
|
double dAdjProjNxt1 = ( trAdjTria.GetP( ( nVrt + 1) % 3) - ptS1) * vtV ;
|
|
double dAdjOrtNxt1 = ( ( trAdjTria.GetP( ( nVrt + 1) % 3) - ptS1) - dAdjProjNxt1 * vtV).Len() ;
|
|
double dAdjProjNxt2 = ( trAdjTria.GetP( ( nVrt + 2) % 3) - ptS1) * vtV ;
|
|
double dAdjOrtNxt2 = ( ( trAdjTria.GetP( ( nVrt + 2) % 3) - ptS1) - dAdjProjNxt2 * vtV).Len() ;
|
|
// Triangolo adiacente forma una T-Junction con l'edge di pos 1
|
|
if ( dAdjProjVrt > EPS_SMALL && dAdjProjVrt < dLen - EPS_SMALL && dAdjOrtVrt < EPS_SMALL &&
|
|
dAdjOrtNxt1 > EPS_SMALL && dAdjOrtNxt2 > EPS_SMALL) {
|
|
// Lo aggiungo nel gruppo con i triangoli aventi la sua normale.
|
|
// Se tale gruppo non esiste, lo aggiungo preventivamente
|
|
int nNorm ;
|
|
for ( nNorm = 0 ; nNorm < int( vvIndexesSet[vvIndexesSet.size() - 1].size()) ; ++ nNorm) {
|
|
auto TEdgePtr = vvIndexesSet[vvIndexesSet.size() - 1][nNorm].begin() ;
|
|
if ( AreSameVectorExact( m_vTria[TEdgePtr->nTriaId].vtN, m_vTria[nAdjTriaIndex].vtN)) {
|
|
break ;
|
|
}
|
|
}
|
|
if ( nNorm == int( vvIndexesSet[vvIndexesSet.size() - 1].size())) {
|
|
vvIndexesSet[vvIndexesSet.size() - 1].emplace_back() ;
|
|
}
|
|
// Cerco adiacenti dell'adiacente
|
|
TEdgeId TJAdjTria ;
|
|
TJAdjTria.nTriaId = nAdjTriaIndex ;
|
|
TJAdjTria.nEdge = nVrt ;
|
|
vvIndexesSet[vvIndexesSet.size() - 1][nNorm].emplace( TJAdjTria) ;
|
|
TEdgeId TJTurnTria ;
|
|
TJTurnTria.nTriaId = TJAdjTria.nTriaId ;
|
|
TJTurnTria.nEdge = TJAdjTria.nEdge ;
|
|
while ( GetForwardAdjTriaSharingVertex( TJTurnTria.nTriaId, TJTurnTria.nEdge) &&
|
|
TJTurnTria.nTriaId != TJAdjTria.nTriaId) {
|
|
if ( AreSameVectorExact( m_vTria[TJTurnTria.nTriaId].vtN, m_vTria[TJAdjTria.nTriaId].vtN)) {
|
|
vvIndexesSet[vvIndexesSet.size() - 1][nNorm].emplace( TJTurnTria) ;
|
|
}
|
|
}
|
|
TJTurnTria.nTriaId = TJAdjTria.nTriaId ;
|
|
TJTurnTria.nEdge = TJAdjTria.nEdge ;
|
|
while ( GetBackwardAdjTriaSharingVertex( TJTurnTria.nTriaId, TJTurnTria.nEdge) &&
|
|
TJTurnTria.nTriaId != TJAdjTria.nTriaId) {
|
|
if ( AreSameVectorExact( m_vTria[TJTurnTria.nTriaId].vtN, m_vTria[TJAdjTria.nTriaId].vtN)) {
|
|
vvIndexesSet[vvIndexesSet.size() - 1][nNorm].emplace( TJTurnTria) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Fra Loop diversi cerco se un medesimo gruppo appartiene a più edge dello stesso loop
|
|
// o edge di loop diversi. In entrambi i casi fondo i gruppi.
|
|
for ( int nL1 = 0 ; nL1 < int( vvIndexesSet.size()) ; ++ nL1) {
|
|
for ( int nL2 = nL1 + 1 ; nL2 < int( vvIndexesSet.size()) ; ++ nL2) {
|
|
for ( int nN1 = 0 ; nN1 < int( vvIndexesSet[nL1].size()) ; ++ nN1) {
|
|
for ( int nN2 = 0 ; nN2 < int( vvIndexesSet[nL2].size()) ; ++ nN2) {
|
|
bool bFoundCouple = false ;
|
|
for ( auto it1 = vvIndexesSet[nL1][nN1].begin() ; it1 != vvIndexesSet[nL1][nN1].end() ; ++ it1) {
|
|
for ( auto it2 = vvIndexesSet[nL2][nN2].begin() ; it2 != vvIndexesSet[nL2][nN2].end() ; ++ it2) {
|
|
if ( it1->nTriaId == it2->nTriaId) {
|
|
bFoundCouple = true ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( bFoundCouple)
|
|
break ;
|
|
}
|
|
if ( bFoundCouple) {
|
|
if ( vvIndexesSet[nL1][nN1].size() < vvIndexesSet[nL2][nN2].size()) {
|
|
for ( auto it1 = vvIndexesSet[nL1][nN1].begin() ; it1 != vvIndexesSet[nL1][nN1].end() ; ++ it1) {
|
|
vvIndexesSet[nL2][nN2].emplace( *it1) ;
|
|
}
|
|
vvIndexesSet[nL1][nN1].clear() ;
|
|
}
|
|
else {
|
|
for ( auto it2 = vvIndexesSet[nL2][nN2].begin() ; it2 != vvIndexesSet[nL2][nN2].end(); ++ it2) {
|
|
vvIndexesSet[nL1][nN1].emplace( *it2) ;
|
|
}
|
|
vvIndexesSet[nL2][nN2].clear() ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Retriangolarizzo i poligoni
|
|
for ( int nP = 0 ; nP < int( vvIndexesSet.size()) ; ++ nP) {
|
|
for ( int nPP = 0 ; nPP < int( vvIndexesSet[nP].size()) ; ++ nPP) {
|
|
auto it = vvIndexesSet[nP][nPP].begin() ;
|
|
if ( it == vvIndexesSet[nP][nPP].end())
|
|
continue ;
|
|
Point3d ptP0, ptP1, ptP2 ;
|
|
GetVertex( m_vTria[it->nTriaId].nIdVert[0], ptP0) ;
|
|
GetVertex( m_vTria[it->nTriaId].nIdVert[1], ptP1) ;
|
|
GetVertex( m_vTria[it->nTriaId].nIdVert[2], ptP2) ;
|
|
CurveLine cvLine0 ;
|
|
cvLine0.Set( ptP0, ptP1) ;
|
|
CurveLine cvLine1 ;
|
|
cvLine1.Set( ptP1, ptP2) ;
|
|
CurveLine cvLine2 ;
|
|
cvLine2.Set( ptP2, ptP0) ;
|
|
CurveComposite cvLoop ;
|
|
cvLoop.AddCurve( cvLine0) ;
|
|
cvLoop.AddCurve( cvLine1) ;
|
|
cvLoop.AddCurve( cvLine2) ;
|
|
SurfFlatRegion Facet ;
|
|
Facet.AddExtLoop( cvLoop) ;
|
|
RemoveTriangle( it->nTriaId) ;
|
|
++ it ;
|
|
for ( ; it != vvIndexesSet[nP][nPP].end() ; ) {
|
|
Point3d ptAddP0, ptAddP1, ptAddP2;
|
|
if ( ! ( GetVertex( m_vTria[it->nTriaId].nIdVert[0], ptAddP0) &&
|
|
GetVertex( m_vTria[it->nTriaId].nIdVert[1], ptAddP1) &&
|
|
GetVertex( m_vTria[it->nTriaId].nIdVert[2], ptAddP2))) {
|
|
++ it ;
|
|
continue ;
|
|
}
|
|
CurveLine cvAddLine0 ;
|
|
cvAddLine0.Set( ptAddP0, ptAddP1) ;
|
|
CurveLine cvAddLine1 ;
|
|
cvAddLine1.Set( ptAddP1, ptAddP2) ;
|
|
CurveLine cvAddLine2 ;
|
|
cvAddLine2.Set( ptAddP2, ptAddP0) ;
|
|
CurveComposite cvAddLoop ;
|
|
cvAddLoop.AddCurve( cvAddLine0) ;
|
|
cvAddLoop.AddCurve( cvAddLine1) ;
|
|
cvAddLoop.AddCurve( cvAddLine2) ;
|
|
SurfFlatRegion AddFacet ;
|
|
AddFacet.AddExtLoop( cvAddLoop) ;
|
|
Facet.Add( AddFacet) ;
|
|
RemoveTriangle( it->nTriaId) ;
|
|
++it ;
|
|
}
|
|
int nChunkNum = Facet.GetChunkCount() ;
|
|
for ( int nChunk = 0 ; nChunk < nChunkNum ; ++ nChunk) {
|
|
ICurve* pOutline = Facet.GetLoop( nChunk, 0) ;
|
|
PolyLine PolyOutline ;
|
|
pOutline->ApproxWithLines( LIN_TOL_FINE, ANG_TOL_STD_DEG, ICurve::APL_STD, PolyOutline) ;
|
|
PNTVECTOR vPt ;
|
|
INTVECTOR vTr ;
|
|
if ( Triangulate().Make( PolyOutline, 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]]) } ;
|
|
AddTriangle( nNewId) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::MarchAlongFacetLoopForTJunc( int nT, int nV, int nTimeStamp, TJuncLoop& TJLoop) const
|
|
{
|
|
// Mi muovo lungo il loop, un triangolo alla volta
|
|
bool bEnd = false ;
|
|
while ( ! bEnd) {
|
|
if ( ! MarchOneFacetTriaForTJunc( nT, nV, nTimeStamp, TJLoop, bEnd))
|
|
return false ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::MarchOneFacetTriaForTJunc( int& nT, int& nV, int nTimeStamp, TJuncLoop& TJLoop, bool& bEnd) const
|
|
{
|
|
// Verifico esistenza triangolo adiacente, sul lato dopo il vertice
|
|
if ( m_vTria[nT].nIdAdjac[nV] == SVT_NULL)
|
|
return false ;
|
|
// Indice del triangolo adiacente
|
|
int nAdjT = m_vTria[nT].nIdAdjac[nV] ;
|
|
// Recupero il suo lato di adiacenza
|
|
int nAdjS = SVT_NULL ;
|
|
for ( int i = 0 ; i < 3 ; ++ i) {
|
|
if ( m_vTria[nAdjT].nIdAdjac[i] == nT) {
|
|
nAdjS = i ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( nAdjS == SVT_NULL)
|
|
return false ;
|
|
// Vertice di fine adiacenza e indice del successivo lato
|
|
int nAdjV = Next( nAdjS) ;
|
|
// Verifico se il lato successivo è un bordo
|
|
int nNextT = m_vTria[nAdjT].nIdAdjac[nAdjV] ;
|
|
if ( nNextT == SVT_NULL) {
|
|
// Se già recuperato
|
|
if ( m_vTria[nAdjT].nTemp == nTimeStamp) {
|
|
bEnd = true ;
|
|
return true ;
|
|
}
|
|
// Dichiaro triangolo analizzato
|
|
m_vTria[nAdjT].nTemp = nTimeStamp ;
|
|
// Aggiungo il lato al loop
|
|
TJLoop.emplace_back() ;
|
|
TJLoop.back().nTriaId = nAdjT ;
|
|
TJLoop.back().nEdge = nAdjV ;
|
|
// Verifico anche il successivo
|
|
nAdjV = Next( nAdjV) ;
|
|
nNextT = m_vTria[nAdjT].nIdAdjac[nAdjV] ;
|
|
if ( nNextT == SVT_NULL) {
|
|
// Aggiungo il lato al loop
|
|
TJLoop.emplace_back() ;
|
|
TJLoop.back().nTriaId = nAdjT ;
|
|
TJLoop.back().nEdge = nAdjV ;
|
|
nAdjV = Next(nAdjV);
|
|
}
|
|
}
|
|
// Devo passare al triangolo adiacente
|
|
nT = nAdjT ;
|
|
nV = nAdjV ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::GetForwardAdjTriaSharingVertex( int& nTria, int& nVertInTria) const
|
|
{
|
|
// Verifico validità della posizione del vertice nel triangolo
|
|
if ( nVertInTria < 0 || nVertInTria > 2)
|
|
return false ;
|
|
int nVert = m_vTria[nTria].nIdVert[nVertInTria] ;
|
|
// Verifico esistenza del vertice
|
|
if ( nVert < 0 || nVert >= GetVertexSize() || m_vVert[nVert].nIdTria == SVT_DEL)
|
|
return false ;
|
|
// Verifico esistenza del triangolo
|
|
if ( nTria < 0 || nTria >= GetTriangleSize() || m_vTria[nTria].nIdVert[0] == SVT_DEL)
|
|
return false ;
|
|
// Trovo triangolo adiacente che condivide il vertice
|
|
nTria = m_vTria[nTria].nIdAdjac[nVertInTria] ;
|
|
if ( nTria < 0 || nTria >= GetTriangleSize())
|
|
return false ;
|
|
// Trovo posizione del vertice nel triangolo adiacente
|
|
nVertInTria = - 1 ;
|
|
for ( int n = 0 ; n < 3 ; ++ n) {
|
|
if ( m_vTria[nTria].nIdVert[n] == nVert)
|
|
nVertInTria = n ;
|
|
}
|
|
return ( nVertInTria != - 1) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::GetBackwardAdjTriaSharingVertex( int& nTria, int& nVertInTria) const
|
|
{
|
|
// Verifico validità della posizione del vertice nel triangolo
|
|
if ( nVertInTria < 0 || nVertInTria > 2)
|
|
return false ;
|
|
int nVert = m_vTria[nTria].nIdVert[nVertInTria] ;
|
|
// Verifico esistenza del vertice
|
|
if ( nVert < 0 || nVert >= GetVertexSize() || m_vVert[nVert].nIdTria == SVT_DEL)
|
|
return false ;
|
|
// Verifico esistenza del triangolo
|
|
if ( nTria < 0 || nTria >= GetTriangleSize() || m_vTria[nTria].nIdVert[0] == SVT_DEL)
|
|
return false ;
|
|
// Trovo triangolo adiacente che condivide il vertice
|
|
nTria = m_vTria[nTria].nIdAdjac[( nVertInTria + 2) % 3] ;
|
|
if ( nTria < 0 || nTria >= GetTriangleSize())
|
|
return false ;
|
|
// Trovo posizione del vertice nel triangolo adiacente
|
|
nVertInTria = -1 ;
|
|
for ( int n = 0 ; n < 3 ; ++ n) {
|
|
if ( m_vTria[nTria].nIdVert[n] == nVert)
|
|
nVertInTria = n ;
|
|
}
|
|
return ( nVertInTria != - 1) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::Add( const ISurfTriMesh& Other)
|
|
{
|
|
SurfTriMesh SurfB ;
|
|
SurfB.CopyFrom( &Other) ;
|
|
IntersectTriMeshTriangle( SurfB) ;
|
|
IdentifyParts() ;
|
|
SurfB.IdentifyParts() ;
|
|
int nTriaNumA = GetTriangleSize() ;
|
|
for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) {
|
|
if ( m_vTria[nTA].nTempPart == 1 || m_vTria[nTA].nTempPart == - 2)
|
|
RemoveTriangle( nTA) ;
|
|
}
|
|
int nTriaNumB = SurfB.GetTriangleSize() ;
|
|
for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) {
|
|
if ( SurfB.m_vTria[nTB].nTempPart == - 1) {
|
|
int nNewVert[3] ;
|
|
for ( int nV = 0 ; nV < 3 ; ++ nV) {
|
|
nNewVert[nV] = AddVertex( SurfB.m_vVert[SurfB.m_vTria[nTB].nIdVert[nV]].ptP) ;
|
|
}
|
|
AddTriangle( nNewVert) ;
|
|
}
|
|
}
|
|
bool bContinue = ( AdjustVertices() && DoCompacting()) ;
|
|
if ( bContinue)
|
|
RemoveTJunction() ;
|
|
else
|
|
return false ;
|
|
return ( AdjustVertices() && DoCompacting()) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::Intersect( const ISurfTriMesh& Other)
|
|
{
|
|
SurfTriMesh SurfB ;
|
|
SurfB.CopyFrom( &Other) ;
|
|
IntersectTriMeshTriangle( SurfB) ;
|
|
IdentifyParts() ;
|
|
SurfB.IdentifyParts() ;
|
|
int nTriaNumA = GetTriangleSize() ;
|
|
for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) {
|
|
if ( m_vTria[nTA].nTempPart == - 1 || m_vTria[nTA].nTempPart == - 2)
|
|
RemoveTriangle( nTA) ;
|
|
}
|
|
int nTriaNumB = SurfB.GetTriangleSize() ;
|
|
for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) {
|
|
if ( SurfB.m_vTria[nTB].nTempPart == 1) {
|
|
int nNewVert[3] ;
|
|
for ( int nV = 0 ; nV < 3 ; ++ nV) {
|
|
nNewVert[nV] = AddVertex( SurfB.m_vVert[SurfB.m_vTria[nTB].nIdVert[nV]].ptP) ;
|
|
}
|
|
AddTriangle( nNewVert) ;
|
|
}
|
|
}
|
|
bool bContinue = ( AdjustVertices() && DoCompacting()) ;
|
|
if ( bContinue)
|
|
RemoveTJunction() ;
|
|
else
|
|
return false ;
|
|
return ( AdjustVertices() && DoCompacting()) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::Subtract( const ISurfTriMesh& Other)
|
|
{
|
|
SurfTriMesh SurfB ;
|
|
SurfB.CopyFrom( &Other) ;
|
|
IntersectTriMeshTriangle( SurfB) ;
|
|
IdentifyParts() ;
|
|
SurfB.IdentifyParts() ;
|
|
int nTriaNumA = GetTriangleSize() ;
|
|
for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) {
|
|
if ( m_vTria[nTA].nTempPart == 1 || m_vTria[nTA].nTempPart == 2)
|
|
RemoveTriangle( nTA) ;
|
|
}
|
|
int nTriaNumB = SurfB.GetTriangleSize() ;
|
|
for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) {
|
|
if ( SurfB.m_vTria[nTB].nTempPart == 1) {
|
|
int nNewVert[3] ;
|
|
for ( int nV = 0 ; nV < 3 ; ++ nV) {
|
|
nNewVert[nV] = AddVertex( SurfB.m_vVert[SurfB.m_vTria[nTB].nIdVert[nV]].ptP) ;
|
|
}
|
|
swap( nNewVert[1], nNewVert[2]) ;
|
|
AddTriangle( nNewVert) ;
|
|
}
|
|
}
|
|
bool bContinue = ( AdjustVertices() && DoCompacting()) ;
|
|
if ( bContinue)
|
|
RemoveTJunction() ;
|
|
else
|
|
return false ;
|
|
return ( AdjustVertices() && DoCompacting()) ;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////// DEBUG /////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//if ( ( AreSamePointApprox(trTriaA.GetP(0), Point3d(20, 40, 46)) &&
|
|
// AreSamePointApprox(trTriaA.GetP(1), Point3d(100, 40, 30)) &&
|
|
// AreSamePointApprox(trTriaA.GetP(2), Point3d(20, 40, 30))) ||
|
|
// ( AreSamePointApprox(trTriaA.GetP(2), Point3d(20, 40, 46)) &&
|
|
// AreSamePointApprox(trTriaA.GetP(0), Point3d(100, 40, 30)) &&
|
|
// AreSamePointApprox(trTriaA.GetP(1), Point3d(20, 40, 30))) ||
|
|
// ( AreSamePointApprox(trTriaA.GetP(1), Point3d(20, 40, 46)) &&
|
|
// AreSamePointApprox(trTriaA.GetP(2), Point3d(100, 40, 30)) &&
|
|
// AreSamePointApprox(trTriaA.GetP(0), Point3d(20, 40, 30)))) {
|
|
// int a = 0 ;
|
|
//}
|
|
//
|
|
//if ( ( AreSamePointApprox(trTriaB.GetP(0), Point3d(76, 40, 30)) &&
|
|
// AreSamePointApprox(trTriaB.GetP(1), Point3d(60, 40, 50)) &&
|
|
// AreSamePointApprox(trTriaB.GetP(2), Point3d(20, 40, 30))) ||
|
|
// ( AreSamePointApprox(trTriaB.GetP(2), Point3d(76, 40, 30)) &&
|
|
// AreSamePointApprox(trTriaB.GetP(0), Point3d(60, 40, 50)) &&
|
|
// AreSamePointApprox(trTriaB.GetP(1), Point3d(20, 40, 30))) ||
|
|
// ( AreSamePointApprox(trTriaB.GetP(1), Point3d(76, 40, 30)) &&
|
|
// AreSamePointApprox(trTriaB.GetP(2), Point3d(60, 40, 50)) &&
|
|
// AreSamePointApprox(trTriaB.GetP(0), Point3d(20, 40, 30)))) {
|
|
// int b = 0 ;
|
|
//}
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//if ((AreSamePointApprox(trTriaA.GetP(0), Point3d(20, 40, 46)) &&
|
|
// AreSamePointApprox(trTriaA.GetP(1), Point3d(100, 40, 30)) &&
|
|
// AreSamePointApprox(trTriaA.GetP(2), Point3d(20, 40, 30))) ||
|
|
// (AreSamePointApprox(trTriaA.GetP(2), Point3d(20, 40, 46)) &&
|
|
// AreSamePointApprox(trTriaA.GetP(0), Point3d(100, 40, 30)) &&
|
|
// AreSamePointApprox(trTriaA.GetP(1), Point3d(20, 40, 30))) ||
|
|
// (AreSamePointApprox(trTriaA.GetP(1), Point3d(20, 40, 46)) &&
|
|
// AreSamePointApprox(trTriaA.GetP(2), Point3d(100, 40, 30)) &&
|
|
// AreSamePointApprox(trTriaA.GetP(0), Point3d(20, 40, 30)))) {
|
|
//
|
|
// if ((AreSamePointApprox(trTriaB.GetP(0), Point3d(76, 40, 30)) &&
|
|
// AreSamePointApprox(trTriaB.GetP(1), Point3d(60, 40, 50)) &&
|
|
// AreSamePointApprox(trTriaB.GetP(2), Point3d(20, 40, 30))) ||
|
|
// (AreSamePointApprox(trTriaB.GetP(2), Point3d(76, 40, 30)) &&
|
|
// AreSamePointApprox(trTriaB.GetP(0), Point3d(60, 40, 50)) &&
|
|
// AreSamePointApprox(trTriaB.GetP(1), Point3d(20, 40, 30))) ||
|
|
// (AreSamePointApprox(trTriaB.GetP(1), Point3d(76, 40, 30)) &&
|
|
// AreSamePointApprox(trTriaB.GetP(2), Point3d(60, 40, 50)) &&
|
|
// AreSamePointApprox(trTriaB.GetP(0), Point3d(20, 40, 30)))) {
|
|
// int b = 0;
|
|
// }
|
|
//}
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//bool
|
|
//FacesRetriangulation()
|
|
//{
|
|
// // Mi assicuro che la trimesh sia ok
|
|
// // Assicurarsi che la trimesh sia ok ......
|
|
// // Pongo tutti i triangoli come non visitati
|
|
// for ( int nT = 0 ; nT < GetTriangleSize() ; ++ nT) {
|
|
// m_vTria[nT].nTemp = 0 ;
|
|
// }
|
|
// // Ciclo sui triangoli
|
|
// for ( int nT = 0 ; nT < GetTriangleSize() ; ++ nT) {
|
|
// // Se triangolo non visitato
|
|
// if ( m_vTria[nT].nTemp == 0) {
|
|
// m_vTria[nT].nTemp = 1 ;
|
|
// std::unordered_set<int> TriaIndexSet ;// devi usare stack
|
|
// TriaIndexSet.emplace( nT) ;
|
|
// while ( ! TriaIndexSet.empty()) {
|
|
//
|
|
// }
|
|
// }
|
|
// }
|
|
// return true ;
|
|
//}
|