Files
EgtGeomKernel/SurfTriMeshBooleans.cpp
T
Dario Sassi c93adf402b EgtGeomKernel 2.1e5 :
- aggiunta funzione SurfTriMesh::GeneralizedCut per taglio TriMesh con curva che rappresenta sezione di cilindro infinito.
2019-05-28 15:31:16 +00:00

912 lines
47 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 <algorithm>
//----------------------------------------------------------------------------
struct TriaInOut {
Triangle3d trTria ;
bool bTriaInside ;
} ;
//----------------------------------------------------------------------------
bool
FindRectangleTriangleIntersectionSegment(const Point3d ptP1, const Point3d ptP2, const Point3d ptP3, const Point3d ptP4,
const Triangle3d& trTria, Point3d& ptStSeg, Point3d& ptEnSeg)
{
// Definisco i due triangoli formanti il rettangolo
Triangle3d trTria1, trTria2 ;
trTria1.Set( ptP1, ptP2, ptP4) ;
trTria2.Set( ptP2, ptP3, ptP4) ;
trTria1.Validate() ;
trTria2.Validate() ;
Vector3d vtSeg = ptP2 - ptP1 ;
vtSeg.Normalize() ;
// Interseco il triangolo corrente col primo dei due triangoli del rettangolo
Point3d ptIntA1, ptIntB1 ;
TRIA3DVECTOR vTria1 ;
int nIntType1 = IntersTriaTria( trTria1, trTria, ptIntA1, ptIntB1, vTria1) ;
if ( nIntType1 == ITTT_YES) {
if ( ( ptIntB1 - ptIntA1) * vtSeg < 0.)
std::swap( ptIntA1, ptIntB1) ;
ptStSeg = ptIntA1 ;
ptEnSeg = ptIntB1 ;
}
// Interseco il triangolo corrente con il secondo dei due triangoli del rettangolo
Point3d ptIntA2, ptIntB2 ;
TRIA3DVECTOR vTria2 ;
int nIntType2 = IntersTriaTria( trTria2, trTria, ptIntA2, ptIntB2, vTria2) ;
if ( nIntType2 == ITTT_YES) {
if ( ( ptIntB2 - ptIntA2) * vtSeg < 0.)
std::swap( ptIntA2, ptIntB2) ;
ptEnSeg = ptIntB2 ;
if ( ! ( nIntType1 == ITTT_YES))
ptStSeg = ptIntA2 ;
}
return ( nIntType1 == ITTT_YES || nIntType2 == ITTT_YES) ;
}
//----------------------------------------------------------------------------
bool
FindRectangleTriangleIntersectionSegment2( const Point3d ptP1, const Point3d ptP2, const Point3d ptP3, const Point3d ptP4,
const Triangle3d& trTria, Point3d& ptStSeg, Point3d& ptEnSeg)
{
// Definisco i due triangoli formanti il rettangolo
Triangle3d trTria1, trTria2;
trTria1.Set(ptP1, ptP2, ptP4);
trTria2.Set(ptP2, ptP3, ptP4);
trTria1.Validate();
trTria2.Validate();
Vector3d vtSeg = ptP3 - ptP1;
vtSeg.Normalize();
// Interseco il triangolo corrente col primo dei due triangoli del rettangolo
Point3d ptIntA1, ptIntB1;
TRIA3DVECTOR vTria1;
int nIntType1 = IntersTriaTria(trTria1, trTria, ptIntA1, ptIntB1, vTria1);
if ( nIntType1 == ITTT_YES) {
if ((ptIntB1 - ptIntA1) * vtSeg < 0.)
std::swap(ptIntA1, ptIntB1);
ptStSeg = ptIntA1;
ptEnSeg = ptIntB1;
}
// Interseco il triangolo corrente con il secondo dei due triangoli del rettangolo
Point3d ptIntA2, ptIntB2;
TRIA3DVECTOR vTria2;
int nIntType2 = IntersTriaTria(trTria2, trTria, ptIntA2, ptIntB2, vTria2);
if ( nIntType2 == ITTT_YES) {
if ((ptIntB2 - ptIntA2) * vtSeg < 0.)
std::swap(ptIntA2, ptIntB2);
ptEnSeg = ptIntB2;
if ( !( nIntType1 == ITTT_YES))
ptStSeg = ptIntA2;
}
return ( nIntType1 == ITTT_YES || nIntType2 == ITTT_YES);
}
//----------------------------------------------------------------------------
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)) || ( ! cvCurve.IsClosed()) || vtExtr.IsSmall())
return false ;
// Approssimo la curva con segmenti
PolyLine plLine ;
cvCurve.ApproxWithLines( LIN_TOL_FINE, ANG_TOL_STD_DEG, ICurve::APL_STD, plLine) ;
// Appiattisco la polilinea nel piano perpendicolare all'estrusione
Frame3d frCurve ;
Point3d ptStart ; cvCurve.GetStartPoint( ptStart) ;
frCurve.Set( ptStart, vtExtr) ;
plLine.ToLoc( frCurve) ;
plLine.Flatten() ;
double dArea ;
plLine.GetAreaXY( dArea) ;
BBox3d b3Crv ;
plLine.GetLocalBBox( b3Crv) ;
plLine.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 ;
GetTriangle( nT, trTria) ;
// Box del triangolo nel riferimento locale della curva
BBox3d b3Tria ;
trTria.GetLocalBBox( b3Tria) ;
b3Tria.ToLoc( frCurve) ;
// Se il box del triangolo non interseca quello della curva
if ( ! b3Crv.OverlapsXY( b3Tria)) {
if ( bCCW) {
RemoveTriangle( nT) ;
bModif = true ;
}
continue ;
}
// Determino il numero di vertici che cadono nella curva
int nVertInside = 0 ;
// Ciclo sui vertici del triangolo
for ( int nV = 0 ; nV < 3 ; ++ nV) {
// Vertice del triangolo e sua proiezione sul piano della curva
Point3d ptVert ;
if ( ! GetVertex( m_vTria[nT].nIdVert[nV], ptVert))
continue ;
double dDistVertPlane = ( ptVert - ptStart) * vtExtr ;
Point3d ptVertOnPlane = ptVert - dDistVertPlane * vtExtr ;
// Ciclo sui segmenti della curva, per determinare se la proiezione sulla curva di almeno un vertice
// del triangolo è all'interno del loop oppure un punto della curva, spostandosi lungo una
// retta parallela al versore di estrusione, interseca il triangolo.
double dSqDistVertCurve = DBL_MAX ;
Point3d ptStMin, ptEnMin ;
Point3d ptSt, ptEn ;
bool bContinue = plLine.GetFirstLine( ptSt, ptEn) ;
while ( bContinue) {
CurveLine cvLine ;
cvLine.Set( ptSt, ptEn) ;
// Calcolo della distanza del vertice proiettato sul piano della curva
// dal segmento corrente
DistPointLine dCurDistCalc( ptVertOnPlane, cvLine) ;
double dCurSqDist ;
// Se tale distanza è minore della minima distanza attuale, la aggiorno insieme con gli estremi
// del segmento a distanza minima
if ( dCurDistCalc.GetSqDist( dCurSqDist) && dCurSqDist < dSqDistVertCurve) {
dSqDistVertCurve = dCurSqDist ;
ptStMin = ptSt ;
ptEnMin = ptEn ;
}
bContinue = plLine.GetNextLine( ptSt, ptEn) ;
}
// Direzione del segmento a minima distanza dal vertice corrente proiettato sul piano della curva
Vector3d vtTan = ptEnMin - ptStMin ;
vtTan.Normalize() ;
// Se punto proiettato nella curva aumentiamo il numero di punti interni
if ( ( ptVertOnPlane - ptStMin) * ( vtTan ^ vtExtr) < EPS_SMALL)
++ nVertInside ;
}
// Casi in cui l'orientamento della curva stabilisce la parti interne ed esterne del triangolo
if ( abs( trTria.GetN() * vtExtr) > EPS_ZERO) {
// Vettore di segmenti
std::vector<CurveLine> vLine ;
// Ciclo sui segmenti
Point3d ptSt, ptEn ;
bool bContinue = plLine.GetFirstLine( ptSt, ptEn) ;
while ( bContinue) {
Point3d ptSegSt, ptSegEn ;
// C'è interferenza fra il rettangolo, ottenuto dall'estrusione del segmento corrente, e il triangolo
if ( FindRectangleTriangleIntersectionSegment( ptSt + vtMin, ptEn + vtMin, ptEn + vtMax, ptSt + vtMax,
trTria, ptSegSt, ptSegEn)) {
// Costruisco il tratto di curva
CurveLine cvLine ;
if ( cvLine.Set( ptSegSt, ptSegEn))
vLine.emplace_back( cvLine) ;
}
bContinue = plLine.GetNextLine( ptSt, ptEn) ;
}
// Creo i loop
ChainCurves LoopCreator ;
LoopCreator.Init( false, EPS_SMALL, int( vLine.size())) ;
// Carico le curve per concatenarle
for ( int nCv = 0 ; nCv < int( vLine.size()) ; ++ nCv) {
Point3d ptSt = vLine[nCv].GetStart() ;
Point3d ptEn = vLine[nCv].GetEnd() ;
Vector3d vtDir; vLine[nCv].GetStartDir( vtDir) ;
LoopCreator.AddCurve( nCv + 1, ptSt, vtDir, ptEn, vtDir) ;
}
// Recupero i concatenamenti
INTVECTOR vIds ;
Point3d ptNearStart ;
std::vector<CurveComposite> cvLoopVec ;
while ( LoopCreator.GetChainFromNear( ptNearStart, false, vIds)) {
CurveComposite cvLoop ;
for ( auto i : vIds) {
// Aggiungo la linea alla curva composta.
if ( ! cvLoop.AddCurve( vLine[i - 1], true, 10 * EPS_SMALL))
return false ;
}
cvLoop.MergeCurves( 10 * EPS_SMALL, ANG_TOL_STD_DEG) ;
cvLoopVec.emplace_back( cvLoop) ;
}
// Fra i loop trovati separo gli aperti dai chiusi
std::vector<CurveComposite> cvInnerClosedLoopVec ;
std::vector<CurveComposite> cvOpenLoopVec ;
for ( int nL = 0 ; nL < int( cvLoopVec.size()) ; ++ nL) {
if ( cvLoopVec[nL].IsClosed())
cvInnerClosedLoopVec.emplace_back( cvLoopVec[nL]) ;
else
cvOpenLoopVec.emplace_back( cvLoopVec[nL]) ;
}
// Se contemporaneamente c'è almeno un loop chiuso e almeno uno aperto,
// oppure c'è più di un loop chiuso, vi è un errore.
if ( ( cvInnerClosedLoopVec.size() > 0 && cvOpenLoopVec.size() > 0.) ||
cvInnerClosedLoopVec.size() > 1)
return false ;
// Se c'è un loop chiuso
if ( cvInnerClosedLoopVec.size() == 1) {
// Passo da curva composita a PolyLine
PolyLine plInnerLoop ;
const ICurve* pCv = cvInnerClosedLoopVec[0].GetFirstCurve() ;
while ( pCv != nullptr) {
// Estremi del segmento corrente del loop chiuso corrente
Point3d ptSegSt, ptSegEn ;
pCv->GetStartPoint( ptSegSt) ;
pCv->GetEndPoint( ptSegEn) ;
plInnerLoop.AddUPoint( 0., ptSegSt) ;
plInnerLoop.AddUPoint( 0., ptSegEn) ;
pCv = cvInnerClosedLoopVec[0].GetNextCurve() ;
}
// Se necessario inverto il loop trovato
if ( trTria.GetN() * vtExtr < - EPS_ZERO)
plInnerLoop.Invert() ;
// Tre vertici dentro la curva
if ( nVertInside == 3) {
// Accedo agli indici del triangolo
int nTriaVertId[3] ;
GetTriangle( nT, nTriaVertId) ;
PolyLine plExternalLoop ;
Point3d ptTriaVert0, ptTriaVert1, ptTriaVert2 ;
GetVertex( nTriaVertId[0], ptTriaVert0) ;
GetVertex( nTriaVertId[1], ptTriaVert1) ;
GetVertex( nTriaVertId[2], ptTriaVert2) ;
// Rimuovo il triangolo corrente
RemoveTriangle( nT) ;
plExternalLoop.AddUPoint( 0., ptTriaVert0) ;
plExternalLoop.AddUPoint( 0., ptTriaVert1) ;
plExternalLoop.AddUPoint( 0., ptTriaVert2) ;
plExternalLoop.AddUPoint( 0., ptTriaVert0) ;
// Poligonalizzo il loop
Triangulate CreateTriangulation ;
PNTVECTOR vPt ;
INTVECTOR vTr ;
POLYLINEVECTOR vPL ;
vPL.emplace_back( plExternalLoop) ;
vPL.emplace_back( plInnerLoop) ;
CreateTriangulation.Make( vPL, vPt, vTr) ;
// Aggiungo i 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 dentro (Con un loop chiuso o ci sono tre vertici dentro alla curva o nessuno)
else {
// Rimuovo il triangolo corrente
RemoveTriangle( nT) ;
// Poligonalizzo il loop
Triangulate CreateTriangulation ;
PNTVECTOR vPt ;
INTVECTOR vTr ;
CreateTriangulation.Make( plInnerLoop, vPt, vTr) ;
// Aggiungo i 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 ( cvOpenLoopVec.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.
std::vector<CurveComposite> cvBoundClosedLoopVec ;
CurveComposite cvFirstLoop ;
CurveLine cvEdge ;
cvEdge.Set( trTria.GetP( 0), trTria.GetP( 1)) ;
cvFirstLoop.AddCurve( cvEdge, true, 10 * EPS_SMALL) ;
cvEdge.Set( trTria.GetP( 1), trTria.GetP( 2)) ;
cvFirstLoop.AddCurve( cvEdge, true, 10 * EPS_SMALL) ;
cvEdge.Set( trTria.GetP( 2), trTria.GetP( 0)) ;
cvFirstLoop.AddCurve( cvEdge, true, 10 * EPS_SMALL) ;
cvBoundClosedLoopVec.emplace_back( cvFirstLoop) ;
std::vector<bool> vbInOut ;
vbInOut.push_back( true) ;
// Divido il loop di partenza in sotto-loop
while ( cvOpenLoopVec.size() > 0) {
int nLastOpenLoopN = int( cvOpenLoopVec.size()) - 1 ;
for ( int nL = 0 ; nL < int( cvBoundClosedLoopVec.size()) ; ++ nL) {
// Estremi del loop aperto
Point3d ptOpenLoopStP, ptOpenLoopEnP ;
cvOpenLoopVec[nLastOpenLoopN].GetStartPoint( ptOpenLoopStP) ;
cvOpenLoopVec[nLastOpenLoopN].GetEndPoint( ptOpenLoopEnP) ;
// Cerco se esistono dei tratti del loop chiuso corrente che sono
// toccati dagli estremi del loop aperto corrente
const ICurve* pCvSt = nullptr ;
const ICurve* pCvEn = nullptr ;
const ICurve* pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ;
while ( pCv != nullptr && ( pCvSt == nullptr || pCvEn == nullptr)) {
// Estremi del segmento corrente del loop chiuso corrente
Point3d ptSegSt, ptSegEn ;
pCv->GetStartPoint( ptSegSt) ;
pCv->GetEndPoint( ptSegEn) ;
// 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 ( SqDist( ptOpenLoopStP, ptSegSt) < EPS_SMALL * EPS_SMALL ||
SqDist( ptOpenLoopStP, ptSegEn) < EPS_SMALL * EPS_SMALL)
dSqDistSt = 1. ;
if ( dSqDistSt < EPS_SMALL * EPS_SMALL)
pCvSt = pCv ;
double dSqDistEn ;
dEnDistCalc.GetSqDist( dSqDistEn) ;
if ( SqDist( ptOpenLoopEnP, ptSegSt) < EPS_SMALL * EPS_SMALL ||
SqDist( ptOpenLoopEnP, ptSegEn) < EPS_SMALL * EPS_SMALL)
dSqDistEn = 1. ;
if ( dSqDistEn < EPS_SMALL * EPS_SMALL)
pCvEn = pCv ;
pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ;
}
// Se entrambi gli estremi del loop aperto sono su un segmento del loop chiuso devo dividere il loop in due
if ( pCvSt != nullptr && pCvEn != nullptr) {
// Entrambi gli estremi del loop aperto sono su uno stesso segmento del loop chiuso
if ( pCvSt == pCvEn) {
bool bFirstInside ;
bool bFirstSt ;
CurveComposite cvSplitLoop1, cvSplitLoop2 ;
// Creo primo loop
pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ;
while ( pCv != nullptr) {
// Segmenti loop chiuso
if ( pCv != pCvSt && pCv != pCvEn) {
Point3d ptSegSt, ptSegEn ;
pCv->GetStartPoint( ptSegSt) ;
pCv->GetEndPoint( ptSegEn) ;
CurveLine cvSeg ;
cvSeg.Set( ptSegSt, ptSegEn) ;
cvSplitLoop1.AddCurve( cvSeg) ;
}
// Dal chiuso all'aperto
else if ( pCv == pCvSt) {
// Distanze degli estremi del loop aperto dal punto iniziale del segmento corrente
Point3d ptSegSt, ptSegEn ;
pCv->GetStartPoint( ptSegSt) ;
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 ;
CurveLine cvSeg ;
cvSeg.Set( ptSegSt, ptSegEn) ;
cvSplitLoop1.AddCurve( cvSeg) ;
// Loop aperto
const ICurve* pOpenStart = cvOpenLoopVec[nLastOpenLoopN].GetFirstCurve() ;
const ICurve* pOpen = pOpenStart ;
while ( pOpen != nullptr) {
Point3d ptOpenSt, ptOpenEn ;
pOpen->GetStartPoint( ptOpenSt) ;
pOpen->GetEndPoint( ptOpenEn) ;
CurveLine cvOpenSeg ;
cvOpenSeg.Set( ptOpenSt, ptOpenEn) ;
cvSplitLoop1.AddCurve( cvOpenSeg) ;
if ( pOpen == pOpenStart) {
Vector3d vtLast = ptSegSt - ptSegEn ;
vtLast.Normalize() ;
Vector3d vtFirst = ptOpenEn - ptOpenSt ;
vtFirst.Normalize() ;
bFirstInside = vtLast * ( vtFirst ^ vtExtr) < 0. ;
}
pOpen = cvOpenLoopVec[nLastOpenLoopN].GetNextCurve() ;
}
// Dalla fine del loop aperto alla fine del segmento corrente
ptSegSt = ptOpenLoopEnP ;
pCv->GetEndPoint( ptSegEn) ;
cvSeg ;
cvSeg.Set( ptSegSt, ptSegEn) ;
cvSplitLoop1.AddCurve( cvSeg) ;
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 ;
CurveLine cvSeg ;
cvSeg.Set( ptSegSt, ptSegEn) ;
cvSplitLoop1.AddCurve( cvSeg) ;
// Loop aperto
const ICurve* pOpenLast = cvOpenLoopVec[nLastOpenLoopN].GetLastCurve() ;
const ICurve* pOpen = pOpenLast ;
while ( pOpen != nullptr) {
Point3d ptOpenSt, ptOpenEn ;
pOpen->GetStartPoint( ptOpenSt) ;
pOpen->GetEndPoint( ptOpenEn) ;
CurveLine cvOpenSeg ;
cvOpenSeg.Set( ptOpenEn, ptOpenSt) ;
cvSplitLoop1.AddCurve( cvOpenSeg) ;
if ( pOpen == pOpenLast) {
Vector3d vtLast = ptSegSt - ptSegEn ;
vtLast.Normalize() ;
Vector3d vtFirst = ptOpenEn - ptOpenSt ;
vtFirst.Normalize() ;
bFirstInside = vtLast * ( vtFirst ^ vtExtr) < 0. ;
}
pOpen = cvOpenLoopVec[nLastOpenLoopN].GetPrevCurve() ;
}
// Dall'inizio del loop aperto fino alla fine del segmento corrente
ptSegSt = ptOpenLoopStP ;
pCv->GetEndPoint( ptSegEn) ;
cvSeg ;
cvSeg.Set( ptSegSt, ptSegEn) ;
cvSplitLoop1.AddCurve( cvSeg) ;
bFirstSt = false ;
}
}
pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ;
}
// Creo secondo loop
if ( bFirstSt) {
// Tratto segmento ove cadono gli estremi del loop aperto
CurveLine cvSeg ;
cvSeg.Set( ptOpenLoopStP, ptOpenLoopEnP) ;
cvSplitLoop2.AddCurve( cvSeg) ;
// Loop aperto
const ICurve* pOpen = cvOpenLoopVec[nLastOpenLoopN].GetLastCurve();
while (pOpen != nullptr) {
Point3d ptOpenSt, ptOpenEn;
pOpen->GetStartPoint(ptOpenSt);
pOpen->GetEndPoint(ptOpenEn);
CurveLine cvOpenSeg;
cvOpenSeg.Set(ptOpenEn, ptOpenSt);
cvSplitLoop2.AddCurve(cvOpenSeg);
pOpen = cvOpenLoopVec[nLastOpenLoopN].GetPrevCurve();
}
}
else {
// Tratto segmento ove cadono gli estremi del loop aperto
CurveLine cvSeg ;
cvSeg.Set( ptOpenLoopEnP, ptOpenLoopStP) ;
cvSplitLoop2.AddCurve( cvSeg) ;
// Loop aperto
const ICurve* pOpen = cvOpenLoopVec[nLastOpenLoopN].GetFirstCurve() ;
while ( pOpen != nullptr) {
Point3d ptOpenSt, ptOpenEn ;
pOpen->GetStartPoint( ptOpenSt) ;
pOpen->GetEndPoint( ptOpenEn) ;
CurveLine cvOpenSeg ;
cvOpenSeg.Set( ptOpenSt, ptOpenEn) ;
cvSplitLoop2.AddCurve( cvOpenSeg);
pOpen = cvOpenLoopVec[nLastOpenLoopN].GetNextCurve() ;
}
}
// Aggiungo i nuovi loop nel vettore
cvBoundClosedLoopVec[nL] = cvSplitLoop1 ;
cvBoundClosedLoopVec.emplace_back( cvSplitLoop2) ;
vbInOut[nL] = bFirstInside ;
vbInOut.push_back( ! bFirstInside) ;
}
// Estremi dell'aperto su due diversi segmenti del chiuso
else {
bool bFirstInside ;
bool bFirstSt ;
CurveComposite cvSplitLoop1, cvSplitLoop2 ;
// Creo primo loop
pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ;
while ( pCv != nullptr) {
// Segmento su cui non incide nessun estremo del loop aperto
if ( pCv != pCvSt && pCv != pCvEn) {
Point3d ptSegSt, ptSegEn ;
pCv->GetStartPoint( ptSegSt) ;
pCv->GetEndPoint( ptSegEn) ;
CurveLine cvSeg ;
cvSeg.Set( ptSegSt, ptSegEn) ;
cvSplitLoop1.AddCurve( cvSeg) ;
}
// Segmento su cui incide l'estremo iniziale del loop aperto
else if ( pCv == pCvSt) {
// Dall'inizio del segmento corrente fino all'inizio del loop aperto
Point3d ptSegSt ;
pCv->GetStartPoint( ptSegSt) ;
CurveLine cvSeg ;
cvSeg.Set( ptSegSt, ptOpenLoopStP) ;
cvSplitLoop1.AddCurve( cvSeg) ;
// Loop aperto
const ICurve* pOpenFirst = cvOpenLoopVec[nLastOpenLoopN].GetFirstCurve();
const ICurve* pOpen = pOpenFirst ;
while ( pOpen != nullptr) {
// Valuto se cvSplitLoop1 è interno o esterno
Point3d ptOpenSt, ptOpenEn ;
pOpen->GetStartPoint( ptOpenSt) ;
pOpen->GetEndPoint( ptOpenEn) ;
CurveLine cvOpenSeg ;
cvOpenSeg.Set( ptOpenSt, ptOpenEn) ;
cvSplitLoop1.AddCurve( cvOpenSeg) ;
if ( pOpen == pOpenFirst) {
Vector3d vtLast = ptSegSt - ptOpenLoopStP ;
vtLast.Normalize() ;
Vector3d vtFirst = ptOpenEn - ptOpenSt ;
vtFirst.Normalize() ;
bFirstInside = vtLast * ( vtFirst ^ vtExtr) < 0. ;
}
pOpen = cvOpenLoopVec[nLastOpenLoopN].GetNextCurve() ;
}
// Dalla fine del loop aperto fino alla fine del segmento ove arriva il loop aperto
while ( pCv != pCvEn)
pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ;
Point3d ptSegEn ;
pCv->GetEndPoint( ptSegEn) ;
cvSeg ;
cvSeg.Set( ptOpenLoopEnP, ptSegEn) ;
cvSplitLoop1.AddCurve( cvSeg) ;
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 ;
pCv->GetStartPoint( ptSegSt) ;
CurveLine cvSeg ;
cvSeg.Set( ptSegSt, ptOpenLoopEnP) ;
cvSplitLoop1.AddCurve( cvSeg) ;
// Loop aperto
const ICurve* pOpenLast = cvOpenLoopVec[nLastOpenLoopN].GetLastCurve() ;
const ICurve* pOpen = pOpenLast ;
while ( pOpen != nullptr) {
Point3d ptOpenSt , ptOpenEn ;
pOpen->GetStartPoint( ptOpenSt) ;
pOpen->GetEndPoint( ptOpenEn) ;
CurveLine cvOpenSeg ;
cvOpenSeg.Set( ptOpenEn, ptOpenSt) ;
cvSplitLoop1.AddCurve( cvOpenSeg) ;
if ( pOpen == pOpenLast) {
Vector3d vtLast = ptSegSt - ptOpenLoopEnP ;
vtLast.Normalize() ;
Vector3d vtFirst = ptOpenEn - ptOpenSt ;
vtFirst.Normalize() ;
bFirstInside = vtLast * ( vtFirst ^ vtExtr) < 0. ;
}
pOpen = cvOpenLoopVec[nLastOpenLoopN].GetPrevCurve() ;
}
// Dalla fine del loop aperto fino alla fine del segmento ove arriva il loop aperto
while ( pCv != pCvSt)
pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ;
Point3d ptSegEn ;
pCv->GetEndPoint( ptSegEn) ;
cvSeg.Set( ptOpenLoopStP, ptSegEn) ;
cvSplitLoop1.AddCurve( cvSeg) ;
bFirstSt = false ;
}
pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ;
}
// Creo secondo loop
if ( bFirstSt) {
// Individuo il segmento ove incide l'estremo iniziale del loop aperto
pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ;
while ( pCv != pCvSt)
pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ;
// Dall'estremo finale del loop aperto alla fine del segmento su cui giace
Point3d ptSegSt, ptSegEn ;
ptSegSt = ptOpenLoopStP ;
pCv->GetEndPoint( ptSegEn) ;
CurveLine cvSeg ;
cvSeg.Set( ptSegSt, ptSegEn) ;
cvSplitLoop2.AddCurve( cvSeg) ;
// Loop chiuso fino a segmento ove cade l'estremo finale dell'aperto
const ICurve* pCvStop = pCvEn ;
pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ;
if ( pCv == nullptr)
pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ;
while ( pCv != pCvStop) {
if ( pCv == nullptr)
pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ;
pCv->GetStartPoint( ptSegSt) ;
pCv->GetEndPoint( ptSegEn) ;
CurveLine cvSeg ;
cvSeg.Set( ptSegSt, ptSegEn) ;
cvSplitLoop2.AddCurve( cvSeg) ;
pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ;
}
// Dall'inizio del segmento del loop chiuso ove cade l'estremo finale del loop aperto
// a quest'ultimo
pCv->GetStartPoint( ptSegSt) ;
ptSegEn = ptOpenLoopEnP ;
cvSeg.Set( ptSegSt, ptOpenLoopEnP) ;
cvSplitLoop2.AddCurve( cvSeg) ;
// Loop aperto
const ICurve* pOpen = cvOpenLoopVec[nLastOpenLoopN].GetLastCurve() ;
while ( pOpen != nullptr) {
Point3d ptOpenSt, ptOpenEn ;
pOpen->GetStartPoint( ptOpenSt) ;
pOpen->GetEndPoint( ptOpenEn) ;
CurveLine cvOpenSeg ;
cvOpenSeg.Set( ptOpenEn, ptOpenSt) ;
cvSplitLoop2.AddCurve( cvOpenSeg) ;
pOpen = cvOpenLoopVec[nLastOpenLoopN].GetPrevCurve() ;
}
}
else {
// Individuo il segmento ove incide l'estremo finale del loop aperto
pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ;
while ( pCv != pCvEn)
pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ;
// Dall'estremo finale del loop aperto alla fine del segmento su cui giace
Point3d ptSegSt, ptSegEn ;
ptSegSt = ptOpenLoopEnP ;
pCv->GetEndPoint( ptSegEn) ;
CurveLine cvSeg ;
cvSeg.Set( ptSegSt, ptSegEn) ;
cvSplitLoop2.AddCurve( cvSeg) ;
// Loop chiuso fino al segmento ove cade l'inizio del loop aperto
const ICurve* pCvStop = pCvSt ;
pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ;
if ( pCv == nullptr)
pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ;
while ( pCv != pCvStop) {
if ( pCv == nullptr)
pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ;
pCv->GetStartPoint( ptSegSt) ;
pCv->GetEndPoint( ptSegEn) ;
CurveLine cvSeg ;
cvSeg.Set( ptSegSt, ptSegEn) ;
cvSplitLoop2.AddCurve( cvSeg) ;
pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ;
}
// Dall'inizio del segmento del loop chiuso ove cade l'estremo iniziale del loop aperto
// a quest'ultimo
pCv->GetStartPoint( ptSegSt) ;
ptSegEn = ptOpenLoopStP ;
cvSeg.Set( ptSegSt, ptOpenLoopStP) ;
cvSplitLoop2.AddCurve( cvSeg) ;
// Loop aperto
const ICurve* pOpen = cvOpenLoopVec[nLastOpenLoopN].GetFirstCurve() ;
while ( pOpen != nullptr) {
Point3d ptOpenSt, ptOpenEn ;
pOpen->GetStartPoint( ptOpenSt);
pOpen->GetEndPoint( ptOpenEn);
CurveLine cvOpenSeg ;
cvOpenSeg.Set( ptOpenSt, ptOpenEn) ;
cvSplitLoop2.AddCurve( cvOpenSeg) ;
pOpen = cvOpenLoopVec[nLastOpenLoopN].GetNextCurve() ;
}
}
// Aggiungo i nuovi loop nel vettore
cvBoundClosedLoopVec[nL] = cvSplitLoop1 ;
cvBoundClosedLoopVec.emplace_back( cvSplitLoop2) ;
vbInOut[nL] = bFirstInside ;
vbInOut.push_back( ! bFirstInside) ;
}
}
}
cvOpenLoopVec.resize( nLastOpenLoopN) ;
}
RemoveTriangle( nT) ;
// Trasformo i loop compositi in loop polyline
std::vector<PolyLine> vplPolyVec ;
vplPolyVec.resize( cvBoundClosedLoopVec.size()) ;
for ( int nL = 0 ; nL < int( vplPolyVec.size()) ; ++ nL) {
const ICurve* pCv = cvBoundClosedLoopVec[nL].GetFirstCurve() ;
while ( pCv != nullptr) {
// Estremi del segmento corrente del loop chiuso corrente
Point3d ptSegSt, ptSegEn ;
pCv->GetStartPoint( ptSegSt) ;
pCv->GetEndPoint( ptSegEn) ;
vplPolyVec[nL].AddUPoint( 0., ptSegSt) ;
vplPolyVec[nL].AddUPoint( 0., ptSegEn) ;
pCv = cvBoundClosedLoopVec[nL].GetNextCurve() ;
}
if ( vbInOut[nL]) {
// Poligonalizzo il loop
Triangulate CreateTriangulation ;
PNTVECTOR vPt ;
INTVECTOR vTr ;
CreateTriangulation.Make( vplPolyVec[nL], vPt, vTr) ;
// Aggiungo i 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) ;
}
// L'orientamento del loop non stabilise i vertici dentro e fuori
else {
std::vector<TriaInOut> vTriaVec ;
TriaInOut trStartTria ;
trStartTria.trTria = trTria ;
trStartTria.bTriaInside = true ;
vTriaVec.emplace_back( trStartTria) ;
vTriaVec.resize( 1) ;
// Ciclo sui segmenti
Point3d ptSt, ptEn ;
bool bContinue = plLine.GetFirstLine( ptSt, ptEn) ;
while ( bContinue) {
for ( int nTr = 0 ; nTr < int( vTriaVec.size()) ; ++ nTr) {
Point3d ptSegSt, ptSegEn ;
// C'è interferenza fra il rettangolo, ottenuto dall'estrusione del segmento corrente, e il triangolo
if ( FindRectangleTriangleIntersectionSegment2( ptSt + vtMin, ptEn + vtMin, ptEn + vtMax, ptSt + vtMax,
vTriaVec[nTr].trTria, ptSegSt, ptSegEn)) {
// Stabilisco su quali lati del triangolo cadono gli estremi del segmento intersezione
int nStEdge = -1 ;
int nEnEdge = -1 ;
for ( int nV = 0 ; nV < 3 ; ++ nV) {
int nW = (nV + 1) % 3 ;
Point3d ptVertV = vTriaVec[nTr].trTria.GetP( nV) ;
Point3d ptVertW = vTriaVec[nTr].trTria.GetP( nW) ;
DistPointLine dStDistCalc( ptSegSt, ptVertV, ptVertW) ;
DistPointLine dEnDistCalc( ptSegEn, ptVertV, ptVertW) ;
double dSqDistSt ;
dStDistCalc.GetSqDist( dSqDistSt) ;
if ( dSqDistSt < EPS_SMALL * EPS_SMALL)
nStEdge = nV ;
double dSqDistEn ;
dEnDistCalc.GetSqDist( dSqDistEn) ;
if ( dSqDistEn < EPS_SMALL * EPS_SMALL)
nEnEdge = nV ;
}
int nMinInd, nMaxInd ;
Point3d ptMin, ptMax ;
if ( nStEdge < nEnEdge) {
nMinInd = nStEdge ;
nMaxInd = nEnEdge ;
ptMin = ptSegSt ;
ptMax = ptSegEn ;
}
else {
nMinInd = nEnEdge ;
nMaxInd = nStEdge ;
ptMin = ptSegEn ;
ptMax = ptSegSt ;
}
TriaInOut trSingleTria ;
PolyLine plInnerLoop ;
bool bLoopInside ;
if ( nMaxInd == ( nMinInd + 1) % 3) {
trSingleTria.trTria.SetP( 0, ptMin) ;
trSingleTria.trTria.SetP( 1, vTriaVec[nTr].trTria.GetP( ( nMinInd + 1) % 3)) ;
trSingleTria.trTria.SetP( 2, ptMax) ;
Vector3d vtTan = ptEn - ptSt ;
vtTan.Normalize() ;
if ( ( trSingleTria.trTria.GetP(1) - trSingleTria.trTria.GetP(0)) * ( vtTan ^ vtExtr) < 0.)
trSingleTria.bTriaInside = true ;
else
trSingleTria.bTriaInside = false ;
trSingleTria.trTria.Validate( true) ;
plInnerLoop.AddUPoint( 0., ptMin) ;
plInnerLoop.AddUPoint( 0., ptMax) ;
plInnerLoop.AddUPoint( 0., vTriaVec[nTr].trTria.GetP( ( nMinInd + 2) % 3)) ;
plInnerLoop.AddUPoint( 0., vTriaVec[nTr].trTria.GetP( nMinInd)) ;
plInnerLoop.AddUPoint( 0., ptMin) ;
if ( ( vTriaVec[nTr].trTria.GetP( nMinInd) - ptMin) * ( vtTan ^ vtExtr) < 0.)
bLoopInside = true ;
else
bLoopInside = false ;
}
else {
trSingleTria.trTria.SetP( 0, ptMin) ;
trSingleTria.trTria.SetP( 1, ptMax) ;
trSingleTria.trTria.SetP( 2, vTriaVec[nTr].trTria.GetP( nMinInd)) ;
Vector3d vtTan = ptEn - ptSt ;
vtTan.Normalize() ;
if ( ( trSingleTria.trTria.GetP( 2) - trSingleTria.trTria.GetP( 0)) * ( vtTan ^ vtExtr) < 0.)
trSingleTria.bTriaInside = true ;
else
trSingleTria.bTriaInside = false ;
trSingleTria.trTria.Validate( true) ;
plInnerLoop.AddUPoint( 0., ptMin) ;
plInnerLoop.AddUPoint( 0., vTriaVec[nTr].trTria.GetP( ( nMinInd + 1) % 3)) ;
plInnerLoop.AddUPoint( 0., vTriaVec[nTr].trTria.GetP( ( nMinInd + 2) % 3)) ;
plInnerLoop.AddUPoint( 0., ptMax) ;
plInnerLoop.AddUPoint( 0., ptMin) ;
if ( ( vTriaVec[nTr].trTria.GetP( ( nMinInd + 1) % 3) - ptMin) * ( vtTan ^ vtExtr) < 0.)
bLoopInside = true ;
else
bLoopInside = false ;
}
// Poligonalizzo il loop
Triangulate CreateTriangulation ;
PNTVECTOR vPt ;
INTVECTOR vTr ;
CreateTriangulation.Make( plInnerLoop, vPt, vTr) ;
// Aggiungo i triangoli al vettore
int nOldSize = int( vTriaVec.size()) ;
int nAddSize = int( vTr.size() / 3) ;
vTriaVec.resize( nOldSize + nAddSize) ;
for ( int m = nOldSize - 1 ; m > nTr ; -- m) {
vTriaVec[m + nAddSize] = vTriaVec[m] ;
}
vTriaVec[nTr] = trSingleTria ;
for ( int n = 0 ; n < int( vTr.size()) - 2 ; n += 3) {
int nNewTriaVertId[3] = { vTr[n], vTr[n + 1], vTr[n + 2] } ;
TriaInOut trNewTria ;
trNewTria.trTria.SetP( 0, vPt[nNewTriaVertId[0]]) ;
trNewTria.trTria.SetP( 1, vPt[nNewTriaVertId[1]]) ;
trNewTria.trTria.SetP( 2, vPt[nNewTriaVertId[2]]) ;
trNewTria.trTria.Validate( true) ;
trNewTria.bTriaInside = bLoopInside ;
vTriaVec[nTr + 1 + (n / 3)] = trNewTria ;
}
-- nTr ;
}
}
bContinue = plLine.GetNextLine( ptSt, ptEn) ;
}
// Se non sono state trovate intersezioni col triangolo
if ( vTriaVec.size() == 1) {
// Se almeno un punto interno (sotto l'ipotesi di nessuna intersezione
// equivale a tre punti interni) deve essere conservato così com'è.
if ( nVertInside > 0)
continue ;
// Altrimenti il triangolo deve essere eliminato
else {
RemoveTriangle( nT) ;
continue ;
}
}
RemoveTriangle( nT) ;
bModif = true ;
// Aggiungo i triangoli alla trimesh
for ( int n = 0 ; n < int( vTriaVec.size()) ; ++ n) {
if ( vTriaVec[n].bTriaInside) {
int nNewId[3] = { AddVertex(vTriaVec[n].trTria.GetP( 0)),
AddVertex(vTriaVec[n].trTria.GetP( 1)),
AddVertex(vTriaVec[n].trTria.GetP( 2)) } ;
AddTriangle( nNewId) ;
}
}
}
}
// Se avvenuta modifica, aggiorno tutto
if ( bModif)
return ( AdjustVertices() && DoCompacting()) ;
return true ;
}