cd48e2de3b
- varie correzioni ortografiche.
732 lines
29 KiB
C++
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 ;
|
|
}
|
|
|