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()) ; }