diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc
index 6bf7336..d4263c2 100644
Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ
diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj
index e6b8fd1..900364d 100644
--- a/EgtGeomKernel.vcxproj
+++ b/EgtGeomKernel.vcxproj
@@ -392,6 +392,7 @@ copy $(TargetPath) \EgtProg\Dll64
+
diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters
index a8f9fbe..951db0c 100644
--- a/EgtGeomKernel.vcxproj.filters
+++ b/EgtGeomKernel.vcxproj.filters
@@ -456,6 +456,9 @@
File di origine\Geo
+
+ File di origine\Geo
+
diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp
index 2d32cfc..0970cbd 100644
--- a/SurfTriMesh.cpp
+++ b/SurfTriMesh.cpp
@@ -18,10 +18,10 @@
#include "GeoObjFactory.h"
#include "NgeWriter.h"
#include "NgeReader.h"
+#include "SurfFlatRegion.h"
#include "DistPointLine.h"
#include "Triangulate.h"
#include "GeoConst.h"
-#include "SurfFlatRegion.h"
#include "/EgtDev/Include/EGkIntersLinePlane.h"
#include "/EgtDev/Include/EGkPointGrid3d.h"
#include "/EgtDev/Include/EGkPolyLine.h"
@@ -3399,336 +3399,6 @@ SurfTriMesh::Invert( void)
return true ;
}
-//----------------------------------------------------------------------------
-bool
-SurfTriMesh::CutByTriangles( const Plane3d& plPlane, bool bSaveOnEq, bool& bModif)
-{
- // la superficie deve essere validata
- if ( m_nStatus != OK)
- return false ;
-
- // classifico i vertici rispetto al piano
- double dTol = max( min( 0.5 * m_dLinTol, 10 * EPS_SMALL), EPS_SMALL) ;
- for ( int i = 0 ; i < GetVertexSize() ; ++ i) {
- double dDist = DistPointPlane( m_vVert[i].ptP, plPlane) ;
- if ( abs( dDist) < dTol) {
- m_vVert[i].nTemp = 0 ;
- if ( abs( dDist) > EPS_SMALL)
- m_vVert[i].ptP -= plPlane.GetVersN() * dDist ;
- }
- else if ( dDist > 0)
- m_vVert[i].nTemp = +1 ;
- else
- m_vVert[i].nTemp = -1 ;
- }
-
- // aggiorno timestamp dei triangoli
- for ( auto& Tria : m_vTria)
- Tria.nTemp = m_nTimeStamp ;
- ++ m_nTimeStamp ;
-
- // sistemo i triangoli (eventualmente li elimino)
- for ( int i = 0 ; i < GetTriangleSize() ; ++ i) {
- // salto i triangoli cancellati e quelli aggiunti
- if ( m_vTria[i].nIdVert[0] == SVT_DEL || m_vTria[i].nTemp == m_nTimeStamp)
- continue ;
- // se flag abilita e giace sul piano ed equiverso, lo salvo
- if ( bSaveOnEq &&
- m_vVert[ m_vTria[i].nIdVert[0]].nTemp == 0 &&
- m_vVert[ m_vTria[i].nIdVert[1]].nTemp == 0 &&
- m_vVert[ m_vTria[i].nIdVert[2]].nTemp == 0 &&
- AreSameVectorApprox( m_vTria[i].vtN, plPlane.GetVersN()))
- ;
- // se giace sul piano o dalla parte esterna del piano, lo cancello
- else if ( m_vVert[ m_vTria[i].nIdVert[0]].nTemp != -1 &&
- m_vVert[ m_vTria[i].nIdVert[1]].nTemp != -1 &&
- m_vVert[ m_vTria[i].nIdVert[2]].nTemp != -1) {
- bModif = true ;
- RemoveTriangle( i) ;
- }
- // se giace dalla parte interna con al massimo un lato sul piano, lo conservo
- else if ( m_vVert[ m_vTria[i].nIdVert[0]].nTemp != 1 &&
- m_vVert[ m_vTria[i].nIdVert[1]].nTemp != 1 &&
- m_vVert[ m_vTria[i].nIdVert[2]].nTemp != 1)
- ;
- // altrimenti attraversa il piano, devo modificarlo
- else {
- bModif = true ;
- int nDisc = m_vVert[ m_vTria[i].nIdVert[0]].nTemp +
- m_vVert[ m_vTria[i].nIdVert[1]].nTemp +
- m_vVert[ m_vTria[i].nIdVert[2]].nTemp ;
- // se ha un vertice all'interno e uno sul piano -> 1 nuovo vertice e 1 nuovo triangolo
- if ( nDisc == 0) {
- // classifico i vertici
- int nVertOn, nVertIn, nVertOut ;
- if ( m_vVert[ m_vTria[i].nIdVert[0]].nTemp == 0) {
- nVertOn = 0 ;
- nVertIn = 1 ;
- nVertOut = 2 ;
- if ( m_vVert[ m_vTria[i].nIdVert[1]].nTemp > 0)
- swap( nVertIn, nVertOut) ;
- }
- else if ( m_vVert[ m_vTria[i].nIdVert[1]].nTemp == 0) {
- nVertOn = 1 ;
- nVertIn = 2 ;
- nVertOut = 0 ;
- if ( m_vVert[ m_vTria[i].nIdVert[2]].nTemp > 0)
- swap( nVertIn, nVertOut) ;
- }
- else {
- nVertOn = 2 ;
- nVertIn = 0 ;
- nVertOut = 1 ;
- if ( m_vVert[ m_vTria[i].nIdVert[0]].nTemp > 0)
- swap( nVertIn, nVertOut) ;
- }
- // calcolo il punto di intersezione del lato che attraversa il piano
- double dDistIn = - DistPointPlane( m_vVert[m_vTria[i].nIdVert[nVertIn]].ptP, plPlane) ;
- double dDistOut = DistPointPlane( m_vVert[m_vTria[i].nIdVert[nVertOut]].ptP, plPlane) ;
- Point3d ptInt = Media( m_vVert[m_vTria[i].nIdVert[nVertIn]].ptP,
- m_vVert[m_vTria[i].nIdVert[nVertOut]].ptP,
- dDistIn / ( dDistIn + dDistOut)) ;
- // inserisco il nuovo vertice
- int nNewV = AddVertex( ptInt) ;
- // inserisco il nuovo triangolo
- int nIdVert[3] = { m_vTria[i].nIdVert[0], m_vTria[i].nIdVert[1], m_vTria[i].nIdVert[2]} ;
- nIdVert[nVertOut] = nNewV ;
- int nIdTria = AddTriangle( nIdVert) ;
- if ( nIdTria == SVT_NULL)
- return false ;
- if ( nIdTria != SVT_DEL)
- m_vTria[nIdTria].nTemp = m_nTimeStamp ;
- // cancello il vecchio triangolo
- RemoveTriangle( i) ;
- }
- // se ha un vertice all'interno e due all'esterno -> 2 nuovi vertici e 1 nuovo triangolo
- else if ( nDisc == 1) {
- // classifico i vertici
- int nVertIn, nVertOut1, nVertOut2 ;
- if ( m_vVert[ m_vTria[i].nIdVert[0]].nTemp == -1) {
- nVertIn = 0 ;
- nVertOut1 = 1 ;
- nVertOut2 = 2 ;
- }
- else if ( m_vVert[ m_vTria[i].nIdVert[1]].nTemp == -1) {
- nVertIn = 1 ;
- nVertOut1 = 2 ;
- nVertOut2 = 0 ;
- }
- else {
- nVertIn = 2 ;
- nVertOut1 = 0 ;
- nVertOut2 = 1 ;
- }
- // calcolo i punti di intersezione dei lati che attraversano il piano
- double dDistIn = - DistPointPlane( m_vVert[m_vTria[i].nIdVert[nVertIn]].ptP, plPlane) ;
- double dDistOut1 = DistPointPlane( m_vVert[m_vTria[i].nIdVert[nVertOut1]].ptP, plPlane) ;
- double dDistOut2 = DistPointPlane( m_vVert[m_vTria[i].nIdVert[nVertOut2]].ptP, plPlane) ;
- Point3d ptInt1 = Media( m_vVert[m_vTria[i].nIdVert[nVertIn]].ptP,
- m_vVert[m_vTria[i].nIdVert[nVertOut1]].ptP,
- dDistIn / ( dDistIn + dDistOut1)) ;
- Point3d ptInt2 = Media( m_vVert[m_vTria[i].nIdVert[nVertIn]].ptP,
- m_vVert[m_vTria[i].nIdVert[nVertOut2]].ptP,
- dDistIn / ( dDistIn + dDistOut2)) ;
- // inserisco i nuovi vertici
- int nNewV1 = AddVertex( ptInt1) ;
- int nNewV2 = AddVertex( ptInt2) ;
- // inserisco il nuovo triangolo
- int nIdVert[3] = { m_vTria[i].nIdVert[0], m_vTria[i].nIdVert[1], m_vTria[i].nIdVert[2]} ;
- nIdVert[nVertOut1] = nNewV1 ;
- nIdVert[nVertOut2] = nNewV2 ;
- int nIdTria = AddTriangle( nIdVert) ;
- if ( nIdTria == SVT_NULL)
- return false ;
- if ( nIdTria != SVT_DEL)
- m_vTria[nIdTria].nTemp = m_nTimeStamp ;
- // cancello il vecchio triangolo
- RemoveTriangle( i) ;
- }
- // altrimenti ha due vertici all'interno e uno all'esterno -> 2 nuovi vertici e 2 nuovi triangoli
- else {
- // classifico i vertici
- int nVertIn1, nVertIn2, nVertOut ;
- if ( m_vVert[ m_vTria[i].nIdVert[0]].nTemp == 1) {
- nVertOut = 0 ;
- nVertIn1 = 1 ;
- nVertIn2 = 2 ;
- }
- else if ( m_vVert[ m_vTria[i].nIdVert[1]].nTemp == 1) {
- nVertOut = 1 ;
- nVertIn1 = 2 ;
- nVertIn2 = 0 ;
- }
- else {
- nVertOut = 2 ;
- nVertIn1 = 0 ;
- nVertIn2 = 1 ;
- }
- // calcolo i punti di intersezione dei lati che attraversano il piano
- double dDistIn1 = - DistPointPlane( m_vVert[m_vTria[i].nIdVert[nVertIn1]].ptP, plPlane) ;
- double dDistIn2 = - DistPointPlane( m_vVert[m_vTria[i].nIdVert[nVertIn2]].ptP, plPlane) ;
- double dDistOut = DistPointPlane( m_vVert[m_vTria[i].nIdVert[nVertOut]].ptP, plPlane) ;
- Point3d ptInt1 = Media( m_vVert[m_vTria[i].nIdVert[nVertIn1]].ptP,
- m_vVert[m_vTria[i].nIdVert[nVertOut]].ptP,
- dDistIn1 / ( dDistIn1 + dDistOut)) ;
- Point3d ptInt2 = Media( m_vVert[m_vTria[i].nIdVert[nVertIn2]].ptP,
- m_vVert[m_vTria[i].nIdVert[nVertOut]].ptP,
- dDistIn2 / ( dDistIn2 + dDistOut)) ;
- // inserisco i nuovi vertici
- int nNewV1 = AddVertex( ptInt1) ;
- int nNewV2 = AddVertex( ptInt2) ;
- // inserisco i nuovi triangoli
- int nIdVert1[3] = { m_vTria[i].nIdVert[0], m_vTria[i].nIdVert[1], m_vTria[i].nIdVert[2]} ;
- int nIdVert2[3] = { m_vTria[i].nIdVert[0], m_vTria[i].nIdVert[1], m_vTria[i].nIdVert[2]} ;
- double dSqDist1 = SqDist( m_vVert[m_vTria[i].nIdVert[nVertIn1]].ptP, ptInt2) ;
- double dSqDist2 = SqDist( m_vVert[m_vTria[i].nIdVert[nVertIn2]].ptP, ptInt1) ;
- if ( dSqDist1 <= dSqDist2) {
- nIdVert1[nVertOut] = nNewV1 ;
- nIdVert1[nVertIn2] = nNewV2 ;
- nIdVert2[nVertOut] = nNewV2 ;
- }
- else {
- nIdVert1[nVertOut] = nNewV1 ;
- nIdVert2[nVertOut] = nNewV2 ;
- nIdVert2[nVertIn1] = nNewV1 ;
- }
- int nIdTria1 = AddTriangle( nIdVert1) ;
- int nIdTria2 = AddTriangle( nIdVert2) ;
- if ( nIdTria1 == SVT_NULL || nIdTria2 == SVT_NULL)
- return false ;
- if ( nIdTria1 != SVT_DEL)
- m_vTria[nIdTria1].nTemp = m_nTimeStamp ;
- if ( nIdTria2 != SVT_DEL)
- m_vTria[nIdTria2].nTemp = m_nTimeStamp ;
- // cancello il vecchio triangolo
- RemoveTriangle( i) ;
- }
- }
- }
-
- return true ;
-}
-
-//----------------------------------------------------------------------------
-bool
-SurfTriMesh::CutByFacets( const Plane3d& plPlane, bool bSaveOnEq, bool& bModif)
-{
- // Setto posizione triangoli non definita
- for ( int nT = 0 ; nT < GetTriangleSize() ; ++ nT)
- m_vTria[nT].nTempPart = 0 ;
-
- INTERSCHAINMAP IntersLineMap ;
-
- // Ciclo su tutte le facce.
- for ( int nF = 0 ; nF < GetFacetCount() ; ++ nF) {
- // Dati della faccia
- POLYLINEVECTOR vLoopVec ;
- GetFacetLoops( nF, vLoopVec) ;
- if ( vLoopVec.empty())
- continue ;
- // Verifico la posizione del loop esterno
- int nIntType = VerifyLoopPlane( vLoopVec[0], plPlane) ;
- // Se interseca il piano di taglio, calcolo la divisione della faccia
- LineFacetClassVector IntersLinePart ;
- if ( nIntType == FPI_CUT) {
- PtrOwner pReg( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( vLoopVec))) ;
- if ( IsNull( pReg) || ! pReg->IsValid())
- return false ;
- nIntType = IntersFacetPlane( *pReg, plPlane, IntersLinePart) ;
- }
- // Gestione dei risultati
- if ( nIntType == FPI_CUT) {
- for ( int nPart = 0 ; nPart < int( IntersLinePart.size()) ; ++ nPart) {
- // Salvo intersezione per la faccia.
- auto it = IntersLineMap.find( nF) ;
- if ( it != IntersLineMap.end()) {
- it->second.emplace_back( IntersInnSeg( IntersLinePart[nPart].ptSt, IntersLinePart[nPart].ptEn)) ;
- }
- else {
- IntersLineMap.emplace( nF, IntersInnChain( 1, IntersInnSeg( IntersLinePart[nPart].ptSt, IntersLinePart[nPart].ptEn))) ;
- }
- }
- }
- else if ( nIntType == FPI_ON) {
- INTVECTOR vT ;
- GetAllTriaInFacet( nF, vT) ;
- Vector3d vtNf ;
- GetFacetNormal( nF, vtNf) ;
- for ( auto& nT : vT)
- m_vTria[nT].nTempPart = ( vtNf * plPlane.GetVersN() > 0 ? 2 : -2) ;
- }
- else if ( nIntType == FPI_IN) {
- INTVECTOR vT ;
- GetAllTriaInFacet( nF, vT) ;
- for ( auto& nT : vT)
- m_vTria[nT].nTempPart = 1 ;
- }
- else if ( nIntType == FPI_OUT) {
- INTVECTOR vT ;
- GetAllTriaInFacet( nF, vT) ;
- for ( auto& nT : vT)
- m_vTria[nT].nTempPart = -1 ;
- }
- else
- return false ;
- }
-
- // Divido le facce.
- PieceMap NewFacet ;
- SplitFacet( IntersLineMap, NewFacet) ;
- INTERSEDGEMAP EdgeInterLineMap, EdgeEdgeLineMap ;
- RetriangulateFacetPieces( NewFacet, EdgeInterLineMap, EdgeEdgeLineMap) ;
-
- // Elimino i triangoli superflui
- for ( int nT = 0 ; nT < GetTriangleSize() ; ++ nT) {
- if ( m_vTria[nT].nTempPart == 0 ||
- m_vTria[nT].nTempPart == -1 ||
- m_vTria[nT].nTempPart == -2 ||
- ( ! bSaveOnEq && m_vTria[nT].nTempPart == 2)) {
- RemoveTriangle( nT) ;
- bModif = true ;
- }
- }
-
- return true ;
-}
-
-//----------------------------------------------------------------------------
-bool
-SurfTriMesh::Cut( const Plane3d& plPlane, bool bSaveOnEq)
-{
- // la superficie deve essere validata
- if ( m_nStatus != OK)
- return false ;
-
- // recupero il numero originale di triangoli e di facce
- int nTriaOriCnt = GetTriangleCount() ;
- int nFacetOriCnt = GetFacetCount() ;
-
- // eseguo il taglio con il metodo delle faccette o dei triangoli (per ora solo coi triangoli)
- bool bModif = false ;
- if ( true || ! CutByFacets( plPlane, bSaveOnEq, bModif)) {
- bModif = false ;
- if ( ! CutByTriangles( plPlane, bSaveOnEq, bModif))
- return false ;
- }
-
- // se effettuate modifiche
- 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::Cut")
- }
-
- return true ;
-}
-
//----------------------------------------------------------------------------
void
SurfTriMesh::ResetHashGrids3d( void) const
diff --git a/SurfTriMesh.h b/SurfTriMesh.h
index 6e61c43..7cf67b3 100644
--- a/SurfTriMesh.h
+++ b/SurfTriMesh.h
@@ -397,7 +397,6 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
bool RetriangulateFacetPieces( const PieceMap& NewFacet,
const INTERSEDGEMAP& EdgeInterLineMap,
const INTERSEDGEMAP& EdgeEdgeLineMap) ;
- bool SimplifyFacets( double dMaxEdgeLen) ;
bool EdgeInteriorContactManager( const SurfTriMesh& OthSurf,
const INTERSCHAINMAP& InterInterLineMap,
const INTERSEDGEMAP& EdgeInterLineMap) ;
@@ -411,6 +410,11 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
bool RemoveTripleTriangles( void) ;
bool ScanForTripleTriangles( bool& bModified) ;
bool FlipTriangles( int nTA, int nTB) ;
+ bool SimplifyFacets( double dMaxEdgeLen) ;
+ bool AddChainToChain( const Chain& ChainToAdd, PNTVECTOR& OrigChain) ;
+ bool DistPointFacet( const Point3d& ptP, const POLYLINEVECTOR& vPolyVec, double& dPointFacetDist) ;
+ bool ChangeStart( const Point3d& ptNewStart, PNTVECTOR& Loop) ;
+ bool SplitAtPoint( const Point3d& ptStop, const PNTVECTOR& Loop, PNTVECTOR& Loop1, PNTVECTOR& Loop2) ;
private :
ObjGraphicsMgr m_OGrMgr ; // gestore grafica dell'oggetto
diff --git a/SurfTriMeshBooleans.cpp b/SurfTriMeshBooleans.cpp
index 6ee90d0..2b199d5 100644
--- a/SurfTriMeshBooleans.cpp
+++ b/SurfTriMeshBooleans.cpp
@@ -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
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 ;
diff --git a/SurfTriMeshCuts.cpp b/SurfTriMeshCuts.cpp
new file mode 100644
index 0000000..a49e846
--- /dev/null
+++ b/SurfTriMeshCuts.cpp
@@ -0,0 +1,807 @@
+//----------------------------------------------------------------------------
+// EgalTech 2019-2021
+//----------------------------------------------------------------------------
+// File : SurfTriMeshCuts.cpp Data : 06.11.21 Versione : 2.3k3
+// Contenuto : Implementazione delle funzioni di taglio per SurfFTrimesh.
+//
+//
+//
+// Modifiche : 06.11.21 DS Creazione modulo.
+//
+//
+//----------------------------------------------------------------------------
+
+#include "stdafx.h"
+#include "CurveComposite.h"
+#include "SurfTriMesh.h"
+#include "SurfFlatRegion.h"
+#include "DistPointLine.h"
+#include "Triangulate.h"
+#include "GeoConst.h"
+#include "/EgtDev/Include/EgkSfrCreate.h"
+#include "/EgtDev/Include/EGkDistPointCurve.h"
+#include "/EgtDev/Include/EGkIntersLinePlane.h"
+#include "/EgtDev/Include/EGkIntersPlaneTria.h"
+
+using namespace std ;
+
+//----------------------------------------------------------------------------
+const double CUT_SCALE = 1024 ;
+
+//----------------------------------------------------------------------------
+bool
+SurfTriMesh::Cut( const Plane3d& plPlane, bool bSaveOnEq)
+{
+ // la superficie deve essere validata
+ if ( m_nStatus != OK)
+ return false ;
+
+ // recupero il numero originale di triangoli e di facce
+ int nTriaOriCnt = GetTriangleCount() ;
+ int nFacetOriCnt = GetFacetCount() ;
+
+ // eseguo il taglio con il metodo delle faccette o dei triangoli (per ora solo coi triangoli)
+ bool bModif = false ;
+ if ( true || ! CutByFacets( plPlane, bSaveOnEq, bModif)) {
+ bModif = false ;
+ if ( ! CutByTriangles( plPlane, bSaveOnEq, bModif))
+ return false ;
+ }
+
+ // se effettuate modifiche
+ 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::Cut")
+ }
+
+ return true ;
+}
+
+//----------------------------------------------------------------------------
+bool
+SurfTriMesh::CutByTriangles( const Plane3d& plPlane, bool bSaveOnEq, bool& bModif)
+{
+ // la superficie deve essere validata
+ if ( m_nStatus != OK)
+ return false ;
+
+ // classifico i vertici rispetto al piano
+ double dTol = max( min( 0.5 * m_dLinTol, 10 * EPS_SMALL), EPS_SMALL) ;
+ for ( int i = 0 ; i < GetVertexSize() ; ++ i) {
+ double dDist = DistPointPlane( m_vVert[i].ptP, plPlane) ;
+ if ( abs( dDist) < dTol) {
+ m_vVert[i].nTemp = 0 ;
+ if ( abs( dDist) > EPS_SMALL)
+ m_vVert[i].ptP -= plPlane.GetVersN() * dDist ;
+ }
+ else if ( dDist > 0)
+ m_vVert[i].nTemp = +1 ;
+ else
+ m_vVert[i].nTemp = -1 ;
+ }
+
+ // aggiorno timestamp dei triangoli
+ for ( auto& Tria : m_vTria)
+ Tria.nTemp = m_nTimeStamp ;
+ ++ m_nTimeStamp ;
+
+ // sistemo i triangoli (eventualmente li elimino)
+ for ( int i = 0 ; i < GetTriangleSize() ; ++ i) {
+ // salto i triangoli cancellati e quelli aggiunti
+ if ( m_vTria[i].nIdVert[0] == SVT_DEL || m_vTria[i].nTemp == m_nTimeStamp)
+ continue ;
+ // se flag abilita e giace sul piano ed equiverso, lo salvo
+ if ( bSaveOnEq &&
+ m_vVert[ m_vTria[i].nIdVert[0]].nTemp == 0 &&
+ m_vVert[ m_vTria[i].nIdVert[1]].nTemp == 0 &&
+ m_vVert[ m_vTria[i].nIdVert[2]].nTemp == 0 &&
+ AreSameVectorApprox( m_vTria[i].vtN, plPlane.GetVersN()))
+ ;
+ // se giace sul piano o dalla parte esterna del piano, lo cancello
+ else if ( m_vVert[ m_vTria[i].nIdVert[0]].nTemp != -1 &&
+ m_vVert[ m_vTria[i].nIdVert[1]].nTemp != -1 &&
+ m_vVert[ m_vTria[i].nIdVert[2]].nTemp != -1) {
+ bModif = true ;
+ RemoveTriangle( i) ;
+ }
+ // se giace dalla parte interna con al massimo un lato sul piano, lo conservo
+ else if ( m_vVert[ m_vTria[i].nIdVert[0]].nTemp != 1 &&
+ m_vVert[ m_vTria[i].nIdVert[1]].nTemp != 1 &&
+ m_vVert[ m_vTria[i].nIdVert[2]].nTemp != 1)
+ ;
+ // altrimenti attraversa il piano, devo modificarlo
+ else {
+ bModif = true ;
+ int nDisc = m_vVert[ m_vTria[i].nIdVert[0]].nTemp +
+ m_vVert[ m_vTria[i].nIdVert[1]].nTemp +
+ m_vVert[ m_vTria[i].nIdVert[2]].nTemp ;
+ // se ha un vertice all'interno e uno sul piano -> 1 nuovo vertice e 1 nuovo triangolo
+ if ( nDisc == 0) {
+ // classifico i vertici
+ int nVertOn, nVertIn, nVertOut ;
+ if ( m_vVert[ m_vTria[i].nIdVert[0]].nTemp == 0) {
+ nVertOn = 0 ;
+ nVertIn = 1 ;
+ nVertOut = 2 ;
+ if ( m_vVert[ m_vTria[i].nIdVert[1]].nTemp > 0)
+ swap( nVertIn, nVertOut) ;
+ }
+ else if ( m_vVert[ m_vTria[i].nIdVert[1]].nTemp == 0) {
+ nVertOn = 1 ;
+ nVertIn = 2 ;
+ nVertOut = 0 ;
+ if ( m_vVert[ m_vTria[i].nIdVert[2]].nTemp > 0)
+ swap( nVertIn, nVertOut) ;
+ }
+ else {
+ nVertOn = 2 ;
+ nVertIn = 0 ;
+ nVertOut = 1 ;
+ if ( m_vVert[ m_vTria[i].nIdVert[0]].nTemp > 0)
+ swap( nVertIn, nVertOut) ;
+ }
+ // calcolo il punto di intersezione del lato che attraversa il piano
+ double dDistIn = - DistPointPlane( m_vVert[m_vTria[i].nIdVert[nVertIn]].ptP, plPlane) ;
+ double dDistOut = DistPointPlane( m_vVert[m_vTria[i].nIdVert[nVertOut]].ptP, plPlane) ;
+ Point3d ptInt = Media( m_vVert[m_vTria[i].nIdVert[nVertIn]].ptP,
+ m_vVert[m_vTria[i].nIdVert[nVertOut]].ptP,
+ dDistIn / ( dDistIn + dDistOut)) ;
+ // inserisco il nuovo vertice
+ int nNewV = AddVertex( ptInt) ;
+ // inserisco il nuovo triangolo
+ int nIdVert[3] = { m_vTria[i].nIdVert[0], m_vTria[i].nIdVert[1], m_vTria[i].nIdVert[2]} ;
+ nIdVert[nVertOut] = nNewV ;
+ int nIdTria = AddTriangle( nIdVert) ;
+ if ( nIdTria == SVT_NULL)
+ return false ;
+ if ( nIdTria != SVT_DEL)
+ m_vTria[nIdTria].nTemp = m_nTimeStamp ;
+ // cancello il vecchio triangolo
+ RemoveTriangle( i) ;
+ }
+ // se ha un vertice all'interno e due all'esterno -> 2 nuovi vertici e 1 nuovo triangolo
+ else if ( nDisc == 1) {
+ // classifico i vertici
+ int nVertIn, nVertOut1, nVertOut2 ;
+ if ( m_vVert[ m_vTria[i].nIdVert[0]].nTemp == -1) {
+ nVertIn = 0 ;
+ nVertOut1 = 1 ;
+ nVertOut2 = 2 ;
+ }
+ else if ( m_vVert[ m_vTria[i].nIdVert[1]].nTemp == -1) {
+ nVertIn = 1 ;
+ nVertOut1 = 2 ;
+ nVertOut2 = 0 ;
+ }
+ else {
+ nVertIn = 2 ;
+ nVertOut1 = 0 ;
+ nVertOut2 = 1 ;
+ }
+ // calcolo i punti di intersezione dei lati che attraversano il piano
+ double dDistIn = - DistPointPlane( m_vVert[m_vTria[i].nIdVert[nVertIn]].ptP, plPlane) ;
+ double dDistOut1 = DistPointPlane( m_vVert[m_vTria[i].nIdVert[nVertOut1]].ptP, plPlane) ;
+ double dDistOut2 = DistPointPlane( m_vVert[m_vTria[i].nIdVert[nVertOut2]].ptP, plPlane) ;
+ Point3d ptInt1 = Media( m_vVert[m_vTria[i].nIdVert[nVertIn]].ptP,
+ m_vVert[m_vTria[i].nIdVert[nVertOut1]].ptP,
+ dDistIn / ( dDistIn + dDistOut1)) ;
+ Point3d ptInt2 = Media( m_vVert[m_vTria[i].nIdVert[nVertIn]].ptP,
+ m_vVert[m_vTria[i].nIdVert[nVertOut2]].ptP,
+ dDistIn / ( dDistIn + dDistOut2)) ;
+ // inserisco i nuovi vertici
+ int nNewV1 = AddVertex( ptInt1) ;
+ int nNewV2 = AddVertex( ptInt2) ;
+ // inserisco il nuovo triangolo
+ int nIdVert[3] = { m_vTria[i].nIdVert[0], m_vTria[i].nIdVert[1], m_vTria[i].nIdVert[2]} ;
+ nIdVert[nVertOut1] = nNewV1 ;
+ nIdVert[nVertOut2] = nNewV2 ;
+ int nIdTria = AddTriangle( nIdVert) ;
+ if ( nIdTria == SVT_NULL)
+ return false ;
+ if ( nIdTria != SVT_DEL)
+ m_vTria[nIdTria].nTemp = m_nTimeStamp ;
+ // cancello il vecchio triangolo
+ RemoveTriangle( i) ;
+ }
+ // altrimenti ha due vertici all'interno e uno all'esterno -> 2 nuovi vertici e 2 nuovi triangoli
+ else {
+ // classifico i vertici
+ int nVertIn1, nVertIn2, nVertOut ;
+ if ( m_vVert[ m_vTria[i].nIdVert[0]].nTemp == 1) {
+ nVertOut = 0 ;
+ nVertIn1 = 1 ;
+ nVertIn2 = 2 ;
+ }
+ else if ( m_vVert[ m_vTria[i].nIdVert[1]].nTemp == 1) {
+ nVertOut = 1 ;
+ nVertIn1 = 2 ;
+ nVertIn2 = 0 ;
+ }
+ else {
+ nVertOut = 2 ;
+ nVertIn1 = 0 ;
+ nVertIn2 = 1 ;
+ }
+ // calcolo i punti di intersezione dei lati che attraversano il piano
+ double dDistIn1 = - DistPointPlane( m_vVert[m_vTria[i].nIdVert[nVertIn1]].ptP, plPlane) ;
+ double dDistIn2 = - DistPointPlane( m_vVert[m_vTria[i].nIdVert[nVertIn2]].ptP, plPlane) ;
+ double dDistOut = DistPointPlane( m_vVert[m_vTria[i].nIdVert[nVertOut]].ptP, plPlane) ;
+ Point3d ptInt1 = Media( m_vVert[m_vTria[i].nIdVert[nVertIn1]].ptP,
+ m_vVert[m_vTria[i].nIdVert[nVertOut]].ptP,
+ dDistIn1 / ( dDistIn1 + dDistOut)) ;
+ Point3d ptInt2 = Media( m_vVert[m_vTria[i].nIdVert[nVertIn2]].ptP,
+ m_vVert[m_vTria[i].nIdVert[nVertOut]].ptP,
+ dDistIn2 / ( dDistIn2 + dDistOut)) ;
+ // inserisco i nuovi vertici
+ int nNewV1 = AddVertex( ptInt1) ;
+ int nNewV2 = AddVertex( ptInt2) ;
+ // inserisco i nuovi triangoli
+ int nIdVert1[3] = { m_vTria[i].nIdVert[0], m_vTria[i].nIdVert[1], m_vTria[i].nIdVert[2]} ;
+ int nIdVert2[3] = { m_vTria[i].nIdVert[0], m_vTria[i].nIdVert[1], m_vTria[i].nIdVert[2]} ;
+ double dSqDist1 = SqDist( m_vVert[m_vTria[i].nIdVert[nVertIn1]].ptP, ptInt2) ;
+ double dSqDist2 = SqDist( m_vVert[m_vTria[i].nIdVert[nVertIn2]].ptP, ptInt1) ;
+ if ( dSqDist1 <= dSqDist2) {
+ nIdVert1[nVertOut] = nNewV1 ;
+ nIdVert1[nVertIn2] = nNewV2 ;
+ nIdVert2[nVertOut] = nNewV2 ;
+ }
+ else {
+ nIdVert1[nVertOut] = nNewV1 ;
+ nIdVert2[nVertOut] = nNewV2 ;
+ nIdVert2[nVertIn1] = nNewV1 ;
+ }
+ int nIdTria1 = AddTriangle( nIdVert1) ;
+ int nIdTria2 = AddTriangle( nIdVert2) ;
+ if ( nIdTria1 == SVT_NULL || nIdTria2 == SVT_NULL)
+ return false ;
+ if ( nIdTria1 != SVT_DEL)
+ m_vTria[nIdTria1].nTemp = m_nTimeStamp ;
+ if ( nIdTria2 != SVT_DEL)
+ m_vTria[nIdTria2].nTemp = m_nTimeStamp ;
+ // cancello il vecchio triangolo
+ RemoveTriangle( i) ;
+ }
+ }
+ }
+
+ return true ;
+}
+
+//----------------------------------------------------------------------------
+bool
+SurfTriMesh::CutByFacets( const Plane3d& plPlane, bool bSaveOnEq, bool& bModif)
+{
+ // Setto posizione triangoli non definita
+ for ( int nT = 0 ; nT < GetTriangleSize() ; ++ nT)
+ m_vTria[nT].nTempPart = 0 ;
+
+ INTERSCHAINMAP IntersLineMap ;
+
+ // Ciclo su tutte le facce.
+ for ( int nF = 0 ; nF < GetFacetCount() ; ++ nF) {
+ // Dati della faccia
+ POLYLINEVECTOR vLoopVec ;
+ GetFacetLoops( nF, vLoopVec) ;
+ if ( vLoopVec.empty())
+ continue ;
+ // Verifico la posizione del loop esterno
+ int nIntType = VerifyLoopPlane( vLoopVec[0], plPlane) ;
+ // Se interseca il piano di taglio, calcolo la divisione della faccia
+ LineFacetClassVector IntersLinePart ;
+ if ( nIntType == FPI_CUT) {
+ PtrOwner pReg( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( vLoopVec))) ;
+ if ( IsNull( pReg) || ! pReg->IsValid())
+ return false ;
+ nIntType = IntersFacetPlane( *pReg, plPlane, IntersLinePart) ;
+ }
+ // Gestione dei risultati
+ if ( nIntType == FPI_CUT) {
+ for ( int nPart = 0 ; nPart < int( IntersLinePart.size()) ; ++ nPart) {
+ // Salvo intersezione per la faccia.
+ auto it = IntersLineMap.find( nF) ;
+ if ( it != IntersLineMap.end()) {
+ it->second.emplace_back( IntersInnSeg( IntersLinePart[nPart].ptSt, IntersLinePart[nPart].ptEn)) ;
+ }
+ else {
+ IntersLineMap.emplace( nF, IntersInnChain( 1, IntersInnSeg( IntersLinePart[nPart].ptSt, IntersLinePart[nPart].ptEn))) ;
+ }
+ }
+ }
+ else if ( nIntType == FPI_ON) {
+ INTVECTOR vT ;
+ GetAllTriaInFacet( nF, vT) ;
+ Vector3d vtNf ;
+ GetFacetNormal( nF, vtNf) ;
+ for ( auto& nT : vT)
+ m_vTria[nT].nTempPart = ( vtNf * plPlane.GetVersN() > 0 ? 2 : -2) ;
+ }
+ else if ( nIntType == FPI_IN) {
+ INTVECTOR vT ;
+ GetAllTriaInFacet( nF, vT) ;
+ for ( auto& nT : vT)
+ m_vTria[nT].nTempPart = 1 ;
+ }
+ else if ( nIntType == FPI_OUT) {
+ INTVECTOR vT ;
+ GetAllTriaInFacet( nF, vT) ;
+ for ( auto& nT : vT)
+ m_vTria[nT].nTempPart = -1 ;
+ }
+ else
+ return false ;
+ }
+
+ // Divido le facce.
+ PieceMap NewFacet ;
+ SplitFacet( IntersLineMap, NewFacet) ;
+ INTERSEDGEMAP EdgeInterLineMap, EdgeEdgeLineMap ;
+ RetriangulateFacetPieces( NewFacet, EdgeInterLineMap, EdgeEdgeLineMap) ;
+
+ // Elimino i triangoli superflui
+ for ( int nT = 0 ; nT < GetTriangleSize() ; ++ nT) {
+ if ( m_vTria[nT].nTempPart == 0 ||
+ m_vTria[nT].nTempPart == -1 ||
+ m_vTria[nT].nTempPart == -2 ||
+ ( ! bSaveOnEq && m_vTria[nT].nTempPart == 2)) {
+ RemoveTriangle( nT) ;
+ bModif = true ;
+ }
+ }
+
+ return true ;
+}
+
+//----------------------------------------------------------------------------
+// Risultato : 0=nessuna intersezione, 1=intersezione è un punto, 2=intersezione è un segmento
+static int
+IntersRectangleTriangle( const Point3d& ptP, const Vector3d& vtL1, const Vector3d& vtL2,
+ const Triangle3d& trTria, Point3d& ptStSeg, Point3d& ptEnSeg)
+{
+ // Assegno tolleranza lineare
+ double dTol = EPS_SMALL ;
+ // Definisco il piano del rettangolo
+ Plane3d plRectanglePlane ;
+ if ( ! plRectanglePlane.Set( ptP, vtL1 ^ vtL2))
+ return -1 ;
+ // Interseco il piano con il triangolo (recupero estremi in ordine inverso per mantenere l'esterno a destra nei loop)
+ int nPlTrIntRes = IntersPlaneTria( plRectanglePlane, trTria, ptEnSeg, ptStSeg) ;
+ if ( nPlTrIntRes != IntPlaneTriaType::IPTT_YES)
+ return 0 ;
+ // Limito il segmento col rettangolo
+ Vector3d vtSegDir = ptEnSeg - ptStSeg ;
+ double dSegLen = vtSegDir.Len() ;
+ vtSegDir /= dSegLen ;
+ // utilizzo piani ortogonali al rettangolo passanti per i suoi estremi
+ Plane3d plTrim1 ; plTrim1.Set( ptP, -vtL1) ;
+ Plane3d plTrim2 ; plTrim2.Set( ptP + vtL1, vtL1) ;
+ if ( vtSegDir * vtL1 < 0.)
+ swap( plTrim1, plTrim2) ;
+ Point3d ptInt1 ;
+ int nLnPl1IntRes = IntersLinePlane( ptStSeg, vtSegDir, dSegLen, plTrim1, ptInt1, false) ;
+ Point3d ptInt2 ;
+ int nLnPl2IntRes = IntersLinePlane( ptStSeg, vtSegDir, dSegLen, plTrim2, ptInt2, false) ;
+ // Se il segmento giace in uno dei due piani
+ if ( ( nLnPl1IntRes == ILPT_NO && nLnPl2IntRes == ILPT_INPLANE) ||
+ ( nLnPl2IntRes == ILPT_NO && nLnPl1IntRes == ILPT_INPLANE))
+ return ( AreSamePointEpsilon( ptStSeg, ptEnSeg, dTol) ? 1 : 2) ;
+ // Se non ci sono intersezioni
+ if ( nLnPl1IntRes == ILPT_NO && nLnPl2IntRes == ILPT_NO) {
+ // se è tra i due piani
+ if (( ptStSeg - plTrim1.GetPoint()) * plTrim1.GetVersN() < 0. &&
+ ( ptStSeg - plTrim2.GetPoint()) * plTrim2.GetVersN() < 0.)
+ return ( AreSamePointEpsilon( ptStSeg, ptEnSeg, dTol) ? 1 : 2) ;
+ // altrimenti è esterno
+ else
+ return 0 ;
+ }
+ // Posizioni parametriche delle intersezioni sul segmento
+ double dLen1 = ( ptInt1 - ptStSeg) * vtSegDir ;
+ double dLen2 = ( ptInt2 - ptStSeg) * vtSegDir ;
+ // Se la prima intersezione supera la fine o la seconda viene prima dell'inizio, non ci sono intersezioni
+ if ( dLen1 > dSegLen + EPS_ZERO || dLen2 < -EPS_ZERO)
+ return 0 ;
+ // Eventuale aggiustamento inizio
+ if ( dLen1 > 0.) {
+ ptStSeg = ptInt1 ;
+ dSegLen -= dLen1 ;
+ dLen2 -= dLen1 ;
+ }
+ // Eventuale aggiustamento fine
+ if ( dLen2 < dSegLen) {
+ ptEnSeg = ptInt2 ;
+ dSegLen = dLen2 ;
+ }
+ // Assegno il tipo di intersezione
+ return ( dSegLen > dTol ? 2 : 1) ;
+}
+
+//----------------------------------------------------------------------------
+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 ;
+ }
+
+ // Eseguo scalature
+ Frame3d frScalingRef;
+ frScalingRef.Set( m_vVert[0].ptP, X_AX, Y_AX, Z_AX) ;
+ Scale( frScalingRef, CUT_SCALE, CUT_SCALE, CUT_SCALE) ;
+ cvCompo.Scale( frScalingRef, CUT_SCALE, CUT_SCALE, CUT_SCALE) ;
+
+ // 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)) {
+ Scale( frScalingRef, 1. / CUT_SCALE, 1. / CUT_SCALE, 1. / CUT_SCALE) ;
+ 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 se il centro del triangolo cade all'interno della curva
+ bool bTriaCenIn = false ;
+ {
+ DistPointCurve dstPC( trTria.GetCentroid(), cvCompo) ;
+ int nSide ;
+ if ( dstPC.GetSideAtMinDistPoint( 0, vtExtr, nSide))
+ bTriaCenIn = ( nSide == MDS_LEFT) ;
+ }
+
+ // 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() ;
+ }
+
+ for ( auto itI = vChain.begin() ; itI != vChain.end() ; ) {
+ bool bErased = false ;
+ auto itJ = itI ;
+ ++ itJ ;
+ for ( ; itJ != vChain.end() && ! bErased ; ) {
+ if ( int( itI->size()) == 1 && int( itJ->size()) == 1 &&
+ AreSamePointEpsilon( itI->back().ptSt, itJ->back().ptEn, 2 * EPS_SMALL) &&
+ AreSamePointEpsilon( itI->back().ptEn, itJ->back().ptSt, 2 * EPS_SMALL)) {
+ itJ = vChain.erase( itJ) ;
+ bErased = true ;
+ }
+ else
+ ++ itJ ;
+ }
+ if ( bErased) {
+ itI = vChain.erase( itI) ;
+ bErased = false ;
+ }
+ else
+ ++ itI ;
+ }
+
+ // 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) && nCurLoopLast > 0)
+ 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)) {
+ Scale( frScalingRef, 1. / CUT_SCALE, 1. / CUT_SCALE, 1. / CUT_SCALE) ;
+ 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 ( ! bTriaCenIn) {
+ RemoveTriangle( nT) ;
+ bModif = true ;
+ }
+ }
+
+ // Se avvenuta modifica, aggiorno tutto
+ if ( bModif) {
+ // aggiorno tutto
+ if ( ! AdjustVertices() || ! DoCompacting()) {
+ Scale( frScalingRef, 1. / CUT_SCALE, 1. / CUT_SCALE, 1. / CUT_SCALE) ;
+ return false ;
+ }
+ }
+
+ // Ripristino scala originale
+ Scale( frScalingRef, 1. / CUT_SCALE, 1. / CUT_SCALE, 1. / CUT_SCALE) ;
+
+ // 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 ;
+}
diff --git a/SurfTriMeshUtilities.cpp b/SurfTriMeshUtilities.cpp
index eb88e7d..8aeeea2 100644
--- a/SurfTriMeshUtilities.cpp
+++ b/SurfTriMeshUtilities.cpp
@@ -248,3 +248,192 @@ SurfTriMesh::SimplifyFacets( double dMaxEdgeLen)
// Eseguo aggiustamenti
return ( AdjustVertices() && DoCompacting()) ;
}
+
+//----------------------------------------------------------------------------
+bool
+SurfTriMesh::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
+bool
+SurfTriMesh::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 ;
+}
+
+//----------------------------------------------------------------------------
+bool
+SurfTriMesh::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 ;
+}
+
+//----------------------------------------------------------------------------
+bool
+SurfTriMesh::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 < int( Loop.size()) ; ++ 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 {
+ if ( nMinSeg != int( Loop.size()) )
+ 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 ;
+}