EgtGeomKernel 2.3k3 :
- modifiche per GeneralizedCut di SurfTriMesh - Cut e GeneralizedCut di SurfTriMesh spostati in nuovo sorgente SurfTriMeshCuts.cpp.
This commit is contained in:
+13
-635
@@ -1,13 +1,14 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// EgalTech 2019-2020
|
||||
// EgalTech 2019-2021
|
||||
//----------------------------------------------------------------------------
|
||||
// File : SurfTriMeshBooleans.cpp Data : 01.10.20 Versione : 2.2j1
|
||||
// File : SurfTriMeshBooleans.cpp Data : 06.11.21 Versione : 2.3k3
|
||||
// Contenuto : Implementazione delle funzioni booleane per SurfFTrimesh.
|
||||
//
|
||||
//
|
||||
//
|
||||
// Modifiche : 10.05.19 LM Creazione modulo.
|
||||
// 01.10.20 LM Aggiunte scalature 1024x.
|
||||
// 06.11.21 LM Rifacimento GeneralizedCut.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
@@ -20,19 +21,19 @@
|
||||
#include "Triangulate.h"
|
||||
#include "GeoConst.h"
|
||||
#include "/EgtDev/Include/EgtNumUtils.h"
|
||||
#include "/EgtDev/Include/EgkCurve.h"
|
||||
#include "/EgtDev/Include/EgkDistPointCurve.h"
|
||||
#include "/EgtDev/Include/EgkDistPointTria.h"
|
||||
#include "/EgtDev/Include/EgkIntersLineTria.h"
|
||||
#include "/EgtDev/Include/EgkIntersLineBox.h"
|
||||
#include "/EgtDev/Include/EgkIntersPlanePlane.h"
|
||||
#include "/EgtDev/Include/EgkIntersTriaTria.h"
|
||||
#include "/EgtDev/Include/EgkSfrCreate.h"
|
||||
#include "/EgtDev/Include/EGkCurve.h"
|
||||
#include "/EgtDev/Include/EGkDistPointCurve.h"
|
||||
#include "/EgtDev/Include/EGkDistPointTria.h"
|
||||
#include "/EgtDev/Include/EGkIntersLineTria.h"
|
||||
#include "/EgtDev/Include/EGkIntersLineBox.h"
|
||||
#include "/EgtDev/Include/EGkIntersPlanePlane.h"
|
||||
#include "/EgtDev/Include/EGkIntersTriaTria.h"
|
||||
#include "/EgtDev/Include/EGkSfrCreate.h"
|
||||
#include "/EgtDev/Include/EGkChainCurves.h"
|
||||
#include "/EgtDev/Include/EGkGeoCollection.h"
|
||||
#include "/EgtDev/Include/EGkPolygon3d.h"
|
||||
#include "/EgtDev/Include/EgtPerfCounter.h"
|
||||
#include "/EgtDev/Include/EgnStringUtils.h"
|
||||
#include "/EgtDev/Include/EGnStringUtils.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std ;
|
||||
@@ -40,629 +41,6 @@ using namespace std ;
|
||||
//----------------------------------------------------------------------------
|
||||
const double BOOLEAN_SCALE = 1024 ;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static 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_VERT_VERT || nIntTypeA == ITTT_VERT_EDGE || nIntTypeA == ITTT_VERT_INT || nIntTypeA == ITTT_EDGE_VERT || nIntTypeA == ITTT_EDGE_EDGE_PNT || nIntTypeA == ITTT_INT_VERT)
|
||||
nIntA = 1 ;
|
||||
else if ( /*nIntTypeA == ITTT_EDGE_EDGE_SEG || nIntTypeA == ITTT_EDGE_INT ||*/ nIntTypeA == ITTT_INT_EDGE || nIntTypeA == ITTT_INT_INT_SEG) {
|
||||
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_VERT_VERT || nIntTypeB == ITTT_VERT_EDGE || nIntTypeB == ITTT_VERT_INT || nIntTypeB == ITTT_EDGE_VERT || nIntTypeB == ITTT_EDGE_EDGE_PNT || nIntTypeB == ITTT_INT_VERT)
|
||||
nIntB = 1 ;
|
||||
else if ( /*nIntTypeB == ITTT_EDGE_EDGE_SEG || nIntTypeB == ITTT_EDGE_INT ||*/ nIntTypeB == ITTT_INT_EDGE || nIntTypeB == ITTT_INT_INT_SEG) {
|
||||
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 ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static 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
|
||||
return false ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Una faccia di una trimesh ha una sola componente connessa, con un loop esterno e possibili loop interni
|
||||
static bool
|
||||
DistPointFacet( const Point3d& ptP, const POLYLINEVECTOR& vPolyVec, double& dPointFacetDist)
|
||||
{
|
||||
// Verifico la presenza del loop esterno
|
||||
if ( vPolyVec.size() < 1)
|
||||
return false ;
|
||||
// Proietto il punto sul piano della faccia, utilizzando il loop esterno
|
||||
Plane3d plPlane ;
|
||||
double dArea ;
|
||||
if ( ! vPolyVec[0].IsClosedAndFlat( plPlane, dArea))
|
||||
return false ;
|
||||
double dDistPtPl = DistPointPlane( ptP, plPlane) ;
|
||||
Point3d ptProjP = ptP + dDistPtPl * plPlane.GetVersN() ;
|
||||
// Verifico se il punto proiettato è esterno al loop esterno
|
||||
int nPtOut = -1 ;
|
||||
if ( ! IsPointInsidePolyLine( ptProjP, vPolyVec[0], EPS_SMALL))
|
||||
nPtOut = 0 ;
|
||||
// Verifico se il punto proiettato è interno ai loop interni (quindi esterno alla faccia)
|
||||
for ( int nLoop = 1 ; nLoop < int( vPolyVec.size()) && nPtOut < 0 ; ++ nLoop) {
|
||||
Plane3d plPlane ;
|
||||
double dArea ;
|
||||
if ( ! vPolyVec[nLoop].IsClosedAndFlat( plPlane, dArea))
|
||||
return false ;
|
||||
if ( IsPointInsidePolyLine( ptProjP, vPolyVec[nLoop], EPS_SMALL))
|
||||
nPtOut = nLoop ;
|
||||
}
|
||||
// Se il punto si proietta sulla faccia, la distanza dalla faccia coincide con quella dal piano
|
||||
if ( nPtOut < 0) {
|
||||
dPointFacetDist = abs( dDistPtPl) ;
|
||||
return true ;
|
||||
}
|
||||
// Altrimenti calcolo la minima distanza del punto dalla polilinea del contorno a cui è esterno
|
||||
double dDist ;
|
||||
if ( DistPointPolyLine( ptP, vPolyVec[nPtOut], dDist)) {
|
||||
dPointFacetDist = dDist ;
|
||||
return true ;
|
||||
}
|
||||
return false ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool
|
||||
ChangeStart( const Point3d& ptNewStart, PNTVECTOR& Loop)
|
||||
{
|
||||
// Cerco il tratto del loop chiuso più vicino al punto
|
||||
int nMinSeg = - 1 ;
|
||||
double dMinSqDinst = DBL_MAX ;
|
||||
for ( int nPt = 0 ; nPt < int( Loop.size()) ; ++ nPt) {
|
||||
// Estremi del segmento corrente del loop
|
||||
Point3d ptSegSt = Loop[nPt] ;
|
||||
Point3d ptSegEn = Loop[( nPt + 1) % int( Loop.size())] ;
|
||||
// Distanza del punto dal segmento del loop
|
||||
DistPointLine dDistCalc( ptNewStart, ptSegSt, ptSegEn) ;
|
||||
double dSqDist ;
|
||||
dDistCalc.GetSqDist( dSqDist) ;
|
||||
if ( dSqDist < dMinSqDinst) {
|
||||
dMinSqDinst = dSqDist ;
|
||||
nMinSeg = nPt ;
|
||||
}
|
||||
}
|
||||
// Se il punto non sta sul loop, errore
|
||||
if ( dMinSqDinst > SQ_EPS_SMALL)
|
||||
return false ;
|
||||
// Verifico che il punto stia su un vertice, in tal caso non devo fare nulla
|
||||
bool bOnStart = AreSamePointApprox( Loop[nMinSeg], ptNewStart) ;
|
||||
bool bOnEnd = AreSamePointApprox( Loop[( nMinSeg + 1) % int( Loop.size())], ptNewStart) ;
|
||||
if ( bOnStart || bOnEnd) {
|
||||
if ( bOnEnd) {
|
||||
++ nMinSeg ;
|
||||
if ( nMinSeg % int( Loop.size()) == 0)
|
||||
return true ;
|
||||
}
|
||||
PNTVECTOR vTempVec ;
|
||||
for ( int nPt = 0 ; nPt < nMinSeg ; ++ nPt)
|
||||
vTempVec.emplace_back( Loop[nPt]) ;
|
||||
int nSize = int( Loop.size()) ;
|
||||
for ( int nPt = 0 ; nPt < nSize - nMinSeg ; ++ nPt) {
|
||||
Loop[nPt] = Loop[nPt + nMinSeg] ;
|
||||
}
|
||||
for ( int nPt = 0 ; nPt < int( vTempVec.size()) ; ++ nPt) {
|
||||
Loop[nPt + nSize - nMinSeg] = vTempVec[nPt] ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
// Ridimensiono il loop
|
||||
Loop.resize( Loop.size() + 1) ;
|
||||
// Copio i primi punti
|
||||
PNTVECTOR LoopTemp ;
|
||||
for ( int nPt = 0 ; nPt <= nMinSeg ; ++ 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 - nMinSeg ;
|
||||
for ( int nPt = 1 ; nPt <= nLastPointNum ; ++ nPt) {
|
||||
Loop[nPt] = Loop[nPt + nMinSeg] ;
|
||||
}
|
||||
// Porto i primi in fondo
|
||||
for ( int nPt = 0 ; nPt < int( LoopTemp.size()) ; ++ nPt) {
|
||||
Loop[nPt + nLastPointNum] = LoopTemp[nPt] ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool
|
||||
SplitAtPoint( const Point3d& ptStop, const PNTVECTOR& Loop, PNTVECTOR& Loop1, PNTVECTOR& Loop2)
|
||||
{
|
||||
// Cerco il tratto del loop chiuso più vicino al punto
|
||||
int nMinSeg = -1 ;
|
||||
double dMinSqDinst = DBL_MAX ;
|
||||
for ( int nPt = 0 ; nPt < int( Loop.size()) ; ++ nPt) {
|
||||
// Estremi del segmento corrente del loop
|
||||
Point3d ptSegSt = Loop[nPt] ;
|
||||
Point3d ptSegEn = Loop[( nPt + 1) % int(Loop.size())] ;
|
||||
// Distanza del punto dal segmento del loop
|
||||
DistPointLine dDistCalc( ptStop, ptSegSt, ptSegEn) ;
|
||||
double dSqDist ;
|
||||
dDistCalc.GetSqDist( dSqDist) ;
|
||||
if ( dSqDist < dMinSqDinst) {
|
||||
dMinSqDinst = dSqDist ;
|
||||
nMinSeg = nPt ;
|
||||
}
|
||||
}
|
||||
// Se il punto non sta sul loop, errore
|
||||
if ( dMinSqDinst > SQ_EPS_SMALL)
|
||||
return false ;
|
||||
// Verifico che il punto stia su un vertice, in tal caso non devo aggiungerlo
|
||||
bool bFirst = AreSamePointApprox( Loop[nMinSeg], ptStop) ;
|
||||
bool bLast = AreSamePointApprox( Loop[( nMinSeg + 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)
|
||||
++ nMinSeg ;
|
||||
// Inglobo fino a nSeg nel primo loop
|
||||
for ( int nPt = 0 ; nPt <= nMinSeg ; ++ 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[nMinSeg]) ;
|
||||
}
|
||||
// Inglobo gli ultimi vertici in Loop2
|
||||
for ( int nPt = nMinSeg + 1 ; nPt < int( Loop.size()) ; ++ nPt)
|
||||
Loop2.emplace_back( Loop[nPt]) ;
|
||||
Loop2.emplace_back( Loop[0]) ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
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 ;
|
||||
|
||||
// Recupero il numero originale di triangoli e di facce
|
||||
int nTriaOriCnt = GetTriangleCount() ;
|
||||
int nFacetOriCnt = GetFacetCount() ;
|
||||
|
||||
// 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 ;
|
||||
int nVertOutside = 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 ;
|
||||
else
|
||||
++ nVertOutside ;
|
||||
}
|
||||
|
||||
// Vettore di catene di punti
|
||||
CHAINVECTOR vChain ;
|
||||
// Ciclo sui segmenti
|
||||
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 == 2) {
|
||||
// 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 ;
|
||||
CurInters.ptSt = ptSegSt ;
|
||||
CurInters.ptEn = ptSegEn ;
|
||||
// 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() ;
|
||||
}
|
||||
if ( nChainCnt == 0 && nVertOutside > 0) {
|
||||
nVertInside = 0 ;
|
||||
vChain.clear() ;
|
||||
nChainCnt = 0 ;
|
||||
}
|
||||
// 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 ;
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
CHAINVECTOR cvClosedChain ;
|
||||
CHAINVECTOR cvOpenChain ;
|
||||
for ( int nL = 0 ; nL < int( vChain.size()) ; ++ nL) {
|
||||
int nCurLoopLast = max( int(vChain[nL].size()) - 1, 0) ;
|
||||
if ( AreSamePointApprox( vChain[nL][0].ptSt, vChain[nL][nCurLoopLast].ptEn))
|
||||
cvClosedChain.emplace_back( vChain[nL]) ;
|
||||
else {
|
||||
cvOpenChain.emplace_back( vChain[nL]) ;
|
||||
}
|
||||
}
|
||||
for ( auto it = cvClosedChain.begin() ; it != cvClosedChain.end() ; ) {
|
||||
if ( int( it->size()) < 3)
|
||||
it = cvClosedChain.erase( it) ;
|
||||
else
|
||||
++ it ;
|
||||
}
|
||||
// Se più di una catena chiusa oppure catene chiuse e aperte, errore
|
||||
if ( cvClosedChain.size() > 1 || ( cvClosedChain.size() > 0 && int( cvOpenChain.size()) > 0))
|
||||
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)) ;
|
||||
|
||||
PNTMATRIX 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 ;
|
||||
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 ;
|
||||
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] ;
|
||||
}
|
||||
cvBoundClosedLoopVec[nLoop] = Loop1 ;
|
||||
cvBoundClosedLoopVec[nLoop + 1] = Loop2 ;
|
||||
vbInOut[nLoop] = false ;
|
||||
vbInOut[nLoop + 1] = true ;
|
||||
++ nLoop ;
|
||||
}
|
||||
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 ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// da eliminare
|
||||
else if ( nVertInside == 0)
|
||||
RemoveTriangle( nT) ;
|
||||
}
|
||||
|
||||
// Se avvenuta modifica, aggiorno tutto
|
||||
if ( bModif) {
|
||||
// aggiorno tutto
|
||||
if ( ! AdjustVertices() || ! DoCompacting())
|
||||
return false ;
|
||||
}
|
||||
|
||||
// se superficie originale a facce, cerco di semplificarle in ogni caso
|
||||
if ( nFacetOriCnt < 200 || double( nTriaOriCnt) / nFacetOriCnt > 4) {
|
||||
if ( ! SimplifyFacets( 500.0))
|
||||
LOG_ERROR( GetEGkLogger(), "Error in SimplifyFacets of Stm::GeneralizedCut")
|
||||
}
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
SurfTriMesh::DecomposeLoop( CHAINVECTOR& cvOpenChain, INTVECTOR& vnDegVec, PNTMATRIX& cvBoundClosedLoopVec, BOOLVECTOR& vbInOut)
|
||||
@@ -1535,7 +913,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
static bool
|
||||
FindTriaIncidence( const Triangle3d& trTria, const TRIA3DVECTOR& vOthTriaVec, INTMATRIX& vAdjSegToCurTria)
|
||||
{
|
||||
int nNumFoundContact = 0 ;
|
||||
|
||||
Reference in New Issue
Block a user