//---------------------------------------------------------------------------- // 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 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 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( 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 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( 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 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 pCrvToReturn( CreateBasicCurveComposite()) ; if ( IsNull( pCrvToReturn)) return false ; // primo tratto di curva della Composita iniziale PtrOwner 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 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 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 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 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( 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 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 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 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 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 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 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 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 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 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 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 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 ; }