Files
EgtGeomKernel/SurfTriMeshBooleans.cpp
T
Dario Sassi 1fc9d137d9 EgtGeomKernel 2.1f4 :
- modifiche e correzioni a GeneralizedCut di SurfTriMesh.
2019-06-28 07:11:23 +00:00

832 lines
44 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/EgkIntersLineTria.h"
#include "/EgtDev/Include/EgkIntersTriaTria.h"
#include "/EgtDev/Include/EGkChainCurves.h"
#include "/EgtDev/Include/EGkGeoCollection.h"
#include <algorithm>
using namespace std ;
//----------------------------------------------------------------------------
// Struttura segmento di intersezione
struct IntSegment {
Point3d ptSt ;
Point3d ptEn ;
Vector3d vtOuter ;
bool bDegenerate ;
} ;
// Tipo chain
typedef vector<IntSegment> Chain ;
// Tipo vettore di Chain
typedef vector<Chain> CHAINVECTOR ;
//----------------------------------------------------------------------------
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 ( nIntTypeA == ITTT_PNT || nIntTypeA == ITTT_VERT)
nIntA = 1 ;
else if ( nIntTypeA == ITTT_YES || 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 ( nIntTypeB == ITTT_PNT || nIntTypeB == ITTT_VERT)
nIntB = 1 ;
else if ( nIntTypeB == ITTT_YES || 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
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 ;
// Ne calcolo una copia proiettata sul piano della curva
// 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( 1)) ;
cvFirstLoop.emplace_back( trTria.GetP( 2)) ;
cvFirstLoop.emplace_back( trTria.GetP( 2)) ;
cvFirstLoop.emplace_back( trTria.GetP( 0)) ;
vector<PNTVECTOR> cvBoundClosedLoopVec ;
cvBoundClosedLoopVec.emplace_back(cvFirstLoop);
vector<bool> 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 ;
// Cerco se esistono dei tratti del loop chiuso corrente che sono
// toccati dagli estremi del loop aperto corrente
int nCvSt = -1 ;
int nCvEn = -1 ;
for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) - 1 && ( nCvSt == -1 || nCvEn == -1) ; nLine += 2) {
// Estremi del segmento corrente del loop chiuso corrente
Point3d ptSegSt = cvBoundClosedLoopVec[nLoop][nLine] ;
Point3d ptSegEn = cvBoundClosedLoopVec[nLoop][nLine + 1] ;
// Vedo se gli estremi del loop aperto stanno su un segmento del chiuso
DistPointLine dStDistCalc( ptOpenLoopStP, ptSegSt, ptSegEn) ;
DistPointLine dEnDistCalc( ptOpenLoopEnP, ptSegSt, ptSegEn) ;
double dSqDistSt ;
dStDistCalc.GetSqDist(dSqDistSt) ;
if ( dSqDistSt < SQ_EPS_SMALL) {
nCvSt = nLine ;
}
double dSqDistEn ;
dEnDistCalc.GetSqDist(dSqDistEn) ;
if ( dSqDistEn < SQ_EPS_SMALL) {
nCvEn = nLine ;
}
}
// Se entrambi gli estremi del loop aperto sono su un segmento del loop chiuso devo dividere il loop in due
if ( nCvSt != - 1 && nCvEn != - 1) {
// Entrambi gli estremi del loop aperto sono su uno stesso segmento del loop chiuso
if ( nCvSt == nCvEn) {
bool bFirstInside ;
bool bFirstSt ;
PNTVECTOR cvSplitLoop1, cvSplitLoop2 ;
// Creo primo loop
for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) - 1 ; nLine += 2) {
// Segmenti loop chiuso
if ( nLine != nCvSt && nLine != nCvEn) {
cvSplitLoop1.emplace_back( cvBoundClosedLoopVec[nLoop][nLine]) ;
cvSplitLoop1.emplace_back( cvBoundClosedLoopVec[nLoop][nLine+1]) ;
}
// Dal chiuso all'aperto
else if ( nLine == nCvSt) {
// Distanze degli estremi del loop aperto dal punto iniziale del segmento corrente
Point3d ptSegSt, ptSegEn ;
ptSegSt = cvBoundClosedLoopVec[nLoop][nLine] ;
double dDistStSt = SqDist( ptSegSt, ptOpenLoopStP) ;
double dDistStEn = SqDist( ptSegSt, ptOpenLoopEnP) ;
// Devo percorrere il loop aperto nel suo verso
if ( dDistStSt < dDistStEn) {
// Dall'inizio del segmento corrente fino all'inizio del loop aperto
ptSegEn = ptOpenLoopStP ;
cvSplitLoop1.emplace_back( ptSegSt) ;
cvSplitLoop1.emplace_back( ptSegEn) ;
// Loop aperto
for ( int nOpenLine = 0 ; nOpenLine < int( cvOpenChain[nLastOpenLoopN].size()) ; ++ nOpenLine) {
Point3d ptOpenSt = cvOpenChain[nLastOpenLoopN][nOpenLine].ptSt ;
Point3d ptOpenEn = cvOpenChain[nLastOpenLoopN][nOpenLine].ptEn ;
cvSplitLoop1.emplace_back( ptOpenSt) ;
cvSplitLoop1.emplace_back( ptOpenEn) ;
if ( nOpenLine == 0) {
Vector3d vtLast = ptSegSt - ptSegEn ;
vtLast.Normalize() ;
bFirstInside = vtLast * cvOpenChain[nLastOpenLoopN][nOpenLine].vtOuter < 0. ;
}
}
// Dalla fine del loop aperto alla fine del segmento corrente
ptSegSt = ptOpenLoopEnP ;
ptSegEn = cvBoundClosedLoopVec[nLoop][nLine+1] ;
cvSplitLoop1.emplace_back( ptSegSt) ;
cvSplitLoop1.emplace_back( ptSegEn) ;
bFirstSt = true ;
}
// Devo percorrere il loop aperto contro il suo verso
else {
// Dall'inizio del segmento corrente fino alla fine del loop aperto
ptSegEn = ptOpenLoopEnP ;
cvSplitLoop1.emplace_back( ptSegSt) ;
cvSplitLoop1.emplace_back( ptSegEn) ;
// Loop aperto
for ( int nOpenLine = int( cvOpenChain[nLastOpenLoopN].size()) - 1 ; nOpenLine >= 0 ; -- nOpenLine) {
Point3d ptOpenSt = cvOpenChain[nLastOpenLoopN][nOpenLine].ptEn ;
Point3d ptOpenEn = cvOpenChain[nLastOpenLoopN][nOpenLine].ptSt ;
cvSplitLoop1.emplace_back( ptOpenSt) ;
cvSplitLoop1.emplace_back( ptOpenEn) ;
if ( nOpenLine == int( cvOpenChain[nLastOpenLoopN].size()) - 1) {
Vector3d vtLast = ptSegSt - ptSegEn ;
vtLast.Normalize() ;
bFirstInside = vtLast * cvOpenChain[nLastOpenLoopN][nOpenLine].vtOuter < 0. ;
}
}
// Dall'inizio del loop aperto fino alla fine del segmento corrente
ptSegSt = ptOpenLoopStP ;
ptSegEn = cvBoundClosedLoopVec[nLoop][nLine+1] ;
cvSplitLoop1.emplace_back( ptSegSt) ;
cvSplitLoop1.emplace_back( ptSegEn) ;
bFirstSt = false ;
}
}
}
// Creo secondo loop
if ( bFirstSt) {
// Tratto segmento ove cadono gli estremi del loop aperto
cvSplitLoop2.emplace_back( ptOpenLoopStP) ;
cvSplitLoop2.emplace_back( ptOpenLoopEnP) ;
// Loop aperto
for ( int nOpenLine = int( cvOpenChain[nLastOpenLoopN].size()) - 1 ; nOpenLine >= 0 ; -- nOpenLine) {
Point3d ptOpenSt = cvOpenChain[nLastOpenLoopN][nOpenLine].ptEn ;
Point3d ptOpenEn = cvOpenChain[nLastOpenLoopN][nOpenLine].ptSt ;
cvSplitLoop2.emplace_back( ptOpenSt) ;
cvSplitLoop2.emplace_back( ptOpenEn) ;
}
}
else {
// Tratto segmento ove cadono gli estremi del loop aperto
cvSplitLoop2.emplace_back( ptOpenLoopEnP) ;
cvSplitLoop2.emplace_back( ptOpenLoopStP) ;
// Loop aperto
for ( int nOpenLine = 0 ; nOpenLine < int( cvOpenChain[nLastOpenLoopN].size()) ; ++ nOpenLine) {
Point3d ptOpenSt = cvOpenChain[nLastOpenLoopN][nOpenLine].ptSt ;
Point3d ptOpenEn = cvOpenChain[nLastOpenLoopN][nOpenLine].ptEn ;
cvSplitLoop2.emplace_back( ptOpenSt) ;
cvSplitLoop2.emplace_back( ptOpenEn) ;
}
}
// 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];
}
cvBoundClosedLoopVec[nLoop] = cvSplitLoop1 ;
cvBoundClosedLoopVec[nLoop + 1] = cvSplitLoop2;
vbInOut[nLoop] = bFirstInside;
vbInOut[nLoop + 1] = !bFirstInside;
++ nLoop ;
}
// Estremi dell'aperto su due diversi segmenti del chiuso
else {
bool bFirstInside ;
bool bFirstSt ;
PNTVECTOR cvSplitLoop1, cvSplitLoop2 ;
for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) - 1 ; nLine += 2) {
// Segmento su cui non incide nessun estremo del loop aperto
if ( nLine != nCvSt && nLine != nCvEn) {
cvSplitLoop1.emplace_back( cvBoundClosedLoopVec[nLoop][nLine]) ;
cvSplitLoop1.emplace_back( cvBoundClosedLoopVec[nLoop][nLine + 1]) ;
}
// Segmento su cui incide l'estremo iniziale del loop aperto
else if ( nLine == nCvSt) {
// Dall'inizio del segmento corrente fino all'inizio del loop aperto
Point3d ptSegSt = cvBoundClosedLoopVec[nLoop][nLine] ;
Point3d ptSegEn = ptOpenLoopStP ;
cvSplitLoop1.emplace_back( ptSegSt) ;
cvSplitLoop1.emplace_back( ptSegEn) ;
// Loop aperto
for ( int nOpenLine = 0 ; nOpenLine < int( cvOpenChain[nLastOpenLoopN].size()) ; ++ nOpenLine) {
// Valuto se cvSplitLoop1 è interno o esterno
Point3d ptOpenSt = cvOpenChain[nLastOpenLoopN][nOpenLine].ptSt ;
Point3d ptOpenEn = cvOpenChain[nLastOpenLoopN][nOpenLine].ptEn ;
cvSplitLoop1.emplace_back( ptOpenSt) ;
cvSplitLoop1.emplace_back( ptOpenEn) ;
if ( nOpenLine == 0) {
Vector3d vtLast = ptSegSt - ptOpenLoopStP ;
if ( vtLast.Normalize()) {
bFirstInside = vtLast * cvOpenChain[nLastOpenLoopN][nOpenLine].vtOuter < 0. ;
}
else {
vtLast = cvBoundClosedLoopVec[nLoop][nLine + 1] - ptOpenLoopStP ;
vtLast.Normalize() ;
bFirstInside = vtLast * cvOpenChain[nLastOpenLoopN][nOpenLine].vtOuter > 0. ;
}
}
}
// Dalla fine del loop aperto fino alla fine del segmento ove arriva il loop aperto
nLine = nCvEn ;
ptSegEn = cvBoundClosedLoopVec[nLoop][nLine+1] ;
cvSplitLoop1.emplace_back( ptOpenLoopEnP) ;
cvSplitLoop1.emplace_back( ptSegEn) ;
bFirstSt = true ;
}
// Segmento su cui incide l'estremo finale del loop aperto
else {
// Dall'inizio del segmento corrente fino alla fine del loop aperto
Point3d ptSegSt = cvBoundClosedLoopVec[nLoop][nLine] ;
cvSplitLoop1.emplace_back( ptSegSt) ;
cvSplitLoop1.emplace_back( ptOpenLoopEnP) ;
// Loop aperto
for ( int nOpenLine = int( cvOpenChain[nLastOpenLoopN].size()) - 1 ; nOpenLine >= 0 ; -- nOpenLine) {
Point3d ptOpenSt = cvOpenChain[nLastOpenLoopN][nOpenLine].ptEn ;
Point3d ptOpenEn = cvOpenChain[nLastOpenLoopN][nOpenLine].ptSt ;
cvSplitLoop1.emplace_back( ptOpenSt) ;
cvSplitLoop1.emplace_back( ptOpenEn) ;
if ( nOpenLine == int( cvOpenChain[nLastOpenLoopN].size()) - 1) {
Vector3d vtLast = ptSegSt - ptOpenLoopEnP ;
if ( vtLast.Normalize()) {
bFirstInside = vtLast * cvOpenChain[nLastOpenLoopN][nOpenLine].vtOuter < 0. ;
}
else {
bFirstInside = vtLast * cvOpenChain[nLastOpenLoopN][nOpenLine].vtOuter > 0. ;
}
}
}
// Dalla fine del loop aperto fino alla fine del segmento ove arriva il loop aperto
nLine = nCvSt ;
Point3d ptSegEn = cvBoundClosedLoopVec[nLoop][nLine + 1] ;
cvSplitLoop1.emplace_back( ptOpenLoopStP) ;
cvSplitLoop1.emplace_back( ptSegEn) ;
bFirstSt = false;
}
}
// Creo secondo loop
if ( bFirstSt) {
// Dall'estremo inizinale del loop aperto alla fine del segmento su cui giace
Point3d ptSegSt, ptSegEn ;
ptSegSt = ptOpenLoopStP ;
ptSegEn = cvBoundClosedLoopVec[nLoop][nCvSt+1] ;
cvSplitLoop2.emplace_back( ptSegSt) ;
cvSplitLoop2.emplace_back( ptSegEn) ;
// Loop chiuso fino a segmento ove cade l'estremo finale dell'aperto
for (int nLine = (nCvSt + 2) % int(cvBoundClosedLoopVec[nLoop].size()); nLine != nCvEn; nLine += 2) {
ptSegSt = cvBoundClosedLoopVec[nLoop][nLine % int(cvBoundClosedLoopVec[nLoop].size())];
ptSegEn = cvBoundClosedLoopVec[nLoop][(nLine + 1) % int(cvBoundClosedLoopVec[nLoop].size())];
cvSplitLoop2.emplace_back(ptSegSt);
cvSplitLoop2.emplace_back(ptSegEn);
}
// Dall'inizio del segmento del loop chiuso ove cade l'estremo finale del loop aperto
// a quest'ultimo
ptSegSt = cvBoundClosedLoopVec[nLoop][nCvEn] ;
ptSegEn = ptOpenLoopEnP ;
cvSplitLoop2.emplace_back( ptSegSt) ;
cvSplitLoop2.emplace_back( ptSegEn) ;
// Loop aperto
for ( int nOpenLine = int( cvOpenChain[nLastOpenLoopN].size()) - 1 ; nOpenLine >= 0 ; -- nOpenLine) {
Point3d ptOpenSt = cvOpenChain[nLastOpenLoopN][nOpenLine].ptEn ;
Point3d ptOpenEn = cvOpenChain[nLastOpenLoopN][nOpenLine].ptSt ;
cvSplitLoop2.emplace_back( ptOpenSt) ;
cvSplitLoop2.emplace_back( ptOpenEn) ;
}
}
else {
// Dall'estremo finale del loop aperto alla fine del segmento su cui giace
Point3d ptSegSt = ptOpenLoopEnP ;
Point3d ptSegEn = cvBoundClosedLoopVec[nLoop][nCvEn+1] ;
cvSplitLoop2.emplace_back( ptSegSt) ;
cvSplitLoop2.emplace_back( ptSegEn) ;
// Loop chiuso fino al segmento ove cade l'inizio del loop aperto
for (int nLine = (nCvEn + 2) % int(cvBoundClosedLoopVec[nLoop].size()); nLine != nCvSt; nLine += 2) {
ptSegSt = cvBoundClosedLoopVec[nLoop][nLine % int(cvBoundClosedLoopVec[nLoop].size())];
ptSegEn = cvBoundClosedLoopVec[nLoop][(nLine + 1) % int(cvBoundClosedLoopVec[nLoop].size())];
cvSplitLoop2.emplace_back(ptSegSt);
cvSplitLoop2.emplace_back(ptSegEn);
}
// Dall'inizio del segmento del loop chiuso ove cade l'estremo iniziale del loop aperto
// a quest'ultimo
ptSegSt = cvBoundClosedLoopVec[nLoop][nCvSt] ;
ptSegEn = ptOpenLoopStP ;
cvSplitLoop2.emplace_back( ptSegSt) ;
cvSplitLoop2.emplace_back( ptSegEn) ;
// Loop aperto
for ( int nOpenLoop = 0 ; nOpenLoop < int( cvOpenChain[nLastOpenLoopN].size()) ; ++ nOpenLoop) {
Point3d ptOpenSt = cvOpenChain[nLastOpenLoopN][nOpenLoop].ptSt ;
Point3d ptOpenEn = cvOpenChain[nLastOpenLoopN][nOpenLoop].ptEn ;
cvSplitLoop2.emplace_back( ptOpenSt) ;
cvSplitLoop2.emplace_back( ptOpenEn) ;
}
}
// 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] ;
}
cvBoundClosedLoopVec[nLoop] = cvSplitLoop1 ;
cvBoundClosedLoopVec[nLoop + 1] = cvSplitLoop2 ;
vbInOut[nLoop] = bFirstInside ;
vbInOut[nLoop + 1] = ! bFirstInside ;
++ 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()) - 1 && nCvSecond == -1 ; nLine += 2) {
// Estremi del segmento corrente del loop chiuso corrente
Point3d ptSegSt = cvBoundClosedLoopVec[nLoop][nLine] ;
Point3d ptSegEn = cvBoundClosedLoopVec[nLoop][nLine + 1] ;
// 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 += 2) {
ptM12 += cvBoundClosedLoopVec[nLoop][i] ;
++ nCount ;
}
ptM12 /= nCount ;
// verifico se questo punto è dalla parte valida o no
bool bC12 = ( ( ptM12 - ptProva) * vtVecProva < 0) ;
// numero totale di punti
int nPntTot = int( cvBoundClosedLoopVec[nLoop].size()) ;
// elimino i punti dalla parte non valida
if ( bC12) {
// assegno i nuovi valori
cvBoundClosedLoopVec[nLoop][nCvFirst] = ptProva ;
cvBoundClosedLoopVec[nLoop][nCvSecond+1] = ptProva ;
// 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()) ;
}
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) ;
}
vbInOut[nLoop] = true ;
// PNTVECTOR cvSplitLoop;
// for (int nLine = 0; nLine < nCvFirst; nLine += 2) {
// cvSplitLoop.emplace_back(cvBoundClosedLoopVec[nLoop][nLine]);
// cvSplitLoop.emplace_back(cvBoundClosedLoopVec[nLoop][nLine + 1]);
// }
// cvSplitLoop.emplace_back(cvBoundClosedLoopVec[nLoop][nCvFirst]);
// cvSplitLoop.emplace_back(ptProva);
// cvSplitLoop.emplace_back(ptProva);
// cvSplitLoop.emplace_back(cvBoundClosedLoopVec[nLoop][nCvSecond + 1]);
// for (int nLine = nCvSecond + 2; nLine < int(cvBoundClosedLoopVec[nLoop].size()) - 1; nLine += 2) {
// cvSplitLoop.emplace_back(cvBoundClosedLoopVec[nLoop][nLine]);
// cvSplitLoop.emplace_back(cvBoundClosedLoopVec[nLoop][nLine + 1]);
// }
// cvBoundClosedLoopVec[nLoop] = cvSplitLoop;
// if ((cvBoundClosedLoopVec[nLoop][nCvFirst] - ptProva) * vtVecProva < 0.)
// vbInOut[nLoop] = true;
// else
// vbInOut[nLoop] = false;
}
}
}
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()) - 1 ; nLine += 2) {
vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][nLine]) ;
vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][nLine + 1]) ;
}
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 ;
}