//---------------------------------------------------------------------------- // EgalTech 2018-2018 //---------------------------------------------------------------------------- // File : EXE_GeoInters.cpp Data : 27.09.18 Versione : 1.9i4 // Contenuto : Funzioni di intersezioni tra oggetto geometrici per EXE. // // // // Modifiche : 27.09.18 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "EXE.h" #include "EXE_Const.h" #include "EXE_Macro.h" #include "AuxTools.h" #include "GeoTools.h" #include "/EgtDev/Include/EXeExecutor.h" #include "/EgtDev/Include/EXeConst.h" #include "/EgtDev/Include/EGkGeoPoint3d.h" #include "/EgtDev/Include/EGkCurveLine.h" #include "/EgtDev/Include/EGkCurveComposite.h" #include "/EgtDev/Include/EGkChainCurves.h" #include "/EgtDev/Include/EGkCurveLocal.h" #include "/EgtDev/Include/EGkStmStandard.h" #include "/EgtDev/Include/EGkStmFromTriangleSoup.h" #include "/EgtDev/Include/EGkSurfLocal.h" #include "/EgtDev/Include/EGkVolZmap.h" #include "/EgtDev/Include/EGkIntersCurves.h" #include "/EgtDev/Include/EGkIntersLineBox.h" #include "/EgtDev/Include/EGkIntersPlaneBox.h" #include "/EgtDev/Include/EGkIntersLineSurfTm.h" #include "/EgtDev/Include/EGkIntersPlaneSurfTm.h" #include "/EgtDev/Include/EGkIntersSurfTmSurfTm.h" #include "/EgtDev/Include/EGkIntersLinePlane.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EgtNumUtils.h" #include "/EgtDev/Include/EgtPointerOwner.h" using namespace std ; //------------------------------------------------------------------------------- bool MyLineCurveInters( const Point3d& ptP, const Vector3d& vtDir, const int nId, const int nRefType, INTDBLVECTOR& vInters) { vInters.clear() ; IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // recupero il riferimento di calcolo Frame3d frCalc ; if ( nRefType == RTY_GLOB) frCalc = GLOB_FRM ; else if ( nRefType == RTY_GRID) frCalc = pGeomDB->GetGridFrame() ; else { if ( ! pGeomDB->GetGlobFrame( nId, frCalc)) return false ; } // recupero la curva in locale al gruppo destinazione CurveLocal CrvLoc( pGeomDB, nId, frCalc) ; // calcolo l'ingombro della curva BBox3d b3Crv ; if ( ! CrvLoc->GetLocalBBox( b3Crv)) return false ; b3Crv.Expand( 100 * EPS_SMALL) ; // definisco la linea (punto e direzione sono già nel riferimento di calcolo) double dLen = 2 * floor( b3Crv.MaxDistFromPoint( ptP)) ; double dOffs = -dLen / 2 ; PtrOwner pLine( CreateCurveLine()) ; if ( IsNull( pLine) || ! pLine->SetPVL( ptP + dOffs * vtDir, vtDir, dLen) ) return false ; // intersezione fra le curve nel piano di calcolo IntersCurveCurve intCC( *pLine, *CrvLoc, true) ; int nInters = intCC.GetIntersCount() ; // recupero i risultati for ( int i = 0 ; i < nInters ; i++) { IntCrvCrvInfo aInfo ; intCC.GetIntCrvCrvInfo( i, aInfo) ; // se intersezione puntuale if ( ! aInfo.bOverlap) { double dDist = dOffs + aInfo.IciA[0].dU * dLen ; int nType = CLT_NONE ; if ( aInfo.IciA[0].nPrevTy == ICCT_IN) { if ( aInfo.IciA[0].nNextTy == ICCT_IN) nType = CLT_TOUCH_IN ; else if ( aInfo.IciA[0].nNextTy == ICCT_OUT) nType = CLT_OUT ; } else if ( aInfo.IciA[0].nPrevTy == ICCT_OUT) { if ( aInfo.IciA[0].nNextTy == ICCT_IN) nType = CLT_IN ; else if ( aInfo.IciA[0].nNextTy == ICCT_OUT) nType = CLT_TOUCH_OUT ; } vInters.emplace_back( nType, dDist) ; } // altrimenti sovrapposizione else { // inizio double dDist1 = dOffs + aInfo.IciA[0].dU * dLen ; int nType1 = CLT_NONE ; if ( aInfo.IciA[0].nPrevTy == ICCT_IN) nType1 = CLT_TGINI_IN ; else if ( aInfo.IciA[0].nPrevTy == ICCT_OUT) nType1 = CLT_TGINI_OUT ; vInters.emplace_back( nType1, dDist1) ; // fine double dDist2 = dOffs + aInfo.IciA[1].dU * dLen ; int nType2 = CLT_NONE ; if ( aInfo.IciA[1].nNextTy == ICCT_IN) nType2 = CLT_TGFIN_IN ; else if ( aInfo.IciA[1].nNextTy == ICCT_OUT) nType2 = CLT_TGFIN_OUT ; vInters.emplace_back( nType2, dDist2) ; } } return true ; } //------------------------------------------------------------------------------- bool ExeLineCurveInters( const Point3d& ptP, const Vector3d& vtDir, const int nId, const int nRefType, INTDBLVECTOR& vInters) { // eseguo bool bOk = MyLineCurveInters( ptP, vtDir, nId, nRefType, vInters) ; // se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtLineCurveInters({" + ToString( ptP) + "},{" + ToString( vtDir) + "},{" + ToString( nId) + "," + RefTypeToString( nRefType) + ")" + " -- Ok=" + ToString( bOk) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } // restituisco stato esecuzione return bOk ; } //------------------------------------------------------------------------------- bool ExeLineBoxInters( const Point3d& ptP, const Vector3d& vtDir, const BBox3d& b3Box, INTDBLVECTOR& vInters) { // eseguo bool bOk = IntersLineBox( ptP, vtDir, 1, b3Box, vInters, false) ; // se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtLineBoxInters({" + ToString( ptP) + "},{" + ToString( vtDir) + "},{" + ToString( b3Box) + "})" + " -- Ok=" + ToString( bOk) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } // restituisco l'identificativo della prima nuova entità return bOk ; } //------------------------------------------------------------------------------- static bool MyLineSurfTmInters( const Point3d& ptP, const Vector3d& vtDir, int nId, int nRefType, INTDBLVECTOR& vInters) { vInters.clear() ; IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // recupero la superficie TriMesh const ISurfTriMesh* pStm = GetSurfTriMesh( pGeomDB->GetGeoObj( nId)) ; if ( pStm == nullptr) return false ; // recupero il suo riferimento globale Frame3d frSurf ; if ( ! pGeomDB->GetGlobFrame( nId, frSurf)) return false ; // porto in locale il punto e la direzione della linea Point3d ptPL = GetPointLocal( pGeomDB, ptP, nRefType, frSurf) ; Vector3d vtDirL = GetVectorLocal( pGeomDB, vtDir, nRefType, frSurf) ; vtDirL.Normalize() ; // calcolo l'ingombro della trimesh BBox3d b3Surf ; if ( ! pStm->GetLocalBBox( b3Surf)) return false ; // calcolo l'intersezione double dLen = b3Surf.MaxDistFromPoint( ptPL) ; ILSIVECTOR vInfo ; if ( ! IntersLineSurfTm( ptPL, vtDirL, dLen, *pStm, vInfo, false)) return false ; // ciclo sulle intersezioni for ( const auto& Info : vInfo) { // se intersezione puntuale if ( Info.nILTT == ILTT_VERT || Info.nILTT == ILTT_EDGE || Info.nILTT == ILTT_IN) { int nFlag = SLT_TOUCH ; if ( Info.dCosDN > EPS_ZERO) nFlag = SLT_OUT ; else if ( Info.dCosDN < -EPS_ZERO) nFlag = SLT_IN ; vInters.emplace_back( nFlag, Info.dU) ; } // se altrimenti intersezione con coincidenza else if ( Info.nILTT == ILTT_SEGM || Info.nILTT == ILTT_SEGM_ON_EDGE) { vInters.emplace_back( SLT_TG_INI, Info.dU) ; vInters.emplace_back( SLT_TG_FIN, Info.dU2) ; } } // elimino intersezioni ripetute for ( size_t j = 1 ; j < vInters.size() ; ) { // intersezione precedente size_t i = j - 1 ; // se hanno lo stesso parametro if ( abs( vInters[i].second - vInters[j].second) < EPS_SMALL) { // se sono entrambe entranti o uscenti, elimino la seconda if ( ( vInters[i].first == SLT_IN && vInters[j].first == SLT_IN) || ( vInters[i].first == SLT_OUT && vInters[j].first == SLT_OUT)) { vInters.erase( vInters.begin() + j) ; continue ; } // se una entrante e l'altra uscente, cambio in touch ed elimino la seconda else if ( ( vInters[i].first == SLT_IN && vInters[j].first == SLT_OUT) || ( vInters[i].first == SLT_OUT && vInters[j].first == SLT_IN)) { vInters[i].first = SLT_TOUCH ; vInters.erase( vInters.begin() + j) ; continue ; } // se una puntuale e l'altra inizio di coincidenza, elimino la prima else if ( ( vInters[i].first == SLT_IN || vInters[i].first == SLT_OUT || vInters[i].first == SLT_TOUCH) && vInters[j].first == SLT_TG_INI) { vInters.erase( vInters.begin() + i) ; continue ; } // se una fine di coincidenza e l'altra puntuale, elimino la seconda else if ( vInters[i].first == SLT_TG_FIN && ( vInters[j].first == SLT_IN || vInters[j].first == SLT_OUT || vInters[j].first == SLT_TOUCH)) { vInters.erase( vInters.begin() + j) ; continue ; } // se una fine di coincidenza e l'altra inizio di coincidenza, elimino entrambe else if ( i > 0 && vInters[i].first == SLT_TG_FIN && vInters[j].first == SLT_TG_INI) { vInters.erase( vInters.begin() + j) ; vInters.erase( vInters.begin() + i) ; -- j ; continue ; } } // passo alla successiva ++ j ; } return true ; } //------------------------------------------------------------------------------- bool ExeLineSurfTmInters( const Point3d& ptP, const Vector3d& vtDir, int nId, int nRefType, INTDBLVECTOR& vInters) { // eseguo bool bOk = MyLineSurfTmInters( ptP, vtDir, nId, nRefType, vInters) ; // se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtLineSurfTmInters({" + ToString( ptP) + "},{" + ToString( vtDir) + "}," + ToString( nId) + "," + RefTypeToString( nRefType) + ")" + " -- Ok=" + ToString( bOk) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } // restituisco l'identificativo della prima nuova entità return bOk ; } //------------------------------------------------------------------------------- static bool MyLineVolZmapInters( const Point3d& ptP, const Vector3d& vtDir, int nId, int nRefType, INTDBLVECTOR& vInters) { vInters.clear() ; IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // recupero lo Zmap IVolZmap* pVZM = GetVolZmap( pGeomDB->GetGeoObj( nId)) ; if ( pVZM == nullptr) return false ; // recupero il suo riferimento globale Frame3d frZmap ; if ( ! pGeomDB->GetGlobFrame( nId, frZmap)) return false ; // porto in locale il punto e la direzione della linea Point3d ptPL = GetPointLocal( pGeomDB, ptP, nRefType, frZmap) ; Vector3d vtDirL = GetVectorLocal( pGeomDB, vtDir, nRefType, frZmap) ; vtDirL.Normalize() ; // calcolo l'ingombro dello Zmap BBox3d b3Surf ; if ( ! pVZM->GetLocalBBox( b3Surf)) return false ; // calcolo l'intersezione ILZIVECTOR vInfo ; if ( ! pVZM->GetLineIntersection( ptPL, vtDirL, vInfo)) return false ; // ciclo sulle intersezioni for ( const auto& Info : vInfo) { // se intersezione puntuale if ( Info.nILTT == ILTT_VERT || Info.nILTT == ILTT_EDGE || Info.nILTT == ILTT_IN) { int nFlag = SLT_TOUCH ; if ( vtDirL * Info.trTria.GetN() > EPS_ZERO) nFlag = SLT_OUT ; else if ( vtDirL * Info.trTria.GetN() < -EPS_ZERO) nFlag = SLT_IN ; vInters.emplace_back( nFlag, Info.dU) ; } // se altrimenti intersezione con coincidenza else if ( Info.nILTT == ILTT_SEGM || Info.nILTT == ILTT_SEGM_ON_EDGE) { vInters.emplace_back( SLT_TG_INI, Info.dU) ; vInters.emplace_back( SLT_TG_FIN, Info.dU2) ; } } // elimino intersezioni ripetute for ( size_t j = 1 ; j < vInters.size() ; ) { // intersezione precedente size_t i = j - 1 ; // se hanno lo stesso parametro if ( abs( vInters[i].second - vInters[j].second) < EPS_SMALL) { // se sono entrambe entranti o uscenti, elimino la seconda if ( ( vInters[i].first == SLT_IN && vInters[j].first == SLT_IN) || ( vInters[i].first == SLT_OUT && vInters[j].first == SLT_OUT)) { vInters.erase( vInters.begin() + j) ; continue ; } // se una entrante e l'altra uscente, cambio in touch ed elimino la seconda else if ( ( vInters[i].first == SLT_IN && vInters[j].first == SLT_OUT) || ( vInters[i].first == SLT_OUT && vInters[j].first == SLT_IN)) { vInters[i].first = SLT_TOUCH ; vInters.erase( vInters.begin() + j) ; continue ; } // se una puntuale e l'altra inizio di coincidenza, elimino la prima else if ( ( vInters[i].first == SLT_IN || vInters[i].first == SLT_OUT || vInters[i].first == SLT_TOUCH) && vInters[j].first == SLT_TG_INI) { vInters.erase( vInters.begin() + i) ; continue ; } // se una fine di coincidenza e l'altra puntuale, elimino la seconda else if ( vInters[i].first == SLT_TG_FIN && ( vInters[j].first == SLT_IN || vInters[j].first == SLT_OUT || vInters[j].first == SLT_TOUCH)) { vInters.erase( vInters.begin() + j) ; continue ; } // se una fine di coincidenza e l'altra inizio di coincidenza, elimino entrambe else if ( i > 0 && vInters[i].first == SLT_TG_FIN && vInters[j].first == SLT_TG_INI) { vInters.erase( vInters.begin() + j) ; vInters.erase( vInters.begin() + i) ; -- j ; continue ; } } // passo alla successiva ++ j ; } return true ; } //------------------------------------------------------------------------------- bool ExeLineVolZmapInters( const Point3d& ptP, const Vector3d& vtDir, int nId, int nRefType, INTDBLVECTOR& vInters) { // eseguo bool bOk = MyLineVolZmapInters( ptP, vtDir, nId, nRefType, vInters) ; // se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtLineVolZmapInters({" + ToString( ptP) + "},{" + ToString( vtDir) + "}," + ToString( nId) + "," + RefTypeToString( nRefType) + ")" + " -- Ok=" + ToString( bOk) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } // restituisco stato operazione return bOk ; } //------------------------------------------------------------------------------- static int MyAddPlaneIntersResultToGeomDB( IGeomDB* pGeomDB, const PNTVECTOR& vPnt, const BIPNTVECTOR& vBpt, const TRIA3DVECTOR& vTria, const Frame3d& frOrig, const Frame3d& frDest, int nId, int nDestGrpId, const Vector3d& vtExtr, double dToler, int& nPntCount, int& nCrvCount, int& nSrfCount) { // Inserisco il risultato nel DB int nFirstId = GDB_ID_NULL ; // Inserisco i punti nel DB for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) { // creo il punto PtrOwner pGeoPnt( CreateGeoPoint3d()) ; if ( IsNull( pGeoPnt)) return GDB_ID_NULL ; // setto il punto pGeoPnt->Set( vPnt[i]) ; // porto il punto nel riferimento destinazione pGeoPnt->LocToLoc( frOrig, frDest) ; // lo inserisco nel DB geometrico int nNewId = pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrpId, Release( pGeoPnt)) ; if ( nNewId == GDB_ID_NULL) return GDB_ID_NULL ; // copio il materiale if ( ! pGeomDB->CopyMaterial( nId, nNewId)) return GDB_ID_NULL ; // aggiorno contatori if ( nFirstId == GDB_ID_NULL) nFirstId = nNewId ; ++ nPntCount ; } // Inserisco le curve nel DB (dopo averle concatenate) ChainCurves chainC ; chainC.Init( false, dToler, int( vBpt.size())) ; for ( int i = 0 ; i < int( vBpt.size()) ; ++ i) { Vector3d vtDir = vBpt[i].second - vBpt[i].first ; vtDir.Normalize() ; if ( ! chainC.AddCurve( i + 1, vBpt[i].first, vtDir, vBpt[i].second, vtDir)) return GDB_ID_NULL ; } // recupero i percorsi concatenati Point3d ptNear = ( vBpt.empty() ? ORIG : vBpt[0].first) ; INTVECTOR vId ; while ( chainC.GetChainFromNear( ptNear, false, vId)) { // creo una curva composita PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo)) return GDB_ID_NULL ; // recupero gli estremi dei segmenti, creo le linee e le inserisco nella composita bool bAdded = true ; for ( int i = 0 ; i < int( vId.size()) ; ++ i) { // creo un segmento di retta PtrOwner pLine( CreateCurveLine()) ; if ( IsNull( pLine)) return GDB_ID_NULL ; // recupero gli estremi (non vanno mai invertiti per opzione di concatenamento) int nInd = abs( vId[i]) - 1 ; Point3d ptStart = ( bAdded ? vBpt[nInd].first : ptNear) ; Point3d ptEnd = vBpt[nInd].second ; // provo ad accodarlo alla composita bAdded = ( Dist( ptStart, ptEnd) > dToler / 2 && pLine->Set( ptStart, ptEnd) && pCrvCompo->AddCurve( Release( pLine), true, dToler)) ; ptNear = ( bAdded ? ptEnd : ptStart) ; } // se lunghezza curva inferiore a 5 volte la tolleranza, la ignoro double dCrvLen ; if ( ! pCrvCompo->GetLength( dCrvLen) || dCrvLen < 5. * dToler) continue ; // se curva chiusa entro 5 volte la tolleranza ma considerata aperta, la chiudo bene Point3d ptStart, ptEnd ; if ( pCrvCompo->GetStartPoint( ptStart) && pCrvCompo->GetEndPoint( ptEnd) && AreSamePointEpsilon( ptStart, ptEnd, 5. * dToler) && ! AreSamePointApprox( ptStart, ptEnd)) { // porto il punto finale a coincidere esattamente con l'inizio pCrvCompo->ModifyEnd( ptStart) ; } // assegno estrusione come direzione normale al piano pCrvCompo->SetExtrusion( vtExtr) ; // unisco segmenti allineati pCrvCompo->MergeCurves( 0.5 * dToler, ANG_TOL_STD_DEG) ; // porto la curva nel riferimento destinazione pCrvCompo->LocToLoc( frOrig, frDest) ; // la inserisco nel DB geometrico int nNewId = pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrpId, Release( pCrvCompo)) ; if ( nNewId == GDB_ID_NULL) return GDB_ID_NULL ; // copio il materiale if ( ! pGeomDB->CopyMaterial( nId, nNewId)) return GDB_ID_NULL ; // aggiorno contatori if ( nFirstId == GDB_ID_NULL) nFirstId = nNewId ; ++ nCrvCount ; } // Inserisco i triangoli nel DB (dopo averli uniti in una superficie trimesh) StmFromTriangleSoup StmFts ; if ( ! StmFts.Start()) return GDB_ID_NULL ; for ( int i = 0 ; i < int( vTria.size()) ; ++ i) // inserisco il triangolo nella nuova superficie StmFts.AddTriangle( vTria[i]) ; // valido la superficie e calcolo le adiacenze if ( ! StmFts.End()) return GDB_ID_NULL ; // se superficie con triangoli PtrOwner pNewStm( StmFts.GetSurf()) ; if ( ! IsNull( pNewStm) && pNewStm->GetTriangleCount() > 0) { // porto la superficie nel riferimento destinazione pNewStm->LocToLoc( frOrig, frDest) ; // la inserisco nel DB int nNewId = pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrpId, Release( pNewStm)) ; if ( nNewId == GDB_ID_NULL) return GDB_ID_NULL ; // copio il materiale if ( ! pGeomDB->CopyMaterial( nId, nNewId)) return GDB_ID_NULL ; // aggiorno contatori if ( nFirstId == GDB_ID_NULL) nFirstId = nNewId ; ++ nSrfCount ; } return nFirstId ; } //------------------------------------------------------------------------------- int MyPlaneCurveInters( const Point3d& ptOn, const Vector3d& vtN, const int nId, const int nDestGrpId, const int nRefType, int& nCount) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, GDB_ID_NULL) // recupero la curva const ICurve* pCrv = GetCurve( pGeomDB->GetGeoObj( nId)) ; if ( pCrv == nullptr) return GDB_ID_NULL ; // recupero il suo riferimento globale Frame3d frCrv ; if ( ! pGeomDB->GetGlobFrame( nId, frCrv)) return GDB_ID_NULL ; // recupero il riferimento del gruppo di destinazione Frame3d frDest ; if ( ! pGeomDB->GetGroupGlobFrame( nDestGrpId, frDest)) return GDB_ID_NULL ; // definisco il piano in locale Point3d ptOnL = GetPointLocal( pGeomDB, ptOn, nRefType, frCrv) ; Vector3d vtNL = GetVectorLocal( pGeomDB, vtN, nRefType, frCrv) ; Plane3d plPlane ; plPlane.Set( ptOnL, vtNL) ; // approssimo la curva con polyline PolyLine PL ; if ( ! pCrv->ApproxWithLines( 10 * EPS_SMALL, 15, ICurve::APL_SPECIAL, PL)) return GDB_ID_NULL ; // per ogni tratto della polyline cerco l'intersezione con il piano PNTVECTOR vPnt ; BIPNTVECTOR vBpt ; Point3d ptS, ptE ; PL.GetFirstPoint( ptS) ; while ( PL.GetNextPoint( ptE)) { Point3d ptInt ; int nRes = IntersLinePlane( ptS, ptE, plPlane, ptInt) ; if ( nRes == ILPT_INPLANE) vBpt.emplace_back( ptS, ptE) ; else if ( nRes != ILPT_NO) vPnt.emplace_back( ptInt) ; // aggiorno ptS per tratto successivo ptS = ptE ; } // elimino segmenti ripetuti for ( int i = 0 ; i < ( int)vBpt.size() ; ) { bool bFound = false ; for ( int j = i + 1 ; j < ( int)vBpt.size() ; j ++) { if (( AreSamePointApprox( vBpt[i].first, vBpt[j].first) && AreSamePointApprox( vBpt[i].second, vBpt[j].second)) || ( AreSamePointApprox( vBpt[i].first, vBpt[j].second) && AreSamePointApprox( vBpt[i].second, vBpt[j].first))) { bFound = true ; break ; } } if ( bFound) vBpt.erase( vBpt.begin() + i) ; else i ++ ; } // elimino punti ripetuti for ( int i = 0 ; i < ( int)vPnt.size() ; ) { bool bFound = false ; // cerco tra i punti rimanenti for ( int j = i + 1 ; j < ( int)vPnt.size() ; j ++) { if ( AreSamePointApprox( vPnt[i], vPnt[j])) { bFound = true ; break ; } } // cerco eventualmente tra i segmenti if ( ! bFound) { for ( int j = 0 ; j < ( int)vBpt.size() ; j ++) { if ( AreSamePointApprox( vPnt[i], vBpt[j].first) || AreSamePointApprox( vPnt[i], vBpt[j].second)) { bFound = true ; break ; } } } if ( bFound) vPnt.erase( vPnt.begin() + i) ; else i ++ ; } // aggiungo i risultati al DB geometrico int nPntCount{ 0}, nCrvCount{ 0}, nTmp{ 0} ; int nFirstId = MyAddPlaneIntersResultToGeomDB( pGeomDB, vPnt, vBpt, TRIA3DVECTOR(), frCrv, frDest, nId, nDestGrpId, vtNL, EPS_SMALL, nPntCount, nCrvCount, nTmp) ; nCount = nPntCount + nCrvCount ; // restituisco l'identificativo della prima entità creata return nFirstId ; } //------------------------------------------------------------------------------- int ExePlaneCurveInters( const Point3d& ptOn, const Vector3d& vtN, const int nId, const int nDestGrpId, const int nRefType, int* pnCount) { // eseguo int nCount{ 0} ; int nFirstId = MyPlaneCurveInters( ptOn, vtN, nId, nDestGrpId, nRefType, nCount) ; // aggiorno contatori if ( nFirstId != GDB_ID_NULL) { if ( pnCount != nullptr) *pnCount = nCount ; ExeSetModified() ; } // se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtPlaneCurveInters({" + ToString( ptOn) + "},{" + ToString( vtN) + "},{" + ToString( nId) + "," + ToString( nDestGrpId) + "," + RefTypeToString( nRefType) + ")" + " -- Id=" + ToString( nFirstId) + ", nCnt=" + ToString( nCount) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } // restituisco l'identificativo della prima nuova entità return nFirstId ; } //------------------------------------------------------------------------------- static int MyPlaneBoxInters( const Point3d& ptOn, const Vector3d& vtN, const BBox3d& b3Box, int nDestGrpId, int nRefType, int& nPntCount, int& nCrvCount, int& nSrfCount) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, GDB_ID_NULL) // recupero il riferimento del gruppo di destinazione Frame3d frDest ; if ( ! pGeomDB->GetGroupGlobFrame( nDestGrpId, frDest)) return GDB_ID_NULL ; // recupero il riferimento sorgente Frame3d frSou ; if ( nRefType == RTY_GLOB) frSou = Frame3d() ; else if ( nRefType == RTY_GRID) frSou = pGeomDB->GetGridFrame() ; else // ( nRefType == RTY_LOC) frSou = frDest ; // calcolo il piano Plane3d plPlane ; if ( ! plPlane.Set( ptOn, vtN)) return GDB_ID_NULL ; // eseguo l'intersezione PNTVECTOR vPnt ; BIPNTVECTOR vBpt ; TRIA3DVECTOR vTria ; if ( ! IntersPlaneBox( plPlane, b3Box, vPnt, vBpt, vTria)) return GDB_ID_NULL ; // porto le intersezioni nel riferimento destinazione for ( auto& Pnt : vPnt) Pnt.LocToLoc( frSou, frDest) ; for ( auto& Bpt : vBpt) { Bpt.first.LocToLoc( frSou, frDest) ; Bpt.second.LocToLoc( frSou, frDest) ; } for ( auto& Tria : vTria) Tria.LocToLoc( frSou, frDest) ; // porto la normale al piano nel riferimento destinazione Vector3d vtNL = vtN ; vtNL.LocToLoc( frSou, frDest) ; // Inserisco il risultato nel DB int nFirstId = GDB_ID_NULL ; // Inserisco i punti nel DB for ( size_t i = 0 ; i < vPnt.size() ; ++ i) { // creo il punto PtrOwner pGeoPnt( CreateGeoPoint3d()) ; if ( IsNull( pGeoPnt)) return GDB_ID_NULL ; // setto il punto pGeoPnt->Set( vPnt[i]) ; // lo inserisco nel DB geometrico int nNewId = pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrpId, Release( pGeoPnt)) ; if ( nNewId == GDB_ID_NULL) return GDB_ID_NULL ; // aggiorno contatori if ( nFirstId == GDB_ID_NULL) nFirstId = nNewId ; ++ nPntCount ; } // Concateno i tratti di curva double dToler = 2 * EPS_SMALL ; ChainCurves chainC ; chainC.Init( false, dToler, int( vBpt.size())) ; for ( size_t i = 0 ; i < vBpt.size() ; ++ i) { Vector3d vtDir = vBpt[i].second - vBpt[i].first ; vtDir.Normalize() ; if ( ! chainC.AddCurve( int( i) + 1, vBpt[i].first, vtDir, vBpt[i].second, vtDir)) return GDB_ID_NULL ; } // recupero i percorsi concatenati Point3d ptNear = ( vBpt.empty() ? ORIG : vBpt[0].first) ; INTVECTOR vId ; while ( chainC.GetChainFromNear( ptNear, false, vId)) { // creo una curva composita PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo)) return GDB_ID_NULL ; // recupero gli estremi dei segmenti, creo le linee e le inserisco nella composita for ( size_t i = 0 ; i < vId.size() ; ++ i) { // creo una segmento di retta int nInd = abs( vId[i]) - 1 ; bool bInvert = ( vId[i] < 0) ; PtrOwner pLine( CreateCurveLine()) ; if ( IsNull( pLine) || ! pLine->Set( vBpt[nInd].first, vBpt[nInd].second)) return GDB_ID_NULL ; if ( bInvert) pLine->Invert() ; // lo accodo alla composita if ( ! pCrvCompo->AddCurve( Release( pLine), true, dToler)) return GDB_ID_NULL ; // aggiorno il prossimo near ptNear = vBpt[nInd].second ; } // se lunghezza curva inferiore a 5 volte la tolleranza, la salto double dCrvLen ; if ( ! pCrvCompo->GetLength( dCrvLen) || dCrvLen < 5. * dToler) continue ; // se curva chiusa entro 5 volte la tolleranza ma considerata aperta, la chiudo bene Point3d ptStart, ptEnd ; if ( pCrvCompo->GetStartPoint( ptStart) && pCrvCompo->GetEndPoint( ptEnd) && AreSamePointEpsilon( ptStart, ptEnd, 5. * dToler) && ! AreSamePointApprox( ptStart, ptEnd)) { // porto il punto finale a coincidere esattamente con l'inizio pCrvCompo->ModifyEnd( ptStart) ; } // assegno estrusione come direzione normale al piano pCrvCompo->SetExtrusion( vtNL) ; // unisco segmenti allineati pCrvCompo->MergeCurves( 0.5 * dToler, ANG_TOL_STD_DEG) ; // la inserisco nel DB geometrico int nNewId = pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrpId, Release( pCrvCompo)) ; if ( nNewId == GDB_ID_NULL) return GDB_ID_NULL ; // aggiorno contatori if ( nFirstId == GDB_ID_NULL) nFirstId = nNewId ; ++ nCrvCount ; } // Se ci sono segmenti ma non sono state create curve, aggiungo punto nel loro centro if ( ! vBpt.empty() && nCrvCount == 0) { BBox3d b3Crv ; for ( size_t i = 0 ; i < vBpt.size() ; ++ i) { b3Crv.Add( vBpt[i].first) ; b3Crv.Add( vBpt[i].second) ; } if ( ! b3Crv.IsEmpty()) { // creo il punto PtrOwner pGeoPnt( CreateGeoPoint3d()) ; if ( IsNull( pGeoPnt)) return GDB_ID_NULL ; // setto il punto Point3d ptCen ; b3Crv.GetCenter( ptCen) ; pGeoPnt->Set( ptCen) ; // lo inserisco nel DB geometrico int nNewId = pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrpId, Release( pGeoPnt)) ; if ( nNewId == GDB_ID_NULL) return GDB_ID_NULL ; // aggiorno contatori if ( nFirstId == GDB_ID_NULL) nFirstId = nNewId ; ++ nPntCount ; } } // Costruisco una superficie trimesh dall'insieme di triangoli StmFromTriangleSoup StmFts ; if ( ! StmFts.Start()) return GDB_ID_NULL ; for ( size_t i = 0 ; i < vTria.size() ; ++ i) // inserisco il triangolo nella nuova superficie StmFts.AddTriangle( vTria[i]) ; // valido la superficie e calcolo le adiacenze if ( ! StmFts.End()) return GDB_ID_NULL ; // se superficie con triangoli PtrOwner pNewStm( StmFts.GetSurf()) ; if ( ! IsNull( pNewStm) && pNewStm->GetTriangleCount() > 0) { // la inserisco nel DB int nNewId = pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrpId, Release( pNewStm)) ; if ( nNewId == GDB_ID_NULL) return GDB_ID_NULL ; // aggiorno contatori if ( nFirstId == GDB_ID_NULL) nFirstId = nNewId ; ++ nSrfCount ; } // restituisco l'identificativo della prima nuova entità return nFirstId ; } //------------------------------------------------------------------------------- int ExePlaneBoxInters( const Point3d& ptOn, const Vector3d& vtN, const BBox3d& b3Box, int nDestGrpId, int nRefType, int* pnPntCount, int* pnCrvCount, int* pnSrfCount) { // eseguo int nPntCount{ 0}, nCrvCount{ 0}, nSrfCount{ 0} ; int nFirstId = MyPlaneBoxInters( ptOn, vtN, b3Box, nDestGrpId, nRefType, nPntCount, nCrvCount, nSrfCount) ; // aggiorno contatori if ( nFirstId != GDB_ID_NULL) { if ( pnPntCount != nullptr) *pnPntCount = nPntCount ; if ( pnCrvCount != nullptr) *pnCrvCount = nCrvCount ; if ( pnSrfCount != nullptr) *pnSrfCount = nSrfCount ; ExeSetModified() ; } // se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtPlaneBoxInters({" + ToString( ptOn) + "},{" + ToString( vtN) + "},{" + ToString( b3Box) + "}," + ToString( nDestGrpId) + "," + RefTypeToString( nRefType) + ")" + " -- Id1=" + ToString( nFirstId) + ", PntNbr=" + ToString( nPntCount) + ", CrvNbr=" + ToString( nCrvCount) + ", SrfNbr=" + ToString( nSrfCount) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } // restituisco l'identificativo della prima nuova entità return nFirstId ; } //------------------------------------------------------------------------------- static int MyPlaneSurfTmInters( const Point3d& ptOn, const Vector3d& vtN, int nId, int nDestGrpId, int nRefType, double dToler, int& nPntCount, int& nCrvCount, int& nSrfCount) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, GDB_ID_NULL) // recupero la superficie TriMesh const ISurfTriMesh* pStm = GetSurfTriMesh( pGeomDB->GetGeoObj( nId)) ; if ( pStm == nullptr) return GDB_ID_NULL ; // recupero il suo riferimento globale Frame3d frSurf ; if ( ! pGeomDB->GetGlobFrame( nId, frSurf)) return GDB_ID_NULL ; // recupero il riferimento del gruppo di destinazione Frame3d frDest ; if ( ! pGeomDB->GetGroupGlobFrame( nDestGrpId, frDest)) return GDB_ID_NULL ; // porto in locale il punto e la normale del piano Point3d ptOnL = GetPointLocal( pGeomDB, ptOn, nRefType, frSurf) ; Vector3d vtNL = GetVectorLocal( pGeomDB, vtN, nRefType, frSurf) ; // calcolo il piano di intersezione Plane3d plPlane ; if ( ! plPlane.Set( ptOnL, vtNL)) return GDB_ID_NULL ; // eseguo l'intersezione PNTVECTOR vPnt ; BIPNTVECTOR vBpt ; TRIA3DVECTOR vTria ; if ( ! IntersPlaneSurfTm( plPlane, *pStm, vPnt, vBpt, vTria)) return GDB_ID_NULL ; // inserisco il risultato dell'intersezione nel DB int nFirstId = MyAddPlaneIntersResultToGeomDB( pGeomDB, vPnt, vBpt, vTria, frSurf, frDest, nId, nDestGrpId, plPlane.GetVersN(), dToler, nPntCount, nCrvCount, nSrfCount) ; // restituisco l'identificativo della prima nuova entità return nFirstId ; } //------------------------------------------------------------------------------- int ExePlaneSurfTmInters( const Point3d& ptOn, const Vector3d& vtN, int nId, int nDestGrpId, int nRefType, double dToler, int* pnPntCount, int* pnCrvCount, int* pnSrfCount) { // eseguo int nPntCount{ 0}, nCrvCount{ 0}, nSrfCount{ 0} ; int nFirstId = MyPlaneSurfTmInters( ptOn, vtN, nId, nDestGrpId, nRefType, dToler, nPntCount, nCrvCount, nSrfCount) ; // aggiorno contatori if ( nFirstId != GDB_ID_NULL) { if ( pnPntCount != nullptr) *pnPntCount = nPntCount ; if ( pnCrvCount != nullptr) *pnCrvCount = nCrvCount ; if ( pnSrfCount != nullptr) *pnSrfCount = nSrfCount ; ExeSetModified() ; } // se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtPlaneSurfTmInters({" + ToString( ptOn) + "},{" + ToString( vtN) + "}," + ToString( nId) + "," + ToString( nDestGrpId) + "," + RefTypeToString( nRefType) + "," + ToString( dToler) + ")" + " -- Id1=" + ToString( nFirstId) + ", PntNbr=" + ToString( nPntCount) + ", CrvNbr=" + ToString( nCrvCount) + ", SrfNbr=" + ToString( nSrfCount) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } // restituisco l'identificativo della prima nuova entità return nFirstId ; } //------------------------------------------------------------------------------- static int MyParPlanesSurfTmInters( const Point3d& ptOn, const Vector3d& vtN, const DBLVECTOR& vdDist, int nId, int nDestGrpId, int nRefType, double dToler, int& nGrpCount) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, GDB_ID_NULL) // recupero la superficie TriMesh const ISurfTriMesh* pStm = GetSurfTriMesh( pGeomDB->GetGeoObj( nId)) ; if ( pStm == nullptr) return GDB_ID_NULL ; // recupero il suo riferimento globale Frame3d frSurf ; if ( ! pGeomDB->GetGlobFrame( nId, frSurf)) return GDB_ID_NULL ; // recupero il riferimento del gruppo di destinazione Frame3d frDest ; if ( ! pGeomDB->GetGroupGlobFrame( nDestGrpId, frDest)) return GDB_ID_NULL ; // porto in locale la normale del piano Point3d ptOnL = GetPointLocal( pGeomDB, ptOn, nRefType, frSurf) ; Vector3d vtNL = GetVectorLocal( pGeomDB, vtN, nRefType, frSurf) ; // costruisco il frame dei piani Frame3d frPlanes ; frPlanes.Set( ptOnL, vtNL) ; // intersezione fra superficie e piani paralleli IntersParPlanesSurfTm intPlStm( frPlanes, *pStm) ; int nFirstGrpId = GDB_ID_NULL ; for ( size_t i = 0 ; i < vdDist.size() ; i++) { // creo il layer in cui salvare int nGrpId = pGeomDB->AddGroup( GDB_ID_NULL, nDestGrpId, GLOB_FRM) ; nGrpCount ++ ; if ( nFirstGrpId == GDB_ID_NULL) nFirstGrpId = nGrpId ; // cerco l'intersezione con il piano PNTVECTOR vPnt ; BIPNTVECTOR vBpt ; TRIA3DVECTOR vTria ; if ( ! intPlStm.GetInters( vdDist[i], vPnt, vBpt, vTria)) { string sErr = "Error on ParPlanesStmInters at distance " + ToString( vdDist[i]) ; LOG_ERROR( GetLogger(), sErr.c_str()) ; continue ; } // inserisco il risultato nel DB int nTmp{ 0} ; MyAddPlaneIntersResultToGeomDB( pGeomDB, vPnt, vBpt, vTria, frSurf, frDest, nId, nGrpId, vtNL, dToler, nTmp, nTmp, nTmp) ; } // restituisco l'identificativo del primo gruppo creato return nFirstGrpId ; } //------------------------------------------------------------------------------- int ExeParPlanesSurfTmInters( const Point3d& ptOn, const Vector3d& vtN, const DBLVECTOR& vdDist, int nId, int nDestGrpId, int nRefType, double dToler, int* pnGrpCount) { // eseguo int nGrpCount{ 0} ; int nFirstId = MyParPlanesSurfTmInters( ptOn, vtN, vdDist, nId, nDestGrpId, nRefType, dToler, nGrpCount) ; // aggiorno contatori if ( nFirstId != GDB_ID_NULL) { if ( pnGrpCount != nullptr) *pnGrpCount = nGrpCount ; ExeSetModified() ; } // se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtParPlanesSurfTmInters({" + ToString( ptOn) + "},{" + ToString( vtN) + "},{" + ToString( vdDist) + "}," + ToString( nId) + "," + ToString( nDestGrpId) + "," + RefTypeToString( nRefType) + "," + ToString( dToler) + ")" + " -- Id=" + ToString( nFirstId) + ", GrpCnt=" + ToString( nGrpCount) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } // restituisco l'identificativo della prima nuova entità return nFirstId ; } //---------------------------------------------------------------------------- int MyPlaneVolZmapInters( const Point3d& ptOn, const Vector3d& vtN, int nId, int nDestGrpId, int nRefType, int& nCount) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // recupero il riferimento locale Frame3d frLoc ; if ( ! pGeomDB->GetGlobFrame( nId, frLoc)) return GDB_ID_NULL ; // recupero il riferimento destinazione Frame3d frDest ; if ( ! pGeomDB->GetGlobFrame( nDestGrpId, frDest)) return GDB_ID_NULL ; // porto in locale il punto e la normale del piano Point3d ptOnL = GetPointLocal( pGeomDB, ptOn, nRefType, frLoc) ; Vector3d vtNL = GetVectorLocal( pGeomDB, vtN, nRefType, frLoc) ; // calcolo il piano di intersezione Plane3d plPlane ; if ( ! plPlane.Set( ptOnL, vtNL)) return GDB_ID_NULL ; // recupero lo Zmap e calcolo l'intersezione IVolZmap* pVZM = GetVolZmap( pGeomDB->GetGeoObj( nId)) ; ICURVEPOVECTOR vpLoop ; if ( pVZM == nullptr || ! pVZM->GetPlaneIntersection( plPlane, vpLoop)) return GDB_ID_NULL ; // inserisco le curve nel gruppo destinazione int nFirstId = GDB_ID_NULL ; for ( size_t i = 0 ; i < vpLoop.size() ; ++ i) { PtrOwner pCrv( Release( vpLoop[i])) ; if ( IsNull( pCrv)) continue ; pCrv->ToLoc( frDest) ; // inserisco la curva composita nel gruppo destinazione int nNewId = pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrpId, ::Release( pCrv)) ; if ( nNewId == GDB_ID_NULL) return GDB_ID_NULL ; if ( nFirstId == GDB_ID_NULL) nFirstId = nNewId ; ++ nCount ; } // restituisco l'identificativo della prima nuova entità return nFirstId ; } //---------------------------------------------------------------------------- int ExePlaneVolZmapInters( const Point3d& ptOn, const Vector3d& vtN, int nId, int nDestGrpId, int nRefType, int* pnCount) { // eseguo int nCount = 0 ; int nFirstId = MyPlaneVolZmapInters( ptOn, vtN, nId, nDestGrpId, nRefType, nCount) ; if ( pnCount != nullptr) *pnCount = nCount ; ExeSetModified() ; // se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtPlaneVolZmapInters({" + ToString( ptOn) + "},{" + ToString( vtN) + "}," + IdToString( nId) + "," + ToString( nDestGrpId) + "," + RefTypeToString( nRefType) + ")" + " -- Id=" + ToString( nFirstId) + ",Nbr=" + ToString( nCount) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } // restituisco l'identificativo della prima nuova entità return nFirstId ; } //------------------------------------------------------------------------------- int MyCurveCurveInters( const int nId1, const int nId2, const int nDestGrpId, int& nPntCount, int& nCrvCount) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, GDB_ID_NULL) int nFirstId = GDB_ID_NULL ; // recupero il riferimento del gruppo di destinazione Frame3d frDest ; if ( ! pGeomDB->GetGroupGlobFrame( nDestGrpId, frDest)) return GDB_ID_NULL ; // recupero le curve in locale al gruppo destinazione CurveLocal Crv1Loc( pGeomDB, nId1, frDest) ; CurveLocal Crv2Loc( pGeomDB, nId2, frDest) ; // intersezione fra le curve nel piano XY locale IntersCurveCurve intCC( *Crv1Loc, *Crv2Loc, true) ; int nInters = intCC.GetIntersCount() ; // recupero i punti risultanti for ( int i = 0 ; i < nInters ; i++) { IntCrvCrvInfo aInfo ; intCC.GetIntCrvCrvInfo( i, aInfo) ; // verifico se punto if ( ! aInfo.bOverlap) { PtrOwner pGeoPnt( CreateGeoPoint3d()) ; if ( IsNull( pGeoPnt)) return GDB_ID_NULL ; pGeoPnt->Set( aInfo.IciA[0].ptI) ; // lo inserisco nel DB geometrico int nNewId = pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrpId, Release( pGeoPnt)) ; if ( nNewId == GDB_ID_NULL) return GDB_ID_NULL ; // aggiorno parametri if ( nFirstId == GDB_ID_NULL) nFirstId = nNewId ; ++ nPntCount ; } } // recupero le curve risultanti for ( int i = 0 ; i < nInters ; i++) { IntCrvCrvInfo aInfo ; intCC.GetIntCrvCrvInfo( i, aInfo) ; // verifico se curva if ( aInfo.bOverlap) { PtrOwner pCrvRes( Crv1Loc->CopyParamRange( aInfo.IciA[0].dU, aInfo.IciA[1].dU)) ; if ( IsNull( pCrvRes)) return GDB_ID_NULL ; // lo inserisco nel DB geometrico int nNewId = pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrpId, Release( pCrvRes)) ; if ( nNewId == GDB_ID_NULL) return GDB_ID_NULL ; // aggiorno parametri if ( nFirstId == GDB_ID_NULL) nFirstId = nNewId ; ++ nCrvCount ; } } return nFirstId ; } //------------------------------------------------------------------------------- int ExeCurveCurveInters( const int nId1, const int nId2, const int nDestGrpId, int* pnPntCount, int* pnCrvCount) { // eseguo int nPntCount{ 0}, nCrvCount{ 0} ; int nFirstId = MyCurveCurveInters( nId1, nId2, nDestGrpId, nPntCount, nCrvCount) ; // aggiorno contatori if ( nFirstId != GDB_ID_NULL) { if ( pnPntCount != nullptr) *pnPntCount = nPntCount ; if ( pnCrvCount != nullptr) *pnCrvCount = nCrvCount ; ExeSetModified() ; } // se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtCurveCurveInters(" + ToString( nId1) + "," + ToString( nId2) + "," + ToString( nDestGrpId) + ")" + " -- Id=" + ToString( nFirstId) + ", nPntCnt=" + ToString( nPntCount) + ", nCrvCnt=" + ToString( nCrvCount) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } // restituisco l'identificativo della prima nuova entità return nFirstId ; } //------------------------------------------------------------------------------- static bool MyChainCurvesForSurfSurfInters( const BIPNTVECTOR& vBpt, IGeomDB* pGeomDB, int nDestGrpId, int nId1, double dToler, int& nFirstId, int& nCrvCount) { // Concateno i tratti di curva ChainCurves chainC ; chainC.Init( false, dToler, int( vBpt.size())) ; for ( int i = 0 ; i < int( vBpt.size()) ; ++ i) { Vector3d vtDir = vBpt[i].second - vBpt[i].first ; vtDir.Normalize() ; if ( ! chainC.AddCurve( i + 1, vBpt[i].first, vtDir, vBpt[i].second, vtDir)) return false ; } // recupero i percorsi concatenati ICRVCOMPOPOVECTOR vCrvCompo ; Point3d ptNear = ( vBpt.empty() ? ORIG : vBpt[0].first) ; INTVECTOR vId ; while ( chainC.GetChainFromNear( ptNear, true, vId)) { // creo una curva composita PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo)) return false ; // recupero gli estremi dei segmenti, creo le linee e le inserisco nella composita bool bAdded = true ; for ( int i = 0 ; i < int( vId.size()) ; ++ i) { // creo un segmento di retta PtrOwner pLine( CreateCurveLine()) ; if ( IsNull( pLine)) return GDB_ID_NULL ; // recupero gli estremi (non vanno mai invertiti per opzione di concatenamento) int nInd = abs( vId[i]) - 1 ; Point3d ptStart = ( bAdded ? vBpt[nInd].first : ptNear) ; Point3d ptEnd = vBpt[nInd].second ; // provo ad accodarlo alla composita bAdded = ( Dist( ptStart, ptEnd) > dToler / 2 && pLine->Set( ptStart, ptEnd) && pCrvCompo->AddCurve( Release( pLine), true, dToler)) ; ptNear = ( bAdded ? ptEnd : ptStart) ; } // se lunghezza curva inferiore a 5 volte la tolleranza, la salto double dCrvLen ; if ( ! pCrvCompo->GetLength( dCrvLen) || dCrvLen < 5 * dToler) continue ; // unisco segmenti allineati pCrvCompo->MergeCurves( dToler, ANG_TOL_STD_DEG) ; // la salvo vCrvCompo.emplace_back( Release( pCrvCompo)) ; } // Ripeto concatenamento sulle curve appena create (per riempire eventuali mini buchi) chainC.Init( false, dToler, int( vCrvCompo.size())) ; for ( int i = 0 ; i < int( vCrvCompo.size()) ; ++ i) { Point3d ptStart ; vCrvCompo[i]->GetStartPoint( ptStart) ; Vector3d vtStart ; vCrvCompo[i]->GetStartDir( vtStart) ; Point3d ptEnd ; vCrvCompo[i]->GetEndPoint( ptEnd) ; Vector3d vtEnd ; vCrvCompo[i]->GetEndDir( vtEnd) ; if ( ! chainC.AddCurve( i + 1, ptStart, vtStart, ptEnd, vtEnd)) return false ; } // recupero i percorsi concatenati if ( ! vCrvCompo.empty()) vCrvCompo[0]->GetStartPoint( ptNear) ; else ptNear = ORIG ; while ( chainC.GetChainFromNear( ptNear, true, vId)) { // creo una curva composita PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo)) return false ; // inserisco le curve nella composita for ( int i = 0 ; i < int( vId.size()) ; ++ i) { // recupero dati int nInd = abs( vId[i]) - 1 ; bool bInvert = ( vId[i] < 0) ; if ( bInvert) vCrvCompo[nInd]->Invert() ; // accodo if ( ! pCrvCompo->AddCurve( Release( vCrvCompo[nInd]), true, 1.1 * dToler)) return false ; // aggiorno il prossimo near pCrvCompo->GetEndPoint( ptNear) ; } // se curva chiusa entro 5 volte la tolleranza ma considerata aperta, la chiudo bene Point3d ptStart, ptEnd ; if ( pCrvCompo->GetStartPoint( ptStart) && pCrvCompo->GetEndPoint( ptEnd) && AreSamePointEpsilon( ptStart, ptEnd, 5 * dToler) && ! AreSamePointApprox( ptStart, ptEnd)) { // porto il punto finale a coincidere esattamente con l'inizio pCrvCompo->ModifyEnd( ptStart) ; } // unisco segmenti allineati pCrvCompo->MergeCurves( dToler, ANG_TOL_STD_DEG) ; // la inserisco nel DB geometrico int nNewId = pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrpId, Release( pCrvCompo)) ; if ( nNewId == GDB_ID_NULL) return false ; // copio il materiale if ( ! pGeomDB->CopyMaterial( nId1, nNewId)) return false ; // aggiorno contatori if ( nFirstId == GDB_ID_NULL) nFirstId = nNewId ; ++ nCrvCount ; } return true ; } //------------------------------------------------------------------------------- static int MySurfTmSurfTmInters( int nId1, int nId2, int nDestGrpId, double dToler, int& nPntCount, int& nCrvCount, int& nSrfCount) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, GDB_ID_NULL) // recupero il riferimento del gruppo di destinazione Frame3d frDest ; if ( ! pGeomDB->GetGroupGlobFrame( nDestGrpId, frDest)) return GDB_ID_NULL ; // recupero la prima superficie TriMesh espressa nel riferimento destinazione SurfLocal Surf1Loc( pGeomDB, nId1, frDest) ; const ISurfTriMesh* pStm1L = GetSurfTriMesh( Surf1Loc) ; if ( pStm1L == nullptr) return GDB_ID_NULL ; // recupero la seconda superficie TriMesh espressa nel riferimento destinazione SurfLocal Surf2Loc( pGeomDB, nId2, frDest) ; const ISurfTriMesh* pStm2L = GetSurfTriMesh( Surf2Loc) ; if ( pStm2L == nullptr) return GDB_ID_NULL ; // eseguo l'intersezione (già espressa nel riferimento destinazione) PNTVECTOR vPnt ; BIPNTVECTOR vBpt ; TRIA3DVECTOR vTria ; if ( ! IntersSurfTmSurfTm( *pStm1L, *pStm2L, vPnt, vBpt, vTria)) return GDB_ID_NULL ; // Inserisco il risultato nel DB int nFirstId = GDB_ID_NULL ; // Inserisco i punti nel DB for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) { // creo il punto PtrOwner pGeoPnt( CreateGeoPoint3d()) ; if ( IsNull( pGeoPnt)) return GDB_ID_NULL ; // setto il punto pGeoPnt->Set( vPnt[i]) ; // lo inserisco nel DB geometrico int nNewId = pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrpId, Release( pGeoPnt)) ; if ( nNewId == GDB_ID_NULL) return GDB_ID_NULL ; // copio il materiale if ( ! pGeomDB->CopyMaterial( nId1, nNewId)) return GDB_ID_NULL ; // aggiorno contatori if ( nFirstId == GDB_ID_NULL) nFirstId = nNewId ; ++ nPntCount ; } // Inserisco le curve nel DB (dopo averle concatenate) if ( ! MyChainCurvesForSurfSurfInters( vBpt, pGeomDB, nDestGrpId, nId1, dToler, nFirstId, nCrvCount)) return GDB_ID_NULL ; // Inserisco i triangoli nel DB (dopo averli uniti in una superficie trimesh) StmFromTriangleSoup StmFts ; if ( ! StmFts.Start()) return GDB_ID_NULL ; for ( int i = 0 ; i < int( vTria.size()) ; ++ i) // inserisco il triangolo nella nuova superficie StmFts.AddTriangle( vTria[i]) ; // valido la superficie e calcolo le adiacenze if ( ! StmFts.End()) return GDB_ID_NULL ; // se superficie con triangoli PtrOwner pNewStm( StmFts.GetSurf()) ; if ( ! IsNull( pNewStm) && pNewStm->GetTriangleCount() > 0) { // la inserisco nel DB int nNewId = pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrpId, Release( pNewStm)) ; if ( nNewId == GDB_ID_NULL) return GDB_ID_NULL ; // copio il materiale if ( ! pGeomDB->CopyMaterial( nId1, nNewId)) return GDB_ID_NULL ; // aggiorno contatori if ( nFirstId == GDB_ID_NULL) nFirstId = nNewId ; ++ nSrfCount ; } // restituisco l'identificativo della prima nuova entità return nFirstId ; } //------------------------------------------------------------------------------- int ExeSurfTmSurfTmInters( int nId1, int nId2, int nDestGrpId, double dToler, int* pnPntCount, int* pnCrvCount, int* pnSrfCount) { // eseguo int nPntCount{ 0}, nCrvCount{ 0}, nSrfCount{ 0} ; int nFirstId = MySurfTmSurfTmInters( nId1, nId2, nDestGrpId, dToler, nPntCount, nCrvCount, nSrfCount) ; // aggiorno contatori if ( nFirstId != GDB_ID_NULL) { if ( pnPntCount != nullptr) *pnPntCount = nPntCount ; if ( pnCrvCount != nullptr) *pnCrvCount = nCrvCount ; if ( pnSrfCount != nullptr) *pnSrfCount = nSrfCount ; ExeSetModified() ; } // se richiesto, salvo il comando Lua equivalente if ( IsCmdLog()) { string sLua = "EgtSurfTmSurfTmInters(" + ToString( nId1) + "," + ToString( nId2) + "," + ToString( nDestGrpId) + "," + ToString( dToler) + ")" + " -- Id1=" + ToString( nFirstId) + ", PntNbr=" + ToString( nPntCount) + ", CrvNbr=" + ToString( nCrvCount) + ", SrfNbr=" + ToString( nSrfCount) ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } // restituisco l'identificativo della prima nuova entità return nFirstId ; }