//---------------------------------------------------------------------------- // EgalTech 2025-2025 //---------------------------------------------------------------------------- // File : EXE_Trimming.cpp Data : 25.10.25 Versione : 2.7j3 // Funzioni per le lavorazioni di Trimming. // // Modifiche : 23.10.25 RE Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "EXE.h" #include "EXE_Macro.h" #include "DllExchange.h" #include "GeoTools.h" #include "AuxTools.h" #include "/EgtDev/Include/EgtNumUtils.h" #include "/EgtDev/Include/EXeExecutor.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include "/EgtDev/Include/EGkSurfLocal.h" #include "/EgtDev/Include/EGkCurveComposite.h" #include "/EgtDev/Include/EGkTrimming.h" #include "/EgtDev/Include/EGkStmFromTriangleSoup.h" #include "/EgtDev/Include/EGkDistPointCurve.h" #include #include using namespace std ; // --------------------------------------------------------------------------- bool ExeTrimmingGetHoleBorder( int nParentId, const INTVECTOR& vSurfIds, const INTVECTOR& vOtherSurfIds, double dSurfLinTol, double dSurfAngTol, double dEdgeLinTol, double dEdgeAngTol, double dEdgeThick, int& nFirstId, int& nCount) { // Verifica database geometrico IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Inizializzo i valori di ritorno nFirstId = GDB_ID_NULL ; nCount = 0 ; // Se non ho geometrie da ricercare, non faccio nulla if ( vSurfIds.empty()) return true ; // Recupero le superfici da cui estrarre i bordi CISURFPVECTOR vpSurfs ; vpSurfs.reserve( vSurfIds.size()) ; for ( int i = 0 ; i < ssize( vSurfIds) ; ++ i) { int nSurfId = vSurfIds[i] ; // Recupero l'entità const IGeoObj* pGeoObj = pGeomDB->GetGeoObj( nSurfId) ; if ( pGeoObj != nullptr) { // Recupero il Tipo int nType = pGeoObj->GetType() ; if ( nType == SRF_TRIMESH || nType == SRF_BEZIER) { // Recupero la superficie const ISurf* pSurf = GetSurf( pGeoObj) ; if ( pSurf != nullptr && pSurf->IsValid()) vpSurfs.emplace_back( pSurf) ; } } } // Se non ho superfici non faccio nulla if ( vpSurfs.empty()) return false ; // Calcolo il Centroide delle superfici complessive Point3d ptRef = P_INVALID ; if ( ! vOtherSurfIds.empty()) { int nToTSurf = 0 ; for ( int nOtherSurfId : vOtherSurfIds) { // Recupero l'entità const IGeoObj* pGeoObj = pGeomDB->GetGeoObj( nOtherSurfId) ; if ( pGeoObj != nullptr) { // Recupero il Tipo int nType = pGeoObj->GetType() ; if ( nType == SRF_TRIMESH || nType == SRF_BEZIER) { // Recupero la superficie const ISurf* pSurf = GetSurf( pGeoObj) ; if ( pSurf != nullptr && pSurf->IsValid()) { // Recupero il Centroide Point3d ptCentroid ; pSurf->GetCentroid( ptCentroid) ; if ( ! ptRef.IsValid()) ptRef = ptCentroid ; else ptRef += ptCentroid ; ++ nToTSurf ; } } } } if ( nToTSurf > 0) { for ( const ISurf* pSurf : vpSurfs) { Point3d ptCentroid ; pSurf->GetCentroid( ptCentroid) ; if ( ! ptRef.IsValid()) ptRef = ptCentroid ; else ptRef += ptCentroid ; ++ nToTSurf ; } ptRef /= nToTSurf ; } } // Recupero i Bordi per fori ed asole ICRVCOMPOPOVECTOR vHoleBorders ; bool bOk = GetTrimmingHoleBorders( vpSurfs, ptRef, dSurfLinTol, dSurfAngTol, dEdgeLinTol, dEdgeAngTol, dEdgeThick, vHoleBorders) ; if ( bOk) { // Inserisco le curve nel DB e imposto i parametri di ritorno bool bFirst = true ; for ( int i = 0 ; bOk && i < ssize( vHoleBorders) ; ++ i) { // Verifico che sia valida if ( ! IsNull( vHoleBorders[i]) && vHoleBorders[i]->IsValid()) { int nCrvId = pGeomDB->AddGeoObj( GDB_ID_NULL, nParentId, Release( vHoleBorders[i])) ; bOk = ( nCrvId != GDB_ID_NULL) ; if ( bOk) { ++ nCount ; if ( bFirst) { nFirstId = nCrvId ; bFirst = false ; } } } } } ExeSetModified() ; // Se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtTrimmingGetHoleBorder(" + ToString( nParentId) + "," + ToString( vSurfIds) + "," + ToString( dSurfLinTol) + "," + ToString( dSurfAngTol) + "," + ToString( dEdgeLinTol) + "," + ToString( dEdgeAngTol) + "," + ToString( dEdgeThick) + ")" + " bOk=" + ToString( bOk) + " nNewSurfId=" + ToString( nFirstId) + ", nCount= " + ToString( nCount) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } return bOk ; } // --------------------------------------------------------------------------- int ExeTrimmingGetSurfTmFaceAdj( int nParentId, int nSurfId, int nTria, const Point3d& ptTria, double dAngTol, double dSize, double dSizeTol) { // Verifica database geometrico IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Recupero la superficie TriMesh const ISurfTriMesh* pStm = GetSurfTriMesh( pGeomDB->GetGeoObj( nSurfId)) ; bool bOk = ( pStm != nullptr && pStm->IsValid()) ; // Recupero la superficie formata dai triangoli di adiacenza int nNewSurfId = GDB_ID_NULL ; if ( bOk) { PtrOwner pStmAdjFace( CreateSurfTriMesh()) ; bOk = ( ! IsNull( pStmAdjFace) && pStmAdjFace->AdjustTopology()) ; bOk = GetTrimmingStmAdjTria( pStm, nTria, ptTria, dAngTol, dSize, dSizeTol, pStmAdjFace) ; bOk = ( ! IsNull( pStmAdjFace) && pStmAdjFace->IsValid() && pStmAdjFace->GetTriangleCount() > 0) ; // Inserisco la Superficie nel DB geometrico if ( bOk) { nNewSurfId = pGeomDB->AddGeoObj( GDB_ID_NULL, nParentId, Release( pStmAdjFace)) ; bOk = ( nNewSurfId != GDB_ID_NULL) ; } } ExeSetModified() ; // Se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtTrimmingGetSurfTmFromFaceAdj(" + ToString( nParentId) + "," + ToString( nSurfId) + "," + ToString( nTria) + "," + "{ " + ToString( ptTria.x) + "," + ToString( ptTria.y) + "," + ToString( ptTria.z) + "}," + ToString( dAngTol) + ")" + " nNewSurfId=" + ToString( nNewSurfId) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } return nNewSurfId ; } // --------------------------------------------------------------------------- int ExeTrimmingGetSurfTmFromStmFaces( int nParentId, int nSurfId, const INTVECTOR& vFaces) { // Verifica database geometrico IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, GDB_ID_NULL) // Recupero il riferimento del gruppo di destinazione Frame3d frDest ; if ( ! pGeomDB->GetGlobFrame( nParentId, frDest)) return GDB_ID_NULL ; // Recupero la superficie TriMesh const ISurfTriMesh* pStm = GetSurfTriMesh( pGeomDB->GetGeoObj( nSurfId)) ; if ( pStm == nullptr || ! pStm->IsValid()) return GDB_ID_NULL ; // Verifico che le facce appartengano alla superficie if ( vFaces.empty()) return CMD_ID_NULL ; for ( int nF = 0 ; nF < int( vFaces.size()) ; ++ nF) { double dArea = 0. ; if ( ! pStm->GetFacetArea( vFaces[nF], dArea)) return GDB_ID_NULL ; } // Definisco la superficie StmFromTriangleSoup TriaSoup ; TriaSoup.Start() ; for ( int nF = 0 ; nF < int( vFaces.size()) ; ++ nF) { INTVECTOR vT ; if ( ! pStm->GetAllTriaInFacet( vFaces[nF], vT)) return GDB_ID_NULL ; for ( int nT = 0 ; nT < int( vT.size()) ; ++ nT) { Triangle3d Tria ; if ( ! pStm->GetTriangle( vT[nT], Tria) || ! TriaSoup.AddTriangle( Tria)) return GDB_ID_NULL ; } } TriaSoup.End() ; PtrOwner pStmTria( TriaSoup.GetSurf()) ; if ( IsNull( pStmTria) || ! pStmTria->IsValid() || pStmTria->GetTriangleCount() == 0) return GDB_ID_NULL ; // Aggiungo la superficie al DB int nNewSurfId = pGeomDB->AddGeoObj( GDB_ID_NULL, nParentId, Release( pStmTria)) ; ExeSetModified() ; // Se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "TrimmingGetSurfTmFromStmFaces(" + ToString( nParentId) + "," + ToString( nSurfId) + "," + ToString( vFaces) + ")" + " -- nId=" + ToString( nNewSurfId) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } return nNewSurfId ; } // --------------------------------------------------------------------------- bool ExeTrimmingGetAdjSurfs( const INTVECTOR& vSurfId, const INTVECTOR& vOtherSurfId, double dLinTol, double dAngTol, double dAngFaceTol, INTVECTOR& vResId) { // Verifica database geometrico IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Recupero le superfici di Riferimento CISURFPVECTOR vRefSurf ; vRefSurf.reserve( vSurfId.size()) ; bool bOk = true ; for ( int i = 0 ; bOk && i < int( vSurfId.size()) ; ++ i) { const ISurf* pSurf = GetSurf( pGeomDB->GetGeoObj( vSurfId[i])) ; bOk = ( pSurf != nullptr && pSurf->IsValid()) ; vRefSurf.emplace_back( pSurf) ; } // Recupero le superfici complessive, escludendo eventualmente quelle di riferimento se presenti CISURFPVECTOR vOtherSurf ; vOtherSurf.reserve( vOtherSurfId.size()) ; INTVECTOR vIds ; for ( int i = 0 ; bOk && i < int( vOtherSurfId.size()) ; ++ i) { if ( find( vSurfId.begin(), vSurfId.end(), vOtherSurfId[i]) == vSurfId.end()) { const ISurf* pSurf = GetSurf( pGeomDB->GetGeoObj( vOtherSurfId[i])) ; bOk = ( pSurf != nullptr && pSurf->IsValid()) ; vOtherSurf.emplace_back( pSurf) ; vIds.push_back( vOtherSurfId[i]) ; } } // Recupero le facce adiancenti nella tolleranza richiesta INTVECTOR vMyInds ; bOk = bOk && GetTrimmingAdjSurfs( vRefSurf, vOtherSurf, dLinTol, dAngTol, dAngFaceTol, vMyInds) ; if ( bOk) { for ( int myInd : vMyInds) vResId.push_back( vIds[myInd]) ; } ExeSetModified() ; // Se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtTrimmingGetAdjSurfs(" + ToString( vSurfId) + "," + ToString( vOtherSurfId) + "," + ToString( dAngTol) + ")" + " -- bOk=" + ToString( bOk) + ",vResId=" + ToString( vResId) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } return bOk ; } // --------------------------------------------------------------------------- bool ExeTrimmingGetBorders( int nParentId, const SELVECTOR& vIds, double dSurfLinTol, double dSurfAngTol, double dLinTol, double dAngTol, int& nFirstId, int& nCount) { // Verifica database geometrico IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Parametri da restituire nFirstId = GDB_ID_NULL ; nCount = 0 ; // vIds : vettore di { nId = SurfId, nSubId = nSurfFace } // Controllo che vIds non sia vuoto bool bOk = ( ! vIds.empty()) ; // Recupero il riferimento della prima superficie Frame3d frSurf ; bOk = bOk && pGeomDB->GetGlobFrame( vIds[0].nId, frSurf) ; // Recupero il riferimento dei gruppi di destinazione Frame3d frDest ; bOk = bOk && pGeomDB->GetGlobFrame( nParentId, frDest) ; // Recupero gli Id univoci delle superfici selezionate INTSET setUniqueId ; for ( const SelData& nIds : vIds) setUniqueId.insert( nIds.nId) ; // Recupero le superfici e le porto tutte in locale alla prima unordered_map uMapPos ; uMapPos.reserve( setUniqueId.size()) ; SURFLOCALVECTOR vSurfL ; vSurfL.reserve( setUniqueId.size()) ; CISURFPVECTOR vpSurf ; vpSurf.reserve( setUniqueId.size()) ; int nSurf = 0 ; for ( auto nIter = setUniqueId.begin() ; bOk && nIter != setUniqueId.end() ; ++ nIter) { vSurfL.emplace_back( pGeomDB, *nIter, frSurf) ; bOk = ( vSurfL.back().Get() != nullptr) ; vpSurf.emplace_back( vSurfL.back().Get()) ; uMapPos[*nIter] = nSurf ; ++ nSurf ; } // Recupero il vettore di Selezione associato non più agli Id delle superficie ma alle loro posizioni nel vettore SELVECTOR vFaces ; vFaces.reserve( vIds.size()) ; for ( int i = 0 ; bOk && i < int( vIds.size()) ; ++ i) vFaces.emplace_back( uMapPos[vIds[i].nId], vIds[i].nSub) ; // Calcolo le curve di Edge grezze ( quindi i tratti lineari) ICRVCOMPOPOVECTOR vRawEdges ; bOk = bOk && GetTrimmingRawEdges( vpSurf, vFaces, dSurfLinTol, dSurfAngTol, vRawEdges) && ( ! vRawEdges.empty()) ; // Calcolo le curve di Edge approssimate mediante curve di Bezier ICRVCOMPOPOVECTOR vBezierEdges ; bOk = bOk && GetTrimmingBezierEdges( vRawEdges, dLinTol, dAngTol, vBezierEdges) ; nCount = int( vBezierEdges.size()) ; if ( bOk) { // Scorro i gli Edges ottenuti for ( int nCrv = 0 ; bOk && nCrv < nCount ; ++ nCrv) { vBezierEdges[nCrv]->ToLoc( frDest) ; // Inserisco la curva nel DB Geometrico int nCurrId = pGeomDB->AddGeoObj( GDB_ID_NULL, nParentId, Release( vBezierEdges[nCrv])) ; bOk = ( nCurrId != GDB_ID_NULL) ; if ( nCrv == 0) nFirstId = nCurrId ; } } ExeSetModified() ; // Se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtTrimmingGetBorders(" + IdToString( nParentId) + "," + ToString( dSurfLinTol) + "," + ToString( dSurfAngTol) + "," + ToString( dLinTol) + "," + ToString( dAngTol) + ")" ; sLua += " -- bOk=" + ToString( bOk) + " -- FirstId=" + ToString( nFirstId) + " CurveCount=" + ToString( nCount) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } return bOk ; } // --------------------------------------------------------------------------- bool ExeTrimmingGetBordersByNormals( int nParentId, const SELVECTOR& vIds, double dSurfLinTol, double dSurfAngTol, double dLinTol, double dAngTol, double dThick, int& nFirstId, int& nCount) { // Verifica database geometrico IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Parametri da restituire nFirstId = GDB_ID_NULL ; nCount = 0 ; // vIds : vettore di { nId = SurfId, nSubId = nSurfFace } // Controllo che vIds non sia vuoto bool bOk = ( ! vIds.empty()) ; // Recupero il riferimento della prima superficie Frame3d frSurf ; bOk = bOk && pGeomDB->GetGlobFrame( vIds[0].nId, frSurf) ; // Recupero il riferimento dei gruppi di destinazione Frame3d frDest ; bOk = bOk && pGeomDB->GetGlobFrame( nParentId, frDest) ; // Recupero gli Id univoci delle superfici selezionate INTSET setUniqueId ; for ( const SelData& nIds : vIds) setUniqueId.insert( nIds.nId) ; // Recupero le superfici e le porto tutte in locale alla prima unordered_map uMapPos ; uMapPos.reserve( setUniqueId.size()) ; SURFLOCALVECTOR vSurfL ; vSurfL.reserve( setUniqueId.size()) ; CISURFPVECTOR vpSurf ; vpSurf.reserve( setUniqueId.size()) ; int nSurf = 0 ; for ( auto nIter = setUniqueId.begin() ; bOk && nIter != setUniqueId.end() ; ++ nIter) { vSurfL.emplace_back( pGeomDB, *nIter, frSurf) ; bOk = ( vSurfL.back().Get() != nullptr) ; vpSurf.emplace_back( vSurfL.back().Get()) ; uMapPos[*nIter] = nSurf ; ++ nSurf ; } // Recupero il vettore di Selezione associato non più agli Id delle superficie ma alle loro posizioni nel vettore SELVECTOR vFaces ; vFaces.reserve( vIds.size()) ; for ( int i = 0 ; bOk && i < int( vIds.size()) ; ++ i) vFaces.emplace_back( uMapPos[vIds[i].nId], vIds[i].nSub) ; // Calcolo le curve di Edge approssimate mediante curve di Bezier ICRVCOMPOPOVECTOR vBezierEdges ; bOk = bOk && GetTrimmingFinalBorders( vpSurf, vFaces, dSurfLinTol, dSurfAngTol, dLinTol, dAngTol, dThick, vBezierEdges) ; if ( bOk) { nCount = int( vBezierEdges.size()) ; // Scorro i gli Edges ottenuti for ( int nCrv = 0 ; bOk && nCrv < nCount ; ++ nCrv) { vBezierEdges[nCrv]->ToLoc( frDest) ; // Inserisco la curva nel DB Geometrico int nCurrId = pGeomDB->AddGeoObj( GDB_ID_NULL, nParentId, Release( vBezierEdges[nCrv])) ; bOk = ( nCurrId != GDB_ID_NULL) ; if ( nCrv == 0) nFirstId = nCurrId ; } } ExeSetModified() ; // Se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtTrimmingGetBordersByNormals(" + IdToString( nParentId) + "," + ToString( dLinTol) + "," + ToString( dAngTol) + ")" ; sLua += " -- bOk=" + ToString( bOk) + " -- FirstId=" + ToString( nFirstId) + " CurveCount=" + ToString( nCount) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } return bOk ; } // --------------------------------------------------------------------------- bool ExeTrimmingGetFinalBorders( int nParentId, const INTVECTOR& vCrvBezierId, double dLinTol, double dAngTol, const PNTVECTOR& vBrkPts, double dThick, double dThickTol, int& nFirstId, int& nCount) { // Verifica database geometrico IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Parametri da restituire nFirstId = GDB_ID_NULL ; nCount = 0 ; // Recupero il riferimento del gruppo di destinazione Frame3d frDest ; bool bOk = ( pGeomDB->GetGlobFrame( nParentId, frDest)) ; // Recupero le curve di Bordo approssimate come Bezier ICRVCOMPOPOVECTOR vCompoBezierEdges ; vCompoBezierEdges.reserve( vCrvBezierId.size()) ; for ( int nCrv = 0 ; bOk && nCrv < int( vCrvBezierId.size()) ; ++ nCrv) { const ICurve* pCrv = GetCurve( pGeomDB->GetGeoObj( vCrvBezierId[nCrv])) ; bOk = ( pCrv != nullptr && pCrv->IsValid()) ; if ( bOk) { PtrOwner pCompoRawEdges( ConvertCurveToComposite( pCrv->Clone())) ; bOk = ( ! IsNull( pCompoRawEdges) && pCompoRawEdges->IsValid() && vCompoBezierEdges.emplace_back( Release( pCompoRawEdges))) ; } } // Converto i punti in coppie di punti ( se dispari l'ultimo viene ignorato) BIPNTVECTOR vBreakingPts ; vBreakingPts.reserve( int( int( vBrkPts.size()) / 2)) ; for ( int nPt = 0 ; bOk && nPt < int( vBrkPts.size()) - 1 ; nPt += 2) vBreakingPts.emplace_back( make_pair( vBrkPts[nPt], vBrkPts[nPt+1])) ; if ( int( vBrkPts.size()) % 2 != 0) LOG_INFO( GetCmdLogger(), "Warning in EgtExtractSurfFrChunkLoops : Odd number of breaking points") ; // Calcolo le curve di Edge bOk = bOk && GetTrimmingFinalBorders( vCompoBezierEdges, dLinTol, dAngTol, vBreakingPts, dThick, dThickTol) ; nCount = int( vCompoBezierEdges.size()) ; if ( bOk) { // Scorro i gli Edges ottenuti for ( int nCrv = 0 ; bOk && nCrv < nCount ; ++ nCrv) { vCompoBezierEdges[nCrv]->ToLoc( frDest) ; // Inserisco la curva nel DB Geometrico int nCurrId = pGeomDB->AddGeoObj( GDB_ID_NULL, nParentId, Release( vCompoBezierEdges[nCrv])) ; bOk = ( nCurrId != GDB_ID_NULL) ; if ( nCrv == 0) nFirstId = nCurrId ; } ExeSetModified() ; } // Se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtTrimmingGetFinalBorders(" + IdToString( nParentId) + "," + ToString( vCrvBezierId) + "," + ToString( dLinTol) + "," + ToString( dAngTol) + "," ; sLua += "{" ; for ( int nP = 0 ; nP < int( vBrkPts.size()) ; ++ nP) { sLua += "(" + ToString( vBrkPts[nP].x) + ", " + ToString( vBrkPts[nP].y) + ", " + ToString( vBrkPts[nP].z) + ")" + ( nP != int( vBrkPts.size()) - 1 ? "," : "") ; } sLua += "}" ; sLua += ToString( dThick) + "," + ToString( dThickTol) + ")" ; sLua += " -- bOk=" + ToString( bOk) + " -- FirstId=" + ToString( nFirstId) + " CurveCount=" + ToString( nCount) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } return bOk ; } // --------------------------------------------------------------------------- int ExeTrimmingGetRuledBezier( int nParentId, const INTVECTOR& vIds, int nEdge1Id, int nEdge2Id, double dLinTol, const INTVECTOR& vnLineId) { // Verifica database geometrico IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, GDB_ID_NULL) // Aggiusto la tolleranza lineare se necessario double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ; // Recupero il riferimento dei gruppi di destinazione Frame3d frDest ; bool bOk = pGeomDB->GetGlobFrame( nParentId, frDest) ; // Recupero la prima curva const ICurve* pCrvEdge1 = GetCurve( pGeomDB->GetGeoObj( nEdge1Id)) ; bOk = bOk && ( pCrvEdge1 != nullptr && pCrvEdge1->IsValid()) ; // Recupero la seconda curva const ICurve* pCrvEdge2 = GetCurve( pGeomDB->GetGeoObj( nEdge2Id)) ; bOk = bOk && ( pCrvEdge2 != nullptr && pCrvEdge2->IsValid()) ; // Se ci sono delle superfici di riferimento CISURFPVECTOR vpSurf ; vpSurf.reserve( vIds.size()) ; if ( ! vIds.empty()) { SURFLOCALVECTOR vSurfL ; vSurfL.reserve( vIds.size()) ; // Recupero il riferimento della prima superficie Frame3d frSurf ; bOk = bOk && ( pGeomDB->GetGlobFrame( vIds[0], frSurf)) ; // Porto le altre nel riferimento della prima for ( int nSurf = 0 ; bOk && nSurf < int( vIds.size()) ; ++ nSurf) { vSurfL.emplace_back( pGeomDB, vIds[nSurf], frSurf) ; if ( vSurfL.back().Get() == nullptr) { bOk = false ; break ; } vpSurf.emplace_back( vSurfL.back().Get()) ; } } // Recupero i punti di sincronizzazione ( se presenti) BIPNTVECTOR vSyncPoints ; vSyncPoints.reserve( pGeomDB->GetGroupObjs( vnLineId.size())) ; for ( int i = 0 ; bOk && i < ssize( vnLineId) ; ++ i) { // Recupero la Curva const ICurve* pLine = GetCurve( pGeomDB->GetGeoObj( vnLineId[i])) ; bOk = bOk && ( pLine != nullptr && pLine->IsValid()) ; if ( bOk) { // Recupero gli Estremi Point3d ptStart ; pLine->GetStartPoint( ptStart) ; Point3d ptEnd ; pLine->GetEndPoint( ptEnd) ; // Mi assicuro che gli estremi siano sulle curve di Bordo e orientati correttamente ( nel caso inverto) double dSqDistS1 = INFINITO ; if ( ! DistPointCurve( ptStart, *pCrvEdge1).GetSqDist( dSqDistS1)) continue ; if ( dSqDistS1 < dLinTol * dLinTol) { double dSqDistE2 = INFINITO ; if ( ! DistPointCurve( ptEnd, *pCrvEdge2).GetSqDist( dSqDistE2) || dSqDistE2 > dLinTol * dLinTol) continue ; } else { double dSqDistS2 = INFINITO ; if ( ! DistPointCurve( ptStart, *pCrvEdge2).GetSqDist( dSqDistS2) || dSqDistS2 > dLinTol * dLinTol) continue ; double dSqDistE1 = INFINITO ; if ( ! DistPointCurve( ptEnd, *pCrvEdge1).GetSqDist( dSqDistE1) || dSqDistE1 > dLinTol * dLinTol) continue ; swap( ptStart, ptEnd) ; } vSyncPoints.emplace_back( make_pair( ptStart, ptEnd)) ; } } // Recupero la superficie Bezier rigata PtrOwner pSurfBzRuled ; if ( bOk) { pSurfBzRuled.Set( GetTrimmingRuledBezier( vpSurf, pCrvEdge1, pCrvEdge2, dMyLinTol, vSyncPoints)) ; bOk = bOk && ( ! IsNull( pSurfBzRuled) && pSurfBzRuled->IsValid()) ; } // Inserisco la curva nel DB Geometrico int nSurfBzId = GDB_ID_NULL ; if ( bOk) { pSurfBzRuled->ToLoc( frDest) ; nSurfBzId = pGeomDB->AddGeoObj( GDB_ID_NULL, nParentId, Release( pSurfBzRuled)) ; bOk = bOk && ( nSurfBzId != GDB_ID_NULL) ; } ExeSetModified() ; // Se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtTrimmingGetRuledBezier(" + ToString( nParentId) + "," + ToString( vIds) + "," + ToString( nEdge1Id) + "," + ToString( nEdge2Id) + "," + ToString( dLinTol) + ")" + " -- bOk=" + ToString( bOk) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } // Restituisco il risultato return nSurfBzId ; } // --------------------------------------------------------------------------- bool ExeTrimmingInterpolateSyncLines( int nParentId, int nSync1Id, int nSync2Id, int nBorder1Id, int nBorder2Id, double dEdgeLinTol, double dEdgeAngTol, int& nFirstId, int& nCount) { // Verifica database geometrico IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, GDB_ID_NULL) // Reset parametri di ritorno nFirstId = GDB_ID_NULL ; nCount = 0 ; // Aggiusto la tolleranza lineare e angolare se necessario double dMyEdgeLinTol = Clamp( dEdgeLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ; double dMyEdgeAngTol = Clamp( dEdgeAngTol, EPS_ANG_SMALL, 60.) ; // recupero le due curve di sincronizzazione const ICurve* pSync1 = GetCurve( pGeomDB->GetGeoObj( nSync1Id)) ; const ICurve* pSync2 = GetCurve( pGeomDB->GetGeoObj( nSync2Id)) ; bool bOk = ( pSync1 != nullptr && pSync1->IsValid() && pSync2 != nullptr && pSync2->IsValid()) ; // Recupero le due curve di bordo const ICurve* pCrvEdge1 = GetCurve( pGeomDB->GetGeoObj( nBorder1Id)) ; const ICurve* pCrvEdge2 = GetCurve( pGeomDB->GetGeoObj( nBorder2Id)) ; bOk = bOk && ( pCrvEdge1 != nullptr && pCrvEdge1->IsValid()) ; bOk = bOk && ( pCrvEdge2 != nullptr && pCrvEdge2->IsValid()) ; // Calcolo le Curve di sincornizzazione Interpolate BIPNTVECTOR vSyncPoints ; bOk = bOk && GetTrimmingSyncInterpolation( pCrvEdge1, pCrvEdge2, pSync1, pSync2, dMyEdgeLinTol, dMyEdgeAngTol, vSyncPoints) ; if ( bOk && ! vSyncPoints.empty()) { // Inserisco le curve di sincronizzazione nel DB // [orientate da pCrvEdge1 a pCrvEdge2] for ( int i = 0 ; bOk && i < ssize( vSyncPoints) ; ++ i) { PtrOwner pSyncLine( CreateCurveLine()) ; bOk = ( ! IsNull( pSyncLine) && pSyncLine->Set( vSyncPoints[i].first, vSyncPoints[i].second)) ; if ( bOk) { if ( pCrvEdge1->IsPointOn( vSyncPoints[i].second, dMyEdgeLinTol)) pSyncLine->Invert() ; int nSyncId = pGeomDB->AddGeoObj( GDB_ID_NULL, nParentId, Release( pSyncLine)) ; bOk = ( nSyncId != CMD_ID_NULL) ; if ( i == 0) nFirstId = nSyncId ; } } nCount = ssize( vSyncPoints) ; } ExeSetModified() ; // Se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtTrimmingInterpolateSyncLines(" + ToString( nParentId) + "," + ToString( nSync1Id) + "," + ToString( nSync2Id) + "," + ToString( nBorder1Id) + "," + ToString( nBorder2Id) + "," + ToString( dEdgeLinTol) + "," + ToString( dEdgeAngTol) + ")" + " -- bOk=" + ToString( bOk) + " -- nFirstId=" + ToString( nFirstId) + " nCount=" + ToString( nCount) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } return bOk ; } // --------------------------------------------------------------------------- bool ExeTrimmingGetSurfBzSyncPoints( int nParentId, int nEdge1Id, int nEdge2Id, double dLinTol, double dAngTol, int nLineNbr, bool bShowOnCorners, int& nFirstId, int& nCount) { // Verifica database geometrico IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Imposto i parametri di ritorno nFirstId = GDB_ID_NULL ; nCount = 0 ; // Se non devo visualizzare alcuna linea, non faccio nulla if ( nLineNbr <= 0 && ! bShowOnCorners) return true ; // Se necessario aggiusto le tolleranze double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ; double dMyAngTol = Clamp( dAngTol, EPS_ANG_SMALL, ANG_RIGHT) ; // Recupero il riferimento del gruppo di destinazione Frame3d frDest ; bool bOk = ( pGeomDB->GetGlobFrame( nParentId, frDest)) ; // Recupero le due Curve di bordo const ICurve* pCrvEdge1 = GetCurve( pGeomDB->GetGeoObj( nEdge1Id)) ; const ICurve* pCrvEdge2 = GetCurve( pGeomDB->GetGeoObj( nEdge2Id)) ; bOk = bOk && ( pCrvEdge1 != nullptr && pCrvEdge1->IsValid() && pCrvEdge2 != nullptr && pCrvEdge2->IsValid()) ; // Verifico che le curve siano entrambe Aperte o entrambe Chiuse bOk = bOk && ( pCrvEdge1->IsClosed() == pCrvEdge2->IsClosed()) ; // Recupero i punti di sincronizzazione BIPNTVECTOR vSyncPoints ; bOk = bOk && GetTrimmingSurfBzSyncPoints( pCrvEdge1, pCrvEdge2, dMyLinTol, vSyncPoints) && ( ! vSyncPoints.empty()) ; int nToTSyncLines = ssize( vSyncPoints) ; // Ogni punto di sincronizzazione deve avere gli estremi sulle curve di Bordo for ( int i = 0 ; bOk && i < ssize( vSyncPoints) ; ++ i) { double dSqDistStart = INFINITO, dSqDistEnd = INFINITO ; bOk = ( DistPointCurve( vSyncPoints[i].first, *pCrvEdge1).GetSqDist( dSqDistStart) && dSqDistStart < dMyLinTol * dMyLinTol && DistPointCurve( vSyncPoints[i].second, *pCrvEdge2).GetSqDist( dSqDistEnd) && dSqDistEnd < dMyLinTol * dMyLinTol) ; } if ( bOk) { INTSET setInds ; // Se devo visualizzare più linee di quante ne ho ricavate, allora le devo visualizzare tutte if ( nLineNbr >= nToTSyncLines) { for ( int i = 0 ; i < nToTSyncLines ; ++ i) setInds.insert( i) ; } // Altrimenti else { // Se voglio visualizzare gli Spigoli if ( bShowOnCorners) { for ( int nL = 0 ; bOk && nL < nToTSyncLines ; ++ nL) { // Controllo se punto su spigolo della curva double dU = 0. ; Vector3d vtTanPrev, vtTanAft ; Point3d ptUseless ; bOk = ( pCrvEdge1->GetParamAtPoint( vSyncPoints[nL].first, dU, dMyLinTol) && pCrvEdge1->GetPointD1D2( dU, ICurve::FROM_MINUS, ptUseless, &vtTanPrev) && pCrvEdge1->GetPointD1D2( dU, ICurve::FROM_PLUS, ptUseless, &vtTanAft)) ; if ( ! bOk) break ; vtTanPrev.Normalize() ; vtTanAft.Normalize() ; if ( vtTanPrev * vtTanAft < cos( ( dMyAngTol + EPS_ANG_SMALL) * DEGTORAD)) { setInds.insert( nL) ; continue ; } bOk = ( pCrvEdge2->GetParamAtPoint( vSyncPoints[nL].second, dU, dMyLinTol) && pCrvEdge2->GetPointD1D2( dU, ICurve::FROM_MINUS, ptUseless, &vtTanPrev) && pCrvEdge2->GetPointD1D2( dU, ICurve::FROM_PLUS, ptUseless, &vtTanAft)) ; if ( ! bOk) break ; vtTanPrev.Normalize() ; vtTanAft.Normalize() ; if ( vtTanPrev * vtTanAft < cos( ( dMyAngTol + EPS_ANG_SMALL) * DEGTORAD)) { setInds.insert( nL) ; continue ; } } } // Se devo mostrare alcune Linee if ( bOk && nLineNbr > 0) { bool bBothOpen = ( ! pCrvEdge1->IsClosed() && ! pCrvEdge2->IsClosed()) ; bool bBothClosed = ( ! bBothOpen) ; int nLastIdx = nToTSyncLines - 1 ; if ( bBothClosed) { int nLine = nLineNbr ; if ( nLine == 1) setInds.insert( 0) ; else { int nMaxIndex = nToTSyncLines - 2 ; for ( int i = 0 ; i < nLine ; ++ i) { double dT = double( i) / double( nLine) ; int nIdx = int( 0.5 + dT * nMaxIndex) ; setInds.insert( nIdx) ; } setInds.erase( nLastIdx) ; } } else { int nInternal = nLineNbr ; setInds.insert( 0) ; setInds.insert( nLastIdx) ; int nMaxIndex = nLastIdx ; for ( int i = 0; i < nInternal ; ++ i) { double dT = double( i + 1) / double( nInternal + 1) ; int nIdx = int( 0.5 + dT * nMaxIndex) ; setInds.insert( nIdx) ; } } } } // Visualizzo i segmenti lineari di sincronizzazione per ogni indice ricavato bool bFirst = true ; for ( auto Iter = setInds.begin() ; bOk && Iter != setInds.end() ; ++ Iter) { PtrOwner pLine( CreateCurveLine()) ; bOk = ( ! IsNull( pLine) && pLine->Set( vSyncPoints[*Iter].first, vSyncPoints[*Iter].second)) ; if ( bOk) { int nLineId = pGeomDB->AddGeoObj( GDB_ID_NULL, nParentId, Release( pLine)) ; bOk = ( nLineId != GDB_ID_NULL) ; if ( bFirst) { nFirstId = nLineId ; bFirst = false ; } ++ nCount ; } } } ExeSetModified() ; // Se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtTrimmingGetSurfBzSyncPoints(" + ToString( nParentId) + "," + ToString( nEdge1Id) + "," + ToString( nEdge2Id) + "," + ToString( dLinTol) + "," + ToString( nFirstId) + "," + ToString( nCount) + ")" + " -- bOk=" + ToString( bOk) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } return bOk ; } // --------------------------------------------------------------------------- int ExeRegolarizeSurfaceLocally( int nParentId, int nSurfId, int nSyncStartId, int nSyncEndId, double dLinTol) { bool bOk = true ; // Verifica database geometrico IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // recupero la superficie ISurfBezier* pSurfBez = GetSurfBezier( GetSurf( pGeomDB->GetGeoObj( nSurfId))) ; // recupero le due isocurve const ICurve* pSyncStart = GetCurveLine( GetCurve( pGeomDB->GetGeoObj( nSyncStartId))) ; const ICurve* pSyncEnd = GetCurveLine( GetCurve( pGeomDB->GetGeoObj( nSyncEndId))) ; Point3d ptS1 ; pSyncStart->GetStartPoint( ptS1) ; Point3d ptE1 ; pSyncStart->GetEndPoint( ptE1) ; BIPOINT bpIsoStart( ptS1, ptE1) ; Point3d ptS2 ; pSyncEnd->GetStartPoint( ptS2) ; Point3d ptE2 ; pSyncEnd->GetEndPoint( ptE2) ; BIPOINT bpIsoEnd( ptS2, ptE2) ; PtrOwner pNewSurf( RegolarizeBordersLocally( pSurfBez, bpIsoStart, bpIsoEnd, dLinTol)) ; if ( IsNull( pNewSurf)) return GDB_ID_NULL ; int nId = pGeomDB->AddGeoObj( GDB_ID_NULL, nParentId, Release( pNewSurf)) ; return nId ; }