Files
EgtGeomKernel/SubtractProjectedFacesOnStmFace.cpp
Dario Sassi cd48e2de3b EgtGeomKernel :
- varie correzioni ortografiche.
2025-11-15 11:00:21 +01:00

732 lines
29 KiB
C++

//----------------------------------------------------------------------------
// 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 "CurveComposite.h"
#include "SurfFlatRegion.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 <array>
using namespace std ;
//----------------------------------------------------------------------------
// Proiezione sottrazione di facce di TriMesh su una faccia di TriMesh
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
static bool
ImproveCurve( CurveComposite* 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<ICurve> pCrv_c( pCrvCompo->CopyParamRange( dS, dE)) ; // da CurveCompo a Curve
if ( IsNull( pCrv_c) || ! pCrv_c->IsValid())
return false ;
PtrOwner<ICurve> 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<CurveComposite> pCrvCompo( CreateBasicCurveComposite()) ;
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<ISurfFlatRegion> 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<ICurveComposite> 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<ICurveComposite> 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<CurveComposite> pCrvFinal( CreateBasicCurveComposite()) ;
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<CurveComposite> pCrvRange( GetBasicCurveComposite( 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 ( 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<CurveComposite> pCrvToReturn( CreateBasicCurveComposite()) ;
if ( IsNull( pCrvToReturn))
return false ;
// primo tratto di curva della Composita iniziale
PtrOwner<CurveComposite> pCrvA( GetBasicCurveComposite( 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<CurveComposite> pCrvB( GetBasicCurveComposite( 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 dai loop
for ( int i = 0 ; i < int( vPL.size()) ; i++) {
PtrOwner<CurveComposite> pCrvCompo( CreateBasicCurveComposite()) ;
if ( IsNull( pCrvCompo) || ! pCrvCompo->FromPolyLine( vPL[i]) || ! 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<CurveComposite> pCrvCompoLoop( ConvertCurveToBasicComposite( 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<ISurfTriMesh> 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<CurveComposite> pCrvCompoLoop( ConvertCurveToBasicComposite( 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<ISurfFlatRegion> 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, 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<ISurfTriMesh> 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() ;
bool bIsSize0 = ( nVStm_size == 0) ;
if ( bIsSize0) {
// se il vettore delle Trimesh dal proiettare è vuoto, la proeizione è fatta con le altre facce delle TriMesh
PtrOwner<ISurfTriMesh> 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 ; // il flag BOCFlag non importa, ho tutti lati aperti
// 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 ;
// ricavo il Box3D della faccia selezionata nel frame della faccia stessa
Frame3d frH = frFace ; frH.Invert() ;
BBox3d BBoxSelFace ;
if ( ! pStm_face->GetBBox( frH, BBoxSelFace))
return false ;
// superficie finale della proeizione
PtrOwner<SurfFlatRegion> pSfr_proj( CreateBasicSurfFlatRegion()) ;
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) {
// TriMesh da proiettare
PtrOwner<SurfTriMesh> pStm_CurrProj( CloneBasicSurfTriMesh( vStmOthers[t])) ;
if ( IsNull( pStm_CurrProj) || ! pStm_CurrProj->IsValid())
return false ;
// rimuovo dalla TriMesh tutte le facce che sono perpendicolari e tutte le facce il cui Box3D nel piano di
// proeizione non fa overlap con quello della faccia selezionata
// scorro tutte le facce da proiettare
PtrOwner<SurfTriMesh> pStmForProj_noPerpFaces( CreateBasicSurfTriMesh()) ;
StmFromTriangleSoup StmFts ; StmFts.Start() ;
for ( int f = 0 ; f < pStm_CurrProj->GetFacetCount() ; ++ f) {
Vector3d vtN_curr ;
// se perpendicolari alla faccia selezionata, le trascuro
if ( pStm_CurrProj->GetFacetNormal( f, vtN_curr) && abs( vtN_curr * vtN) > 5 * EPS_SMALL) {
BBox3d BBoxFace_f ;
if ( ! pStm_CurrProj->GetFacetBBox( f, frH, BBoxFace_f))
return false ;
// se non c'è OverlapXY tra i due Box3D, la trascuro
if ( BBoxSelFace.OverlapsXY( BBoxFace_f)) {
PtrOwner<SurfTriMesh> pStm_Currface( pStm_CurrProj->CloneFacet( f)) ;
if ( IsNull( pStm_Currface) || ! pStm_Currface->IsValid())
return false ;
Triangle3d Tria ;
int nT = pStm_Currface->GetFirstTriangle( Tria) ;
while ( nT != SVT_NULL) {
// inserisco il triangolo nella nuova superficie
StmFts.AddTriangle( Tria) ;
// passo al triangolo successivo
nT = pStm_Currface->GetNextTriangle( nT, Tria) ;
}
}
}
}
StmFts.End() ;
pStmForProj_noPerpFaces.Set( GetBasicSurfTriMesh( StmFts.GetSurf())) ;
// se la nuova superficie da proittare non contiene nulla, allora passo alla successiva
if ( ! pStmForProj_noPerpFaces->IsValid())
continue ;
// ricostruisco la nuova superificie semplificata da proiettare
if ( ! pStmForProj_noPerpFaces->Repair() ||
! pStm_CurrProj.Set( Release( pStmForProj_noPerpFaces)) ||
IsNull( pStm_CurrProj) ||
! pStm_CurrProj->IsValid())
return false ;
// taglio la superficie con il piano creato ( la proiezione esclude le parti nel semipiano negativo)
// controllo la validità di questa operazione ( la faccia potrebbe essere tutta nel semipiano negativo)
if ( ! pStm_CurrProj->Cut( plFace, true))
return false ;
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<CurveComposite> pCrvCompo( CreateBasicCurveComposite()) ;
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<ISurfFlatRegion> 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( GetBasicSurfFlatRegion( Release( pSfr_proj_faceCurr))) ;
else
if ( ! pSfr_proj->Add( *pSfr_proj_faceCurr))
return false ;
}
// se non c'è nulla da proiettare e flag bOCFlag false, allora esco
if ( ! bExistProj && ! bOCFlag)
return true ;
// FlatRegion associata alla faccia della TriMesh selezionata
PtrOwner<SurfFlatRegion> pSfr_face( CreateBasicSurfFlatRegion()) ;
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<SurfTriMesh> pStm_final( CreateBasicSurfTriMesh()) ;
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 SurfTriMesh* 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 ;
}