diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc
index 5b8287e..fe95cc6 100644
Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ
diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj
index 8eb46d8..10459d3 100644
--- a/EgtGeomKernel.vcxproj
+++ b/EgtGeomKernel.vcxproj
@@ -401,6 +401,7 @@ copy $(TargetPath) \EgtProg\Dll64
+
@@ -620,6 +621,7 @@ copy $(TargetPath) \EgtProg\Dll64
+
diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters
index 6f8b271..9a17d76 100644
--- a/EgtGeomKernel.vcxproj.filters
+++ b/EgtGeomKernel.vcxproj.filters
@@ -486,6 +486,9 @@
File di origine\GeoProject
+
+ File di origine\GeoProject
+
@@ -1127,6 +1130,9 @@
File di intestazione
+
+ File di intestazione\Include
+
diff --git a/SubtractProjectedFacesOnStmFace.cpp b/SubtractProjectedFacesOnStmFace.cpp
new file mode 100644
index 0000000..e6cc25d
--- /dev/null
+++ b/SubtractProjectedFacesOnStmFace.cpp
@@ -0,0 +1,733 @@
+//----------------------------------------------------------------------------
+// EgalTech 2023-2023
+//----------------------------------------------------------------------------
+// File : EGkSubtractProjectedFacesOnStmFace.h Data : 26.09.23 Versione : 2.5j1
+// Contenuto : Dichiarazione della funzione per proiettare facce di TriMesh su una superficie di TriMesh.
+//
+//
+//
+// Modifiche : 26.09.23 RE Creazione modulo.
+//
+//
+//----------------------------------------------------------------------------
+
+//--------------------------- Include ----------------------------------------
+#include "stdafx.h"
+#include "DllMain.h"
+#include "GeoConst.h"
+#include "/EgtDev/Include/EGkSurfFlatRegion.h"
+#include "/EgtDev/Include/EGkSfrCreate.h"
+#include "/EgtDev/Include/EGkCurveAux.h"
+#include "/EgtDev/Include/EGkStmFromTriangleSoup.h"
+#include "/EgtDev/Include/EGkSubtractProjectedFacesOnStmFace.h"
+#include "/EgtDev/Include/EGkStmFromCurves.h"
+#include
+
+using namespace std ;
+
+//----------------------------------------------------------------------------
+// Proiezione sottrazione di facce di TriMesh su una faccia di TriMesh
+//----------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+static bool
+ImproveCurve( ICurveComposite* pCrvCompo, const Frame3d frface, const Plane3d plFace, bool& bSkip)
+{
+ // controllo dei parametri
+ if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid() ||
+ ! frface.IsValid())
+ return false ;
+
+ // 1) se la curva ha un'area o un perimetro troppo piccolo, la trascuro
+ double dArea = SQ_EPS_SMALL , dLen = EPS_SMALL ;
+ Plane3d plCrv ;
+ if ( ! pCrvCompo->GetArea( plCrv, dArea) || ! pCrvCompo->GetLength( dLen))
+ return false ;
+ if ( dArea < 50000 * SQ_EPS_SMALL || dLen < 50 * EPS_SMALL) {
+ bSkip = true ;
+ return true ;
+ }
+
+ // 2) Merge per uniformità
+ if ( ! pCrvCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL))
+ return false ;
+
+ // 3) Rimuoviamo Spikes o Curve a Z
+ if ( ! pCrvCompo->RemoveSmallDefects( 150 * EPS_SMALL, 2 * ANG_TOL_STD_DEG, true))
+ return false ;
+
+ // 4) Interpoliamo mediante Linee ed Archi
+ PolyArc PA ;
+ pCrvCompo->ToLoc( frface) ; // interpolazione nel piano XY
+ pCrvCompo->ApproxWithArcsEx( 500 * EPS_SMALL, ANG_TOL_STD_DEG, 20.0, PA) ;
+ pCrvCompo->Clear() ;
+ pCrvCompo->FromPolyArc( PA) ;
+ pCrvCompo->ToGlob( frface) ;
+
+ // le curve ricavate dalle TriMesh possono presentare dei piccoli errori di approssimazione che non le rendono
+ // del tutto piane... per sicurezza le proietto sul piano creato
+ double dS, dE ;
+ pCrvCompo->GetDomain( dS, dE) ;
+ PtrOwner pCrv_c( pCrvCompo->CopyParamRange( dS, dE)) ; // da CurveCompo a Curve
+ if ( IsNull( pCrv_c) || ! pCrv_c->IsValid())
+ return false ;
+ PtrOwner pCrv_proj( ProjectCurveOnPlane( *pCrv_c, plFace)) ;
+ // secondo controllo per l'area e il perimetro
+ double dAreaCheck = SQ_EPS_SMALL, dLenCheck = EPS_SMALL ;
+ Plane3d plCheck ;
+ if ( ! IsNull( pCrv_proj) && pCrv_proj->IsClosed()) {
+ pCrv_proj->GetArea( plCheck, dAreaCheck) ;
+ pCrv_proj->GetLength( dLenCheck) ;
+ if ( dAreaCheck < 50000 * SQ_EPS_SMALL || dLenCheck < 50 * EPS_SMALL) {
+ bSkip = true ;
+ return true ;
+ }
+ }
+
+ // sostituisco la curva ed esco
+ pCrvCompo->Clear() ;
+ pCrvCompo->CopyFrom( pCrv_proj) ;
+ bSkip = false ;
+ return true ;
+}
+
+//----------------------------------------------------------------------------
+static bool
+GetSfrByStm( const ISurfTriMesh* pStm, ISurfFlatRegion* pSfr, const Plane3d plFace)
+{
+ // controllo validità dei parametri
+ if ( pStm == nullptr || ! pStm->IsValid() || ! plFace.IsValid())
+ return false ;
+
+ // creo un Frame per il sistema di Riferimento Locale
+ Frame3d frFace ; frFace.Set( plFace.GetPoint(), plFace.GetVersN()) ;
+ if ( ! frFace.IsValid())
+ return false ;
+
+ // creo la FlatRegion da resitutiure
+ SurfFlatRegionByContours SrfChunkDef ;
+
+ // recupero i Loop della TriMesh salvandoli in un vettore di PolyLine
+ POLYLINEVECTOR vPl ;
+ pStm->GetLoops( vPl) ;
+
+ // per ogni PolyLine...
+ for ( int i = 0 ; i < ( int)vPl.size() ; ++ i) {
+ // recupero la curva composita
+ PolyLine PL = vPl[i] ;
+ PtrOwner pCrvCompo( CreateCurveComposite()) ;
+ pCrvCompo->FromPolyLine( PL) ;
+
+ // sistemazione varie per la curva ( per creare i loops della FlatRegion)
+ bool bSkip ; // flag per indicare se la curva è accettabile
+ if ( ! ImproveCurve( pCrvCompo, frFace, plFace, bSkip))
+ return false ;
+ if ( ! bSkip)
+ SrfChunkDef.AddCurve( Release( pCrvCompo)) ; // aggiungo la curva
+ }
+
+ // recupero la FlatRegion ( controllandone la validità)
+ PtrOwner pSrfByCurves( SrfChunkDef.GetSurf()) ;
+ if ( IsNull( pSrfByCurves) || ! pSrfByCurves->IsValid() || pSrfByCurves->GetChunkCount() == 0)
+ return true ;
+
+ // restituisco la FlatRegion
+ pSfr->Clear() ;
+ pSfr->CopyFrom( pSrfByCurves) ;
+ return pSfr != nullptr && pSfr->IsValid() ;
+}
+
+//----------------------------------------------------------------------------
+static bool
+CheckSimpleOverlap( const ICurve* pCrv, const ICurveComposite* pCrvOri, int& nStat, double dToll)
+{
+ // === controllo se una curva semplice è sufficientemente vicina ad una curva composita ===
+ // controllo dei parametri
+ if (( pCrv == nullptr || pCrvOri == nullptr || dToll < EPS_SMALL))
+ return false ;
+ nStat = 1 ; // 0 -> no overlap | 1 -> overlap
+
+ // prendo nMax + 1 punti sulla curva semplice...
+ const double nMAX = 10.0 ;
+ for ( int i = 0 ; i <= nMAX ; ++i) {
+ double dPar = i / nMAX ;
+ Point3d ptC ; pCrv->GetPointD1D2( dPar, ICurve::FROM_PLUS, ptC) ;
+ if ( ! pCrvOri->IsPointOn( ptC, dToll)) { // se un punto non è vicino, esco
+ nStat = 0 ;
+ return true ;
+ }
+ }
+
+ return true ;
+}
+
+//----------------------------------------------------------------------------
+static bool
+SetTmpPropByOverlap( ICurveComposite* pCrvCheck, const int nInd, const ICurveComposite* pCrvOri, int& nStat,
+ double dToll)
+{
+ // === Data una sottocurva di una CurveComposite e un'altra composita con le proprietà impostate, spezzo la
+ // sottocurva in tratti di TmpProps uniformi appropriati ===
+ // controllo dei parametri
+ if (( pCrvCheck == nullptr || pCrvOri == nullptr || nInd < 0 || nInd > pCrvCheck->GetCurveCount()
+ || dToll < EPS_SMALL))
+ return false ;
+ nStat = 1 ; // 0 -> no overlap | 1 -> overlap | 2 -> undefined
+
+ // ricavo la curva da controllare
+ PtrOwner pCrv( GetCurveComposite( pCrvCheck->CopyParamRange( nInd, nInd + 1))) ;
+ if ( IsNull( pCrv))
+ return false ;
+
+ // controllo se la curva fa overlap ( mediante vicinanza)
+ if ( ! CheckSimpleOverlap( pCrv, pCrvOri, nStat, dToll))
+ return false ;
+ if ( nStat == 0)
+ return true ;
+
+ // ricavo i parametri sulla curva originale di vicinanza
+ double dUS = 0 ; double dUE = 0 ;
+ Point3d ptS ; pCrv->GetStartPoint( ptS) ;
+ Point3d ptE ; pCrv->GetEndPoint( ptE) ;
+ pCrvOri->GetParamAtPoint( ptS, dUS, dToll) ;
+ pCrvOri->GetParamAtPoint( ptE, dUE, dToll) ;
+
+ // ricavo una approssimazione adeguata dei paramtri dUS e dUE
+ int nRealDUS = ( int)floor( dUS) ;
+ int nRealDUE = ( int)ceil( dUE) ;
+ if ( ceil( dUS) - dUS < EPS_SMALL)
+ nRealDUS = ( int)ceil( dUS) ;
+ if ( dUE - floor( dUE) < EPS_SMALL)
+ nRealDUE = ( int)floor( dUE) ;
+ if ( nRealDUS == pCrvOri->GetCurveCount())
+ nRealDUS = 0 ;
+
+ // controllo se la vicinanza è relativa a più curve sulla originale con stesse temp prop
+ bool bHasAllSameProp = true ;
+ int nProp_prec ; pCrvOri->GetCurveTempProp( nRealDUS, nProp_prec, 0) ;
+ for ( int u = nRealDUS + 1 ; u < nRealDUE && bHasAllSameProp ; ++ u) {
+ int nProp_act ;
+ pCrvOri->GetCurveTempProp( u, nProp_act, 0) ;
+ if ( nProp_prec != nProp_act)
+ bHasAllSameProp = false ;
+ }
+ if ( bHasAllSameProp) { // se tutte le curve hanno tmpProp uguale...
+ int nCrv = nRealDUS ;
+ int nProp0 = 0 ; pCrvOri->GetCurveTempProp( nCrv, nProp0, 0) ;
+ int nProp1 = 0 ; pCrvOri->GetCurveTempProp( nCrv, nProp1, 1) ;
+ pCrvCheck->SetCurveTempProp( nInd, nProp0, 0) ;
+ //pCrvCheck->SetCurveTempProp( nInd, nProp1, 1) ;
+ return true ;
+ }
+
+ // copio le sottocurve toccate
+ PtrOwner pCrvOriRange( CloneCurveComposite( pCrvOri)) ;
+ if ( ! pCrvOriRange->TrimStartEndAtParam( floor( dUS), ceil( dUE)))
+ pCrvOriRange->Clear() ;
+
+ if ( ! pCrvOriRange->IsValid()) {
+ nStat = 2 ;
+ return true ;
+ }
+
+ // curva finale da resitutire ( da semplice Curve a CurveComposite)
+ PtrOwner pCrvFinal( CreateCurveComposite()) ;
+ if ( IsNull( pCrvFinal))
+ return false ;
+
+ // per ogni sottocurva...
+ double dUProjS = 0 ; double dUProjE = 0 ;
+ for ( int u = 0 ; u < pCrvOriRange->GetCurveCount() ; ++ u) {
+
+ Point3d ptCrvOriE ;
+ pCrvOriRange->GetPointD1D2( u + 1, ICurve::FROM_MINUS, ptCrvOriE) ;
+
+ if ( u == 0)
+ dUProjS = 0 ;
+ else
+ dUProjS = dUProjE ;
+
+ if ( u == pCrvOriRange->GetCurveCount() - 1)
+ dUProjE = 1 ;
+ else
+ pCrv->GetParamAtPoint( ptCrvOriE, dUProjE, dToll) ;
+
+ PtrOwner pCrvRange( GetCurveComposite( pCrv->CopyParamRange( dUProjS, dUProjE))) ;
+ if ( ! IsNull( pCrvRange) && pCrvRange->IsValid()) {
+ int nProp0 = 0 ; pCrvOriRange->GetCurveTempProp( u, nProp0, 0) ;
+ int nProp1 = -1 ; pCrvOriRange->GetCurveTempProp( u, nProp1, 1) ;
+ pCrvRange->SetCurveTempProp( 0, nProp0, 0) ;
+ pCrvRange->SetCurveTempProp( 0, nProp1, 1) ;
+ pCrvFinal->AddCurve( Release( pCrvRange)) ;
+ }
+ else {
+ nStat = 2 ;
+ return true ;
+ }
+ }
+
+ // controllo che la CurveComposite ottenuta sia valida e coerente rispetto all'originale ...
+ if ( ! IsNull( pCrvFinal) && pCrvFinal->GetCurveCount() > 0 && pCrvFinal->IsValid()) {
+ Point3d ptSCheck ; Point3d ptECheck ;
+ pCrvFinal->GetStartPoint( ptSCheck) ;
+ pCrvFinal->GetEndPoint( ptECheck) ;
+ if ( ! AreSamePointApprox( ptS, ptSCheck) || ! AreSamePointApprox( ptE, ptECheck))
+ nStat = 2 ;
+ }
+ else
+ nStat = 2 ;
+
+ // ritorno la curva modificata
+ if ( nStat != 2) {
+ pCrvFinal->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ;
+ PtrOwner pCrvToReturn( CreateCurveComposite()) ;
+ if ( IsNull( pCrvToReturn))
+ return false ;
+
+ // primo tratto di curva della Composita iniziale
+ PtrOwner pCrvA( GetCurveComposite( pCrvCheck->CopyParamRange( 0, nInd))) ;
+ if ( ! IsNull( pCrvA) && pCrvA->GetCurveCount() > 0 && pCrvA->IsValid()) {
+ if ( ! pCrvToReturn->AddCurve( Release( pCrvA))) {
+ nStat = 2 ;
+ return true ;
+ }
+ }
+ // tratto corrente di curva con proprietà impostate
+ if ( ! pCrvToReturn->AddCurve( Release( pCrvFinal))) {
+ nStat = 2 ;
+ return true ;
+ }
+
+ // ultimo tratto di curva della Composita iniziale
+ PtrOwner pCrvB( GetCurveComposite( pCrvCheck->CopyParamRange( nInd + 1, pCrvCheck->GetCurveCount()))) ;
+ if ( ! IsNull( pCrvB) && pCrvB->GetCurveCount() > 0 && pCrvB->IsValid())
+ if( ! pCrvToReturn->AddCurve( Release( pCrvB))) {
+ nStat = 2 ;
+ return true ;
+ }
+
+ if ( pCrvToReturn->GetCurveCount() > 0 && pCrvToReturn->IsValid()) {
+ // imposto i parametri originali alla nuova curva
+ double dThick ; pCrvCheck->GetThickness( dThick) ;
+ Vector3d vtExtr ; pCrvCheck->GetExtrusion( vtExtr) ;
+ int nProp0 = pCrvCheck->GetTempProp( 0) ;
+ int nProp1 = pCrvCheck->GetTempProp( 1) ;
+ pCrvCheck->Clear() ;
+ pCrvCheck->AddCurve( Release( pCrvToReturn)) ;
+ pCrvCheck->SetExtrusion( vtExtr ) ;
+ pCrvCheck->SetThickness( dThick) ;
+ pCrvCheck->SetTempProp( nProp0, 0) ;
+ pCrvCheck->SetTempProp( nProp1, 1) ;
+ }
+ else
+ nStat = 2 ;
+ }
+
+ return true ;
+}
+
+//----------------------------------------------------------------------------
+static bool
+GetOCCrvsWithProps( const ISurfTriMesh& StmOrig, int nFaceInd, ICRVCOMPOPOVECTOR& vCrvsWithTmpProps)
+{
+ // === Data una TriMesh e una sua faccia, stabilire i lati aperti e chiusi dalle adiacenze ===
+ // controllo validità dei parametri
+ if ( ! StmOrig.IsValid())
+ return false ;
+ vCrvsWithTmpProps.clear() ;
+ // recupero i contorni della faccia selezionata
+ POLYLINEVECTOR vPL ;
+ StmOrig.GetFacetLoops( nFaceInd, vPL) ;
+ if ( vPL.empty())
+ return false ;
+ // recupero la normale esterna della faccia
+ Vector3d vtN ;
+ if ( ! StmOrig.GetFacetNormal( nFaceInd, vtN))
+ return false ;
+ // creo la curva a partire dei loop
+ for ( int i = 0 ; i < int( vPL.size()) ; i++) {
+ PtrOwner pCrvCompo( CreateCurveComposite()) ;
+ pCrvCompo->FromPolyLine( vPL[i]) ;
+ if ( ! pCrvCompo->IsValid())
+ return false ;
+ // imposto a 0 tutti i lati della pCrvCompo
+ for ( int u = 0 ; u < pCrvCompo->GetCurveCount() ; ++ u)
+ pCrvCompo->SetCurveTempProp( u, 0, 0) ;
+ // determino eventuali lati aperti e aggiorno proprietà del contorno
+ int nInd = 0 ;
+ double dPar ;
+ bool bFound = vPL[i].GetFirstU( dPar, true) ;
+ while ( bFound) {
+ // recupero il flag
+ int nFlag = int( dPar) ;
+ // se non c'è nulla di adiacente, lato aperto
+ if ( nFlag == SVT_NULL) {
+ pCrvCompo->SetCurveTempProp( nInd, 1, 0) ; // --> lato aperto
+ pCrvCompo->SetCurveTempProp( nInd, -1, 1) ; // --> nessuna faccia adiacente
+ }
+ // altrimenti verifico se la faccia adiacente forma diedro convesso o concavo
+ else {
+ bool bAdjac ;
+ Point3d ptP1, ptP2 ;
+ double dAng ;
+ if ( ! StmOrig.GetFacetsContact( nFaceInd, nFlag, bAdjac, ptP1, ptP2, dAng))
+ dAng = - ANG_RIGHT ;
+ if ( dAng > - EPS_ANG_SMALL) {
+ pCrvCompo->SetCurveTempProp( nInd, 1, 0) ; // --> lato aperto
+ pCrvCompo->SetCurveTempProp( nInd, -1, 1) ; // --> nessuna faccia adiacente
+ }
+ else
+ // salvo come prop 1 la faccia adiacente
+ pCrvCompo->SetCurveTempProp( nInd, nFlag, 1) ; // --> il lato chiuso è 0 per default
+ }
+ // passo al successivo
+ ++nInd ;
+ bFound = vPL[i].GetNextU( dPar, true) ;
+ }
+ // assegno l'estrusione dalla normale alla faccia
+ pCrvCompo->SetExtrusion( vtN) ;
+ // unisco le eventuali parti allineate ( mantenendo le proprietà)
+ pCrvCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ;
+ // aggiorno la superficie con il loop
+ vCrvsWithTmpProps.emplace_back( Release( pCrvCompo)) ;
+ }
+ return true ;
+}
+
+//----------------------------------------------------------------------------
+static bool
+SewNewStmFacesWithTmpProps( const ISurfFlatRegion& SfrOCCurves, const Plane3d plFace, ISurfTriMesh* pStmFinal)
+{
+ // controllo dei parametri
+ if ( ! SfrOCCurves.IsValid())
+ return false ;
+
+ // normale dell faccia
+ Vector3d vtN = plFace.GetVersN() ;
+
+ // Creo la TriMesh derivante dai lati chiusi ( estrusione come la normale)
+ // scorro tutti i Loop della FlatRegion cercando le curva che derivano da proiezioni
+ for ( int c = 0 ; c < SfrOCCurves.GetChunkCount() ; ++ c) {
+ for ( int l = 0 ; l < SfrOCCurves.GetLoopCount( c) ; ++ l) {
+ // ricavo il Loop
+ PtrOwner pCrvCompoLoop( ConvertCurveToComposite( SfrOCCurves.GetLoop( c, l))) ;
+ if ( IsNull( pCrvCompoLoop) || ! pCrvCompoLoop->IsValid())
+ return false ;
+ // scorro le sue sottocurve
+ for ( int u = 0 ; u < pCrvCompoLoop->GetCurveCount() ; ++ u) {
+ const ICurve* pCrv_u = pCrvCompoLoop->GetCurve( u) ;
+ if ( pCrv_u == nullptr)
+ return false ;
+ if ( pCrv_u->GetTempProp( 0) == 0) {
+ // se curve chiuse e derivante da una proeizione...
+ PtrOwner pStmCurrExtr( GetSurfTriMeshByExtrusion( pCrv_u, - 1 * vtN, false)) ;
+ if ( IsNull( pStmCurrExtr) || ! pStmCurrExtr->IsValid())
+ return false ;
+ // controllo l'orientamento corretto della nuova faccia
+ Vector3d vtNCurr ;
+ if ( ! pStmCurrExtr->GetFacetNormal( 0, vtNCurr))
+ return false ;
+ double dAng ;
+ if ( vtN.GetAngle( vtNCurr, dAng) && dAng > 0)
+ pStmCurrExtr->Invert() ;
+ // aggiungo alla superficie
+ if ( ! pStmFinal->DoSewing( *pStmCurrExtr))
+ return false ;
+ }
+ }
+ }
+ }
+
+ return true ;
+}
+
+
+//----------------------------------------------------------------------------
+static bool
+AddClosedEdges( const ISurfTriMesh& StmOrig, int nFaceInd, const ISurfFlatRegion& pSfrOrig,
+ const Plane3d plFace, ISurfTriMesh* pStmFinal)
+{
+ // controllo validità dei parametri
+ if ( ! StmOrig.IsValid() || pStmFinal == nullptr || ! pStmFinal->IsValid())
+ return false ;
+
+ // creo un vettore di curve con Flag di lato aperto a partire dalla faccia originale
+ ICRVCOMPOPOVECTOR vCrvWithTmpProps ;
+ if ( ! GetOCCrvsWithProps( StmOrig, nFaceInd, vCrvWithTmpProps))
+ return false ;
+
+ // creo la superficie finale da restituire
+ SurfFlatRegionByContours SfrByC ;
+
+ // scorro tutti i loop della FlatRegion della superficie ottenuta dopo la proiezione
+ for ( int c = 0 ; c < pSfrOrig.GetChunkCount() ; ++ c) {
+ for ( int l = 0 ; l < pSfrOrig.GetLoopCount( c) ; ++ l) {
+ // ricavo la curva composita associata al loop corrente
+ PtrOwner pCrvCompoLoop( ConvertCurveToComposite( pSfrOrig.GetLoop( c, l))) ;
+ if ( IsNull( pCrvCompoLoop) || ! pCrvCompoLoop->IsValid())
+ return false ;
+ // scorro ogni curva del loop ottenuto
+ for ( int u = 0 ; u < pCrvCompoLoop->GetCurveCount() ; ++ u) {
+ bool bFound = false ;
+ for ( int i = 0 ; i < int( vCrvWithTmpProps.size()) && !bFound ; ++ i) {
+ int nStat = 0 ;
+ if ( SetTmpPropByOverlap( pCrvCompoLoop, u, vCrvWithTmpProps[i], nStat, 50 * EPS_SMALL) && nStat == 1)
+ bFound = true ;
+ }
+ // se overlap non trovato, allora la curva deriva da una proiezione, quindi chiusa
+ if ( ! bFound) {
+ pCrvCompoLoop->SetCurveTempProp( u, 0, 0) ; // <---- curva chiusa
+ pCrvCompoLoop->SetCurveTempProp( u, -2, 1) ; // <---- derivante da proiezione
+ }
+ }
+ // inserisco la curva con le proprietà definite
+ SfrByC.AddCurve( Release( pCrvCompoLoop)) ;
+ }
+ }
+
+ // recupero la FlatRegion con le curve impostate
+ PtrOwner pSfrWithTmpProps( SfrByC.GetSurf()) ;
+ if ( IsNull( pSfrWithTmpProps) || ! pSfrWithTmpProps->IsValid())
+ return false ;
+
+ // creo la TriMesh finale da restituire ed esco
+ return SewNewStmFacesWithTmpProps( *pSfrWithTmpProps, plFace, pStmFinal) ;
+}
+
+
+//----------------------------------------------------------------------------
+bool
+SubtractProjectedFacesOnStmFace( const ISurfTriMesh& Stm, int nFaceInd,
+ ISURFTMPOVECTOR& vStmOthers, INTVECTOR& vFIndOthers, bool bOCFlag,
+ bool& bExistProjection, ISurfTriMesh*& pStmRes, int& nNewFaceNbr)
+{
+ // verifico validità della superificie originale
+ if ( ! Stm.IsValid())
+ return false ;
+
+ // ricavo la faccia su cui togliere le proiezioni
+ PtrOwner pStm_face( Stm.CloneFacet( nFaceInd)) ;
+ if ( IsNull( pStm_face) || ! pStm_face->IsValid())
+ return false ;
+
+ // imposto valori di ritorno di default
+ bExistProjection = false ;
+ nNewFaceNbr = 1 ;
+ pStmRes = CreateSurfTriMesh() ;
+ pStmRes->CopyFrom( pStm_face) ;
+
+ // dimensione dei vettori passati come parametri
+ int nVStm_size = ( int)vStmOthers.size() ;
+ int nVId_size = ( int)vFIndOthers.size() ;
+ // se vettori di dimensioni diverse -> incoerenza
+ if ( nVStm_size != nVId_size)
+ return false ;
+ // se entrambi sono vuoti, alora considero di proiettare tutte le altre facce della TriMesh
+ bool bIsSize0 = ( nVStm_size == 0) ;
+ if ( bIsSize0) {
+ // se entrambi i vettori sono vuoti, allora considero da proiettare tutte le altre facce della TriMesh
+ PtrOwner pStmNoSelFace( Stm.Clone()) ;
+ if ( IsNull( pStmNoSelFace) || ! pStmNoSelFace->IsValid())
+ return false ;
+ // se la superficie ha solo una faccia e cerco di toglierla, allora non devo proiettare nulla...
+ if ( pStmNoSelFace->GetFacetCount() == 1)
+ return true ;
+ // rimuovo la faccia da proiettare
+ if ( ! pStmNoSelFace->RemoveFacet( nFaceInd))
+ return false ;
+ // controllo la validità di questa operazione
+ if ( IsNull( pStmNoSelFace) || ! pStmNoSelFace->IsValid())
+ return false ;
+ // modifico il vettore delle TriMesh e delle loro facce
+ vStmOthers.emplace_back( Release( pStmNoSelFace)) ;
+ nVStm_size = 1 ;
+ // NB. E' adottata questa strategia per evitare di proiettare un numero elevato di facce dovuto alla presenza
+ // di archi; calcolo la GetSilhouette dell'intero contorno e non come unione delle singole facce proiettate
+ }
+
+ // creo il sistema di riferimento ( inerente alla faccia selezionata)
+ Point3d ptORIG ;
+ Vector3d vtN ;
+ if ( ! pStm_face->GetCentroid( ptORIG) || // ricavo origine
+ ! pStm_face->GetFacetNormal( 0, vtN)) // ricavo normale
+ return false ;
+ Frame3d frFace ; frFace.Set( ptORIG, vtN) ;
+ if ( ! frFace.IsValid())
+ return false ;
+
+ // creo un piano passante per la faccia selezionata ( di normale inversa per il taglio)
+ // ( tutto ciò che sta nel semipiano negativo della faccia selezionata, non viene proiettato ma tagliato)
+ Plane3d plFace ;
+ plFace.Set( ptORIG, -vtN) ;
+ if ( ! plFace.IsValid())
+ return false ;
+
+ // superficie finale della proeizione
+ PtrOwner pSfr_proj( CreateSurfFlatRegion()) ;
+ if ( IsNull( pSfr_proj))
+ return false ;
+ bool bExistProj = false ; // flag per indicare se almeno un triangolo è stato proiettato
+
+ // scorro le parti di superfici da proiettare...
+ for ( int t = 0 ; t < nVStm_size ; ++ t) {
+ // proiezione corrente
+ PtrOwner pStm_CurrProj( CreateSurfTriMesh()) ;
+ if ( IsNull( pStm_CurrProj))
+ return false ;
+ // *** se sono stati passati alla funzione vettori non vuoti, allora pStm_CurrProj è la faccia
+ // *** corrente da proiettare
+ if ( ! bIsSize0) {
+ // se la faccia da proiettare è perpendicolare alla faccia selezionata, non la considero
+ Vector3d vtN_curr ;
+ if ( ! vStmOthers[t]->GetFacetNormal( vFIndOthers[t], vtN_curr) ||
+ abs( vtN_curr * vtN) < 5 * EPS_SMALL) // <--- | prodotto scalare | < 5 * EPS_SMALL
+ continue ;
+ // recupero la faccia da proiettare ( controllando la sua validità)
+ pStm_CurrProj.Set( vStmOthers[t]->CloneFacet( vFIndOthers[t])) ;
+ if ( IsNull( pStm_CurrProj) || ! pStm_CurrProj->IsValid())
+ return false ;
+ }
+ // *** se sono stati passati alla funzione vettori vuoti allora pStm_CurrProj contiene tutta la TriMesh
+ // *** meno la faccia scelta
+ else {
+ PtrOwner pStmForProj( CloneSurfTriMesh( vStmOthers[0])) ;
+ PtrOwner pStmForProj_noPerpFaces( CreateSurfTriMesh()) ;
+ if ( IsNull( pStmForProj) || ! pStmForProj->IsValid() || IsNull( pStmForProj_noPerpFaces))
+ return false ;
+ StmFromTriangleSoup StmFts ;
+ StmFts.Start() ;
+ // rimuovo le facce perpendicolari
+ for ( int f = 0 ; f < pStmForProj->GetFacetCount() ; ++ f) {
+ Vector3d vtN_curr ;
+ if ( pStmForProj->GetFacetNormal( f, vtN_curr) && abs( vtN_curr * vtN) > 5 * EPS_SMALL) {
+ PtrOwner pStm_face( pStmForProj->CloneFacet( f)) ;
+ if ( IsNull( pStm_face) || ! pStm_face->IsValid())
+ return false ;
+ Triangle3d Tria ;
+ int nT = pStm_face->GetFirstTriangle( Tria) ;
+ while ( nT != SVT_NULL) {
+ // inserisco il triangolo nella nuova superficie
+ StmFts.AddTriangle( Tria) ;
+ // passo al triangolo successivo
+ nT = pStm_face->GetNextTriangle( nT, Tria) ;
+ }
+ }
+ }
+ StmFts.End() ;
+ pStmForProj_noPerpFaces.Set( StmFts.GetSurf()) ;
+ // se la superficie senza le facce perpendicolari non è valida, allora ho finito
+ if ( ! pStmForProj_noPerpFaces->IsValid())
+ return true ;
+ // sistemo
+ pStmForProj_noPerpFaces->Repair() ;
+ // sostituisco
+ pStm_CurrProj.Set( Release( pStmForProj_noPerpFaces)) ;
+ }
+
+ // taglio la superficie con il piano creato ( la proiezione esclude le parti nel semipiano negativo)
+ if ( ! pStm_CurrProj->Cut( plFace, true))
+ return false ;
+ // controllo la validità di questa operazione ( la faccia potrebbe essere tutta nel semipiano negativo)
+ if ( IsNull( pStm_CurrProj) || ! pStm_CurrProj->IsValid() || pStm_CurrProj->GetTriangleCount() == 0)
+ continue ;
+ // recupero la PolyLine della Silhouette
+ POLYLINEVECTOR vPL ;
+ if ( ! pStm_CurrProj->GetSilhouette( vtN, 100 * EPS_SMALL, vPL, true))
+ return false ;
+ // converto le curve in composite
+ // NB. Potrei ottenere più curve, quindi creo la FlatRegion associata
+ SurfFlatRegionByContours sfrBCProj_face ;
+ bool bValidCurrProj = false ;
+ for ( int i = 0 ; i < int( vPL.size()) ; ++ i) {
+ PtrOwner pCrvCompo( CreateCurveComposite()) ;
+ if ( IsNull( pCrvCompo))
+ return false ;
+ pCrvCompo->FromPolyLine( vPL[i]) ;
+ bool bSkip = true ; // flag per indicare se la curva è valida
+ if ( ! ImproveCurve( pCrvCompo, frFace, plFace, bSkip))
+ return false ;
+ // se curva ammissibile, creo la sua FlatRegion
+ if ( ! bSkip) {
+ bValidCurrProj = true ;
+ sfrBCProj_face.AddCurve( Release( pCrvCompo)) ;
+ bExistProj = true ;
+ }
+ }
+ // se proeizione non valida, allora passo all'entità successiva
+ if ( ! bValidCurrProj)
+ continue ;
+ // ricavo la FlatRegion associata alla proiezione delle faccia
+ PtrOwner pSfr_proj_faceCurr( sfrBCProj_face.GetSurf()) ;
+ if ( IsNull( pSfr_proj_faceCurr) || ! pSfr_proj_faceCurr->IsValid())
+ return false ;
+ // inverto se necessario
+ if ( AreOppositeVectorApprox( pSfr_proj_faceCurr->GetNormVersor(), vtN))
+ pSfr_proj_faceCurr->Invert() ;
+ // la sommo alla regione di proeizione globale
+ if ( ! pSfr_proj->IsValid() || pSfr_proj->GetChunkCount() == 0)
+ pSfr_proj.Set( Release( pSfr_proj_faceCurr)) ;
+ else
+ if ( ! pSfr_proj->Add( *pSfr_proj_faceCurr))
+ return false ;
+ }
+
+ // se non c'è nulla d proiettare e flag bOCFlag false, allora esco
+ if ( ! bExistProj && ! bOCFlag)
+ return true ;
+
+ // FlatRegion associata alla faccia della TriMesh selezionata
+ PtrOwner pSfr_face( CreateSurfFlatRegion()) ;
+ if ( IsNull( pSfr_face) || ! GetSfrByStm( pStm_face, pSfr_face, plFace) || ! pSfr_face->IsValid())
+ return false ;
+ // per sicurezza controllo la coerenza con le normali ( per fare la sottrazione)
+ if ( AreOppositeVectorApprox( pSfr_face->GetNormVersor(), vtN))
+ pSfr_face->Invert() ;
+
+ // superficie finale da restituire
+ PtrOwner pStm_final( CreateSurfTriMesh()) ;
+ if ( IsNull( pStm_final))
+ return false ;
+
+ // *** se la proiezione esiste...
+ if ( bExistProj) {
+ // controllo validità della FlatRegion di proiezione globale
+ if ( IsNull( pSfr_proj) || ! pSfr_proj->IsValid())
+ return false ;
+ // ho una proiezione ...
+ bExistProjection = true ;
+ // per sicurezza controllo la coerenza con le normali ( per fare la sottrazione)
+ if ( AreOppositeVectorApprox( pSfr_proj->GetNormVersor(), vtN))
+ pSfr_proj->Invert() ;
+ // sottraggo le FlatRegions ( FlatRegion della faccia selezionata \ FlatRegion proiezione)
+ if ( ! pSfr_face->Subtract( *pSfr_proj))
+ return false ;
+ // controllo validità della sottrazione
+ if ( IsNull( pSfr_face) || ! pSfr_face->IsValid() || pSfr_face->GetChunkCount() == 0) {
+ // la proiezione copre completamente la faccia selezionata
+ delete( pStmRes) ;
+ pStmRes = nullptr ;
+ nNewFaceNbr = 0 ;
+ return true ;
+ }
+ // aggiorno il numero di facce creato
+ nNewFaceNbr = pSfr_face->GetChunkCount() ;
+ }
+
+ // riconverto la FlatRegion in TriMesh ( per restituirla)
+ const ISurfTriMesh* pStm_tmp = pSfr_face->GetAuxSurf() ;
+ if ( pStm_tmp == nullptr || ! pStm_tmp->IsValid())
+ return false ;
+ pStm_final.Set( pStm_tmp->Clone()) ;
+ if ( IsNull( pStm_final) || ! pStm_final->IsValid())
+ return false ;
+
+ // se richiesto aggiugno delle facce sui lati chiusi
+ if ( bOCFlag)
+ if ( ! AddClosedEdges( Stm, nFaceInd, *pSfr_face, plFace, pStm_final))
+ return false ;
+
+ // assegno i valori di ritorno della funzione ed esco
+ pStmRes->CopyFrom( pStm_final) ;
+ return pStmRes->IsValid() && pStmRes->GetTriangleCount() > 0 ;
+}
+
diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp
index 76ad9e9..1e320fe 100644
--- a/SurfTriMesh.cpp
+++ b/SurfTriMesh.cpp
@@ -1069,7 +1069,7 @@ SurfTriMesh::MarchOneTria( int& nT, int& nV, int nTimeStamp,
//----------------------------------------------------------------------------
bool
-SurfTriMesh::GetSilhouette( const Vector3d& vtDir, double dTol, POLYLINEVECTOR& vPL) const
+SurfTriMesh::GetSilhouette( const Vector3d& vtDir, double dTol, POLYLINEVECTOR& vPL, bool bAllTria) const
{
// Verifico lo stato
if ( m_nStatus != OK)
@@ -1166,17 +1166,20 @@ SurfTriMesh::GetSilhouette( const Vector3d& vtDir, double dTol, POLYLINEVECTOR&
int nT = GetFirstTriangle( Tria) ;
while ( nT != SVT_NULL) {
// verifico la normale e il triangolo proiettato
- if ( Tria.GetN() * vtVers > EPS_ZERO &&
+ if ( ( ( bAllTria && abs( Tria.GetN() * vtVers) > EPS_ZERO) ||
+ ( ! bAllTria && Tria.GetN() * vtVers > EPS_ZERO)) &&
Tria.Scale( frOCS, 1, 1, 0) && Tria.GetSqMinHeight() > SQ_EPS_SMALL) {
PtrOwner pSfrTria( GetSurfFlatRegionFromTriangle( Tria)) ;
if ( ! IsNull( pSfrTria)) {
+ if ( bAllTria && Tria.GetN() * vtVers < 0)
+ pSfrTria->Invert() ;
pSfrTria->Offset( dTol, ICurve::OFF_FILLET) ;
if ( IsNull( pSfr))
pSfr.Set( pSfrTria) ;
else
pSfr->Add( *pSfrTria) ;
}
- }
+ }
// passo al successivo
nT = GetNextTriangle( nT, Tria) ;
}
diff --git a/SurfTriMesh.h b/SurfTriMesh.h
index 6ae2946..8390d3a 100644
--- a/SurfTriMesh.h
+++ b/SurfTriMesh.h
@@ -261,7 +261,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
bool GetTriangleSmoothNormals( int nId, TriNormals3d& TNrms) const override ;
SurfTriMesh* CloneTriangle( int nT) const override ;
bool GetLoops( POLYLINEVECTOR& vPL) const override ;
- bool GetSilhouette( const Vector3d& vtDir, double dTol, POLYLINEVECTOR& vPL) const override ;
+ bool GetSilhouette( const Vector3d& vtDir, double dTol, POLYLINEVECTOR& vPL, bool bAllTria = false) const override ;
int GetFacetCount( void) const override ;
int GetFacetSize( void) const override
{ return int( m_vFacet.size()) ; }