//---------------------------------------------------------------------------- // EgalTech 2015-2015 //---------------------------------------------------------------------------- // File : EXE_NstPartNesting.cpp Data : 30.12.15 Versione : 1.6l5 // Contenuto : Funzioni Nesting di Pezzi per EXE. // // // // Modifiche : 30.12.15 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "EXE.h" #include "EXE_Const.h" #include "EXE_Macro.h" #include "EXE_Nst.h" #include "/EgtDev/Include/EXeExecutor.h" #include "/EgtDev/Include/EXeConst.h" #include "/EgtDev/Include/EGkCurveLine.h" #include "/EgtDev/Include/EGkCurveComposite.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EGkSimpleCDSurfFrMove.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EMkMachiningGeoConst.h" #include "/EgtDev/Include/EgtPointerOwner.h" using namespace std ; //---------------------------------------------------------------------------- struct SCollInfoEx : public SCollInfo { int nIdM ; // identificativo della regione mobile bool bIsCutM ; // flag di regione di pezzo o di taglio int nIdF ; // identificativo della regione fissa bool bIsCutF ; // flag di regione di pezzo o di taglio // costruttori SCollInfoEx() : SCollInfo(), nIdM( GDB_ID_NULL), bIsCutM( false), nIdF( GDB_ID_NULL), bIsCutF( false) {} SCollInfoEx( const SCollInfo& Sou) : SCollInfo( Sou), nIdM( GDB_ID_NULL), bIsCutM( false), nIdF( GDB_ID_NULL), bIsCutF( false) {} } ; //---------------------------------------------------------------------------- int GetFlatPartRegion( IGeomDB* pGeomDB, int nId) { // recupero regione del pezzo (è la prima del sottogruppo di nome Region) int nRegGrp = pGeomDB->GetFirstNameInGroup( nId, NST_PARTREG_LAYER) ; int nRegId = pGeomDB->GetFirstInGroup( nRegGrp) ; while ( nRegId != GDB_ID_NULL) { if ( pGeomDB->GetGeoType( nRegId) == SRF_FLATRGN) break ; nRegId = pGeomDB->GetNext( nRegId) ; } return nRegId ; } //---------------------------------------------------------------------------- bool GetFlatPartCutRegions( IGeomDB* pGeomDB, int nId, bool bReduced, INTVECTOR& vCrId) { // recupero gruppo preview lavorazioni del pezzo int nPVGrp = pGeomDB->GetFirstNameInGroup( nId, MCH_PV) ; if ( nPVGrp == GDB_ID_NULL) return true ; // ciclo sulle lavorazioni int nMchId = pGeomDB->GetFirstGroupInGroup( nPVGrp) ; while ( nMchId != GDB_ID_NULL) { int nClId = pGeomDB->GetFirstGroupInGroup( nMchId) ; while ( nClId != GDB_ID_NULL) { int nCrId = pGeomDB->GetFirstNameInGroup( nClId, ( bReduced ? MCH_PV_RRCUT : MCH_PV_RCUT)) ; while ( nCrId != GDB_ID_NULL) { vCrId.emplace_back( nCrId) ; nCrId = pGeomDB->GetNextName( nCrId, ( bReduced ? MCH_PV_RRCUT : MCH_PV_RCUT)) ; } nClId = pGeomDB->GetNextGroup( nClId) ; } nMchId = pGeomDB->GetNextGroup( nMchId) ; } return true ; } //---------------------------------------------------------------------------- int GetFlatPartFromRegion( IGeomDB* pGeomDB, int nId) { // verifico che il layer di appartenenza sia una regione int nLayerId = pGeomDB->GetParentId( nId) ; string sName ; if ( ! pGeomDB->GetName( nLayerId, sName) && ! EqualNoCase( sName, NST_PARTREG_LAYER)) return GDB_ID_NULL ; // restituisco il padre del layer return ( pGeomDB->GetParentId( nLayerId)) ; } //---------------------------------------------------------------------------- int GetFlatPartFromCut( IGeomDB* pGeomDB, int nId) { // verifico appartenga al gruppo PreView (padre di padre di padre) int nPvId = pGeomDB->GetParentId( pGeomDB->GetParentId( pGeomDB->GetParentId( nId))) ; string sName ; if ( ! pGeomDB->GetName( nPvId, sName) && ! EqualNoCase( sName, MCH_PV)) return GDB_ID_NULL ; // restituisco il padre del layer return ( pGeomDB->GetParentId( nPvId)) ; } //---------------------------------------------------------------------------- int GetGeometryFromCut( IGeomDB* pGeomDB, IMachMgr* pMachMgr, int nId) { // verifico appartenga ad una lavorazione int nMchId ; if ( ! pGeomDB->GetInfo( pGeomDB->GetParentId( pGeomDB->GetParentId( nId)), "MId", nMchId)) return GDB_ID_NULL ; // recupero la geometria di applicazione della lavorazione (deve essere una sola) if ( ! pMachMgr->SetCurrMachining( nMchId)) return GDB_ID_NULL ; SELVECTOR vIds ; pMachMgr->GetMachiningGeometry( vIds) ; if ( vIds.size() == 1) return vIds[0].nId ; else return GDB_ID_NULL ; } //---------------------------------------------------------------------------- static int CreateOutBoxRegion( IGeomDB* pGeomDB, int nParentId, double dXmin, double dYmin, double dXmax, double dYmax, double dZ) { // creo polilinea attorno al box (avvolta a serpente) const double SPESS = 100 ; const double DELTA = 1 ; PolyLine PL ; PL.AddUPoint( 0, Point3d( dXmin, dYmin, dZ)) ; PL.AddUPoint( 1, Point3d( dXmin, dYmax, dZ)) ; PL.AddUPoint( 2, Point3d( dXmax, dYmax, dZ)) ; PL.AddUPoint( 3, Point3d( dXmax, dYmin + DELTA + 2 * EPS_SMALL, dZ)) ; PL.AddUPoint( 4, Point3d( dXmax + SPESS, dYmin + DELTA + 2 * EPS_SMALL, dZ)) ; PL.AddUPoint( 5, Point3d( dXmax + SPESS, dYmax + SPESS, dZ)) ; PL.AddUPoint( 6, Point3d( dXmin - SPESS, dYmax + SPESS, dZ)) ; PL.AddUPoint( 7, Point3d( dXmin - SPESS, dYmin - SPESS, dZ)) ; PL.AddUPoint( 8, Point3d( dXmax + SPESS, dYmin - SPESS, dZ)) ; PL.AddUPoint( 9, Point3d( dXmax + SPESS, dYmin + DELTA, dZ)) ; PL.AddUPoint( 10, Point3d( dXmax, dYmin + DELTA, dZ)) ; PL.AddUPoint( 11, Point3d( dXmax, dYmin, dZ)) ; PL.Close() ; // la converto in curva composita PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo) || ! pCompo->FromPolyLine( PL)) return GDB_ID_NULL ; // costruisco la regione piana SurfFlatRegionByContours SfrCntr ; SfrCntr.AddCurve( Release( pCompo)) ; ISurfFlatRegion* pSfr = SfrCntr.GetSurf() ; if ( pSfr == nullptr) return GDB_ID_NULL ; // recupero il riferimento del gruppo di inserimento Frame3d frLoc ; if ( ! pGeomDB->GetGroupGlobFrame( nParentId, frLoc)) return GDB_ID_NULL ; // porto la regione nel riferimento pSfr->ToLoc( frLoc) ; // inserisco la superficie nel DB int nId = pGeomDB->AddGeoObj( GDB_ID_NULL, nParentId, pSfr) ; if ( nId == GDB_ID_NULL) return GDB_ID_NULL ; // assegno nome e la dichiaro temporanea e invisibile pGeomDB->SetName( nId, NST_SHEET_OUTREG) ; pGeomDB->SetLevel( nId, GDB_LV_SYSTEM) ; pGeomDB->SetMaterial( nId, INVISIBLE) ; return nId ; } //---------------------------------------------------------------------------- static bool SetPreviewStatus( IGeomDB* pGeomDB, const INTVECTOR& vIds, bool bShow) { for ( const auto nId : vIds) { int nPvId = pGeomDB->GetFirstNameInGroup(nId, MCH_PV) ; pGeomDB->SetStatus( nPvId, ( bShow ? GDB_ST_ON : GDB_ST_OFF)) ; } return true ; } //---------------------------------------------------------------------------- static bool UpdateToolOffset( IGeomDB* pGeomDB, const INTVECTOR& vIds, bool bReducedCut, double& dOffs) { for ( const auto nId : vIds) { int nPvId = pGeomDB->GetFirstNameInGroup(nId, MCH_PV) ; int nCutId = pGeomDB->GetFirstGroupInGroup( nPvId) ; while ( nCutId != GDB_ID_NULL) { int nPathId = pGeomDB->GetFirstGroupInGroup( nCutId) ; while ( nPathId != GDB_ID_NULL) { double dVal ; if ( pGeomDB->GetInfo( nPathId, MCH_PV_KEY_WT, dVal) && dVal > dOffs) dOffs = dVal ; if ( ! bReducedCut && pGeomDB->GetInfo( nPathId, MCH_PV_KEY_DT, dVal) && dVal > dOffs) dOffs = dVal ; nPathId = pGeomDB->GetNextGroup( nPathId) ; } nCutId = pGeomDB->GetNextGroup( nCutId) ; } } return true ; } //---------------------------------------------------------------------------- bool ExeVerifyPartCluster( const INTVECTOR& vIds, bool bReducedCut, double dXmin, double dYmin, double dXmax, double dYmax) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Box della regione di interesse BBox3d b3Region( dXmin, dYmin, 0, dXmax, dYmax, 0) ; // Flag per calcolo box const int BBF_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ; // Risolvo eventuali riferimenti a oggetti selezionati, compresi nella regione e // calcolo il box del cluster risultante INTVECTOR vTrueIds ; vTrueIds.reserve( vIds.size()) ; BBox3d b3Cluster ; for ( auto nId : vIds) { int nTrueId = (( nId != GDB_ID_SEL) ? nId : pGeomDB->GetFirstSelectedObj()) ; while ( nTrueId != GDB_ID_NULL) { BBox3d b3Part ; if ( pGeomDB->GetGlobalBBox( nTrueId, b3Part, BBF_MY_FLAG)) { // inserisco l'identificativo nel vettore dei validi vTrueIds.push_back( nTrueId) ; // aggiorno il box del cluster b3Cluster.Add( b3Part) ; } // passo al successivo nTrueId = (( nId != GDB_ID_SEL) ? GDB_ID_NULL : pGeomDB->GetNextSelectedObj()) ; } } // Se non sono rimasti oggetti, esco con successo if ( vTrueIds.empty()) return true ; // Determino le regioni dei pezzi rimasti INTVECTOR vReg ; INTVECTOR vCutReg ; BBox3d b3RegCluster ; for ( int nId : vTrueIds) { // recupero regione del pezzo int nRegId = GetFlatPartRegion( pGeomDB, nId) ; BBox3d b3Reg ; if ( pGeomDB->GetGlobalBBox( nRegId, b3Reg, BBF_MY_FLAG)) { vReg.emplace_back( nRegId) ; b3RegCluster.Add( b3Reg) ; } else return false ; // recupero regioni dei tagli del pezzo if ( ! GetFlatPartCutRegions( pGeomDB, nId, bReducedCut, vCutReg)) return false ; } // Verifico di essere all'interno del box esterno if ( ! b3Region.EnclosesXY( b3RegCluster)) return false ; // Verifico se pezzi sotto la radice o pezzi in altro gruppo int nGroupId = pGeomDB->GetParentId( vTrueIds[0]) ; bool bInRoot = ( nGroupId == GDB_ID_ROOT) ; // Determino le regioni di tutti gli altri pezzi compresi nella regione di interesse INTVECTOR vOthReg ; INTVECTOR vOthCutReg ; int nId2 = ( bInRoot ? ExeGetFirstPart( true) : ExeGetFirstGroupInGroup( nGroupId)) ; while ( nId2 != GDB_ID_NULL) { if ( find( vTrueIds.begin(), vTrueIds.end(), nId2) == vTrueIds.end()) { BBox3d b3Part2 ; if ( pGeomDB->GetGlobalBBox( nId2, b3Part2, BBF_MY_FLAG) && b3Cluster.OverlapsXY( b3Part2)) { // recupero regione del pezzo int nRegId = GetFlatPartRegion( pGeomDB, nId2) ; if ( nRegId != GDB_ID_NULL) vOthReg.emplace_back( nRegId) ; else return false ; // recupero regioni dei tagli del pezzo if ( ! GetFlatPartCutRegions( pGeomDB, nId2, bReducedCut, vOthCutReg)) return false ; } } nId2 = ( bInRoot ? ExeGetNextPart( nId2, true) : ExeGetNextGroup( nId2)) ; } // Eseguo verifiche bool bOk = true ; // regioni dei pezzi for ( int nRegId : vReg) { // verifico con le regioni degli altri pezzi for ( int nOthRegId : vOthReg) { if ( ExeSurfFrChunkSimpleClassify( nRegId, 0, nOthRegId, 0) != REGC_OUT) bOk = false ; } // e con le regioni dei tagli degli altri pezzi for ( int nOthCutRegId : vOthCutReg) { if ( ExeSurfFrChunkSimpleClassify( nRegId, 0, nOthCutRegId, 0) != REGC_OUT) bOk = false ; } } // regioni delle lavorazioni dei pezzi for ( int nCutRegId : vCutReg) { // le confronto con le regioni degli altri pezzi for ( int nOthRegId : vOthReg) { if ( ExeSurfFrChunkSimpleClassify( nCutRegId, 0, nOthRegId, 0) != REGC_OUT) bOk = false ; } } return bOk ; } //---------------------------------------------------------------------------- static bool MyPackPartCluster( const INTVECTOR& vIds, bool bReducedCut, double dXmin, double dYmin, double dXmax, double dYmax, bool bBottomUp) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Verifiche sui parametri if ( dXmax < dXmin + EPS_SMALL || dYmax < dYmin + EPS_SMALL) return false ; // Risolvo eventuali riferimenti a oggetti selezionati INTVECTOR vTrueIds ; vTrueIds.reserve( vIds.size()) ; for ( auto nId : vIds) { int nTrueId = (( nId != GDB_ID_SEL) ? nId : pGeomDB->GetFirstSelectedObj()) ; while ( nTrueId != GDB_ID_NULL) { vTrueIds.push_back( nTrueId) ; // passo al successivo nTrueId = (( nId != GDB_ID_SEL) ? GDB_ID_NULL : pGeomDB->GetNextSelectedObj()) ; } } // Se non sono rimasti oggetti, esco con successo if ( vTrueIds.empty()) return true ; // Verifico se pezzi sotto la radice o pezzi in altro gruppo int nGroupId = pGeomDB->GetParentId( vTrueIds[0]) ; bool bInRoot = ( nGroupId == GDB_ID_ROOT) ; // Box della regione di interesse BBox3d b3Region( dXmin, dYmin, 0, dXmax, dYmax, 0) ; // Flag per calcolo box const int BBF_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ; // Determino tutti gli altri pezzi compresi nella regione di interesse INTVECTOR vOtherIds ; int nId2 = ( bInRoot ? ExeGetFirstPart( true) : ExeGetFirstGroupInGroup( nGroupId)) ; while ( nId2 != GDB_ID_NULL) { if ( find( vTrueIds.begin(), vTrueIds.end(), nId2) == vTrueIds.end()) { BBox3d b3Part2 ; if ( pGeomDB->GetGlobalBBox( nId2, b3Part2, BBF_MY_FLAG) && b3Region.OverlapsXY( b3Part2)) { vOtherIds.emplace_back( nId2) ; } } nId2 = ( bInRoot ? ExeGetNextPart( nId2, true) : ExeGetNextGroup( nId2)) ; } // nascondo preview delle lavorazioni SetPreviewStatus( pGeomDB, vTrueIds, false) ; SetPreviewStatus( pGeomDB, vOtherIds, false) ; // calcolo offset per ingombro lavorazioni double dOffs = 0 ; UpdateToolOffset( pGeomDB, vTrueIds, bReducedCut, dOffs) ; UpdateToolOffset( pGeomDB, vOtherIds, bReducedCut, dOffs) ; // eseguo primo movimento come box bool bOk = ExePackBoxCluster( vTrueIds, dXmin, dYmin, dXmax, dYmax, dOffs, bBottomUp) ; // ripristino preview delle lavorazioni SetPreviewStatus( pGeomDB, vTrueIds, true) ; SetPreviewStatus( pGeomDB, vOtherIds, true) ; // se inserimento di massima riuscito, provo a migliorare if ( bOk) { const double BIG_MOVE = 1000 ; Vector3d vtMoveY = ( bBottomUp ? - 1 : 1) * BIG_MOVE * Y_AX ; ExeMovePartCluster( vTrueIds, bReducedCut, vtMoveY, dXmin, dYmin, dXmax, dYmax) ; Vector3d vtMoveX = - BIG_MOVE * X_AX ; ExeMovePartCluster( vTrueIds, bReducedCut, vtMoveX, dXmin, dYmin, dXmax, dYmax) ; } return bOk ; } //---------------------------------------------------------------------------- bool ExePackPartCluster( const INTVECTOR& vIds, bool bReducedCut, double dXmin, double dYmin, double dXmax, double dYmax, bool bBottomUp) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Risolvo eventuali riferimenti a oggetti selezionati INTVECTOR vTrueIds ; vTrueIds.reserve( vIds.size()) ; for ( auto nId : vIds) { int nTrueId = (( nId != GDB_ID_SEL) ? nId : pGeomDB->GetFirstSelectedObj()) ; while ( nTrueId != GDB_ID_NULL) { vTrueIds.push_back( nTrueId) ; // passo al successivo nTrueId = (( nId != GDB_ID_SEL) ? GDB_ID_NULL : pGeomDB->GetNextSelectedObj()) ; } } // se con tagli ridotti if ( bReducedCut) { return MyPackPartCluster( vTrueIds, true, dXmin, dYmin, dXmax, dYmax, bBottomUp) ; } // altrimenti else { // provo con tagli ridotti if ( ! MyPackPartCluster( vTrueIds, true, dXmin, dYmin, dXmax, dYmax, bBottomUp)) return false ; // se posizione valida if ( ExeVerifyPartCluster( vTrueIds, false, dXmin, dYmin, dXmax, dYmax)) { return true ; } // altrimenti, riprovo con tagli standard else { return MyPackPartCluster( vTrueIds, false, dXmin, dYmin, dXmax, dYmax, bBottomUp) ; } } } //---------------------------------------------------------------------------- static SCollInfoEx s_scInfo ; static SCollInfoEx s_scInfoSaved ; //---------------------------------------------------------------------------- static double UpdateCollId( double dLen, double dPrevLen, int nId1, int nId2, bool bIsCut1, bool bIsCut2, SCollInfo scInfoCurr) { if ( abs( dLen - dPrevLen) < EPS_SMALL) { if ( scInfoCurr.nType == SCI_PNT_LINE || scInfoCurr.nType == SCI_LINE_LINE) { s_scInfo = scInfoCurr ; s_scInfo.nIdM = nId1 ; s_scInfo.nIdF = nId2 ; s_scInfo.bIsCutM = bIsCut1 ; s_scInfo.bIsCutF = bIsCut2 ; } return dPrevLen ; } else if ( dLen < dPrevLen) { s_scInfo = scInfoCurr ; s_scInfo.nIdM = nId1 ; s_scInfo.nIdF = nId2 ; s_scInfo.bIsCutM = bIsCut1 ; s_scInfo.bIsCutF = bIsCut2 ; return dLen ; } else return dPrevLen ; } //---------------------------------------------------------------------------- static bool MySurfFrMoveSimpleNoCollision( int nId1, int nId2, const Vector3d& vtDir, double& dLen, SCollInfo& scInfo) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, GDB_ID_NULL) // recupero la prima superficie FlatRegion ISurfFlatRegion* pSfr1 = GetSurfFlatRegion( pGeomDB->GetGeoObj( nId1)) ; bool bOk = ( pSfr1 != nullptr) ; // recupero il riferimento della superficie Frame3d frSurf1 ; bOk = bOk && pGeomDB->GetGlobFrame( nId1, frSurf1) ; // recupero la seconda superficie FlatRegion const ISurfFlatRegion* pSfr2 = GetSurfFlatRegion( pGeomDB->GetGeoObj( nId2)) ; bOk = bOk && ( pSfr2 != nullptr) ; // recupero il riferimento della superficie Frame3d frSurf2 ; bOk = bOk && pGeomDB->GetGlobFrame( nId2, frSurf2) ; // se riferimenti diversi, porto una copia della seconda nel riferimento della prima const ISurfFlatRegion* pSfr2L = pSfr2 ; PtrOwnerpTmp ; if ( ! AreSameFrame( frSurf1, frSurf2)) { pTmp.Set( CloneSurfFlatRegion( pSfr2)) ; bOk = bOk && ! IsNull( pTmp) ; bOk = bOk && pTmp->LocToLoc( frSurf2, frSurf1) ; pSfr2L = Get( pTmp) ; } // porto in locale alla prima superficie il versore di movimento Vector3d vtDirL = vtDir ; vtDirL.ToLoc( frSurf1) ; // calcolo massima lunghezza di traslazione della prima regione senza semplice collisione con la seconda SimpleCDSurfFrMove ScdSfrMove( *pSfr1, *pSfr2L) ; bOk = bOk && ScdSfrMove.Translate( vtDirL, dLen) ; if ( bOk) { scInfo = ScdSfrMove.GetSCollInfo() ; if ( scInfo.nType != SCI_NONE) { scInfo.ptP1.ToGlob( frSurf1) ; scInfo.vtDirM.ToGlob( frSurf1) ; scInfo.vtDirF.ToGlob( frSurf1) ; } if ( scInfo.nType == SCI_LINE_LINE) scInfo.ptP2.ToGlob( frSurf1) ; } return bOk ; } //---------------------------------------------------------------------------- static bool MyMovePartCluster( const INTVECTOR& vIds, bool bReducedCut, Vector3d& vtMove, double dXmin, double dYmin, double dXmax, double dYmax) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Verifiche sui parametri if ( dXmax < dXmin + EPS_SMALL || dYmax < dYmin + EPS_SMALL) return false ; // Reset info di collisione s_scInfo.nType = SCI_NONE ; // Vettore movimento nel piano XY globale Vector3d vtMoveXY( vtMove.x, vtMove.y, 0) ; vtMove = V_NULL ; if ( vtMoveXY.IsSmall()) return true ; // Box della regione di interesse BBox3d b3Region( dXmin, dYmin, 0, dXmax, dYmax, 0) ; // Flag per calcolo box const int BBF_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ; // Risolvo eventuali riferimenti a oggetti selezionati, compresi nella regione e // calcolo il box del cluster risultante INTVECTOR vTrueIds ; vTrueIds.reserve( vIds.size()) ; BBox3d b3Cluster ; for ( auto nId : vIds) { int nTrueId = (( nId != GDB_ID_SEL) ? nId : pGeomDB->GetFirstSelectedObj()) ; while ( nTrueId != GDB_ID_NULL) { BBox3d b3Part ; if ( pGeomDB->GetGlobalBBox( nTrueId, b3Part, BBF_MY_FLAG) && b3Region.OverlapsXY( b3Part)) { // inserisco l'identificativo nel vettore dei validi vTrueIds.push_back( nTrueId) ; // aggiorno il box del cluster b3Cluster.Add( b3Part) ; } // passo al successivo nTrueId = (( nId != GDB_ID_SEL) ? GDB_ID_NULL : pGeomDB->GetNextSelectedObj()) ; } } // Se non sono rimasti oggetti, esco con successo if ( vTrueIds.empty()) return true ; // Verifico se pezzi sotto la radice o pezzi in altro gruppo int nGroupId = pGeomDB->GetParentId( vTrueIds[0]) ; bool bInRoot = ( nGroupId == GDB_ID_ROOT) ; // Determino le regioni di tutti gli altri pezzi compresi nella regione di interesse INTVECTOR vOthReg ; INTVECTOR vOthCutReg ; int nId2 = ( bInRoot ? ExeGetFirstPart( true) : ExeGetFirstGroupInGroup( nGroupId)) ; while ( nId2 != GDB_ID_NULL) { if ( find( vTrueIds.begin(), vTrueIds.end(), nId2) == vTrueIds.end()) { BBox3d b3Part2 ; if ( pGeomDB->GetGlobalBBox( nId2, b3Part2, BBF_MY_FLAG) && b3Region.OverlapsXY( b3Part2)) { // recupero regione del pezzo int nRegId = GetFlatPartRegion( pGeomDB, nId2) ; if ( nRegId != GDB_ID_NULL) vOthReg.emplace_back( nRegId) ; else return false ; // recupero regioni dei tagli del pezzo if ( ! GetFlatPartCutRegions( pGeomDB, nId2, bReducedCut, vOthCutReg)) return false ; } } nId2 = ( bInRoot ? ExeGetNextPart( nId2, true) : ExeGetNextGroup( nId2)) ; } // Se non esiste, creo SurfFlatRegion che delimita la regione valida int nBoxId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_SHEET_OUTREG) ; if ( nBoxId == GDB_ID_NULL) nBoxId = CreateOutBoxRegion( pGeomDB, nGroupId, dXmin, dYmin, dXmax, dYmax, b3Cluster.GetMin().z) ; if ( nBoxId == GDB_ID_NULL) return false ; // Verifico movimento dei pezzi del cluster rispetto agli altri pezzi bool bOk = true ; double dLen = vtMoveXY.Len() ; double dPrevLen = dLen ; Vector3d vtDir = ( dLen > EPS_SMALL ? vtMoveXY / dLen : V_NULL) ; for ( auto nTrueId : vTrueIds) { // recupero regione del pezzo int nRegId = GetFlatPartRegion( pGeomDB, nTrueId) ; if ( nRegId == GDB_ID_NULL) { bOk = false ; break ; } // info di collisione correnti SCollInfo scInfoCurr ; // la confronto con il box MySurfFrMoveSimpleNoCollision( nRegId, nBoxId, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nRegId, nBoxId, false, false, scInfoCurr) ; // la confronto con le regioni degli altri pezzi for ( int nOthRegId : vOthReg) { MySurfFrMoveSimpleNoCollision( nRegId, nOthRegId, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nRegId, nOthRegId, false, false, scInfoCurr) ; } // e con le regioni dei tagli degli altri pezzi for ( int nOthCutRegId : vOthCutReg) { MySurfFrMoveSimpleNoCollision( nRegId, nOthCutRegId, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nRegId, nOthCutRegId, false, true, scInfoCurr) ; } // recupero regioni di lavorazione del pezzo INTVECTOR vCrId ; if ( ! GetFlatPartCutRegions( pGeomDB, nTrueId, bReducedCut, vCrId)) { bOk = false ; break ; } // le confronto con le regioni degli altri pezzi for ( int nCrId : vCrId) { for ( int nOthRegId : vOthReg) { MySurfFrMoveSimpleNoCollision( nCrId, nOthRegId, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nCrId, nOthRegId, true, false, scInfoCurr) ; } } } // Se errore if ( ! bOk) return false ; // Log per debug if ( false) { if ( s_scInfo.nType != SCI_NONE) { string sOut = "Id1=" + ToString( s_scInfo.nIdM) + " Id2=" + ToString( s_scInfo.nIdF) + " Info type=" ; switch ( s_scInfo.nType) { case SCI_NONE : sOut += "NONE" ; break ; case SCI_PNT_PNT : sOut += "PNT_PNT" ; break ; case SCI_PNT_LINE : sOut += "PNT_LINE" ; break ; case SCI_LINE_PNT : sOut += "LINE_PNT" ; break ; case SCI_LINE_LINE : sOut += "LINE_LINE" ; break ; } sOut += " Crv1=" + ToString( s_scInfo.nCrvM) + " Crv2=" + ToString( s_scInfo.nCrvF) ; sOut += " ptA=(" + ToString( s_scInfo.ptP1) + ")" ; if ( s_scInfo.nType == SCI_LINE_LINE) sOut += " ptB=(" + ToString( s_scInfo.ptP2) + ")" ; if ( s_scInfo.nType == SCI_LINE_PNT || s_scInfo.nType == SCI_LINE_LINE) sOut += " Dir1=(" + ToString( s_scInfo.vtDirM) + ")" ; if ( s_scInfo.nType == SCI_PNT_LINE || s_scInfo.nType == SCI_LINE_LINE) sOut += " Dir2=(" + ToString( s_scInfo.vtDirF) + ")" ; LOG_INFO( GetLogger(), sOut.c_str()) ; } } // Se movimento risultante nullo, non faccio alcunché vtMoveXY = vtDir * dLen ; if ( vtMoveXY.IsSmall()) return true ; // Eseguo movimento dei pezzi del cluster for ( auto nTrueId : vTrueIds) pGeomDB->TranslateGlob( nTrueId, vtMoveXY) ; ExeSetModified() ; vtMove = vtMoveXY ; return true ; } //---------------------------------------------------------------------------- bool ExeMovePartCluster( const INTVECTOR& vIds, bool bReducedCut, Vector3d& vtMove, double dXmin, double dYmin, double dXmax, double dYmax) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Risolvo eventuali riferimenti a oggetti selezionati INTVECTOR vTrueIds ; vTrueIds.reserve( vIds.size()) ; for ( auto nId : vIds) { int nTrueId = (( nId != GDB_ID_SEL) ? nId : pGeomDB->GetFirstSelectedObj()) ; while ( nTrueId != GDB_ID_NULL) { vTrueIds.push_back( nTrueId) ; // passo al successivo nTrueId = (( nId != GDB_ID_SEL) ? GDB_ID_NULL : pGeomDB->GetNextSelectedObj()) ; } } // se con tagli ridotti if ( bReducedCut) { return MyMovePartCluster( vTrueIds, true, vtMove, dXmin, dYmin, dXmax, dYmax) ; } // altrimenti else { // provo con tagli ridotti Vector3d vtM = vtMove ; if ( ! MyMovePartCluster( vTrueIds, true, vtM, dXmin, dYmin, dXmax, dYmax)) return false ; // se posizione valida if ( ExeVerifyPartCluster( vTrueIds, false, dXmin, dYmin, dXmax, dYmax)) { vtMove = vtM ; return true ; } // altrimenti, riprovo con tagli standard else { // annullo il movimento for ( int nId : vTrueIds) pGeomDB->TranslateGlob( nId, - vtM) ; // riprovo return MyMovePartCluster( vTrueIds, false, vtMove, dXmin, dYmin, dXmax, dYmax) ; } } } //---------------------------------------------------------------------------- bool ExeRotatePartCluster( const INTVECTOR& vIds, bool bReducedCut, const Point3d& ptCen, double& dRotAngDeg, double dXmin, double dYmin, double dXmax, double dYmax) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Verifiche sui parametri if ( dXmax < dXmin + EPS_SMALL || dYmax < dYmin + EPS_SMALL) return false ; // Reset info di collisione s_scInfo.nType = SCI_NONE ; // Rotazione nel piano XY globale // Box della regione di interesse BBox3d b3Region( dXmin, dYmin, 0, dXmax, dYmax, 0) ; // Flag per calcolo box const int BBF_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ; // Risolvo eventuali riferimenti a oggetti selezionati, compresi nella regione e // calcolo il box del cluster risultante INTVECTOR vTrueIds ; vTrueIds.reserve( vIds.size()) ; BBox3d b3Cluster ; for ( auto nId : vIds) { int nTrueId = (( nId != GDB_ID_SEL) ? nId : pGeomDB->GetFirstSelectedObj()) ; while ( nTrueId != GDB_ID_NULL) { BBox3d b3Part ; if ( pGeomDB->GetGlobalBBox( nTrueId, b3Part, BBF_MY_FLAG) && b3Region.OverlapsXY( b3Part)) { // inserisco l'identificativo nel vettore dei validi vTrueIds.push_back( nTrueId) ; // aggiorno il box del cluster b3Cluster.Add( b3Part) ; } // passo al successivo nTrueId = (( nId != GDB_ID_SEL) ? GDB_ID_NULL : pGeomDB->GetNextSelectedObj()) ; } } // Se non sono rimasti oggetti, esco con successo if ( vTrueIds.empty()) return true ; // Verifico se pezzi sotto la radice o pezzi in altro gruppo int nGroupId = pGeomDB->GetParentId( vTrueIds[0]) ; bool bInRoot = ( nGroupId == GDB_ID_ROOT) ; // Determino le regioni di tutti gli altri pezzi compresi nella regione di interesse INTVECTOR vReg ; INTVECTOR vCutReg ; int nId2 = ( bInRoot ? ExeGetFirstPart( true) : ExeGetFirstGroupInGroup( nGroupId)) ; while ( nId2 != GDB_ID_NULL) { if ( find( vTrueIds.begin(), vTrueIds.end(), nId2) == vTrueIds.end()) { BBox3d b3Part2 ; if ( pGeomDB->GetGlobalBBox( nId2, b3Part2, BBF_MY_FLAG) && b3Region.OverlapsXY( b3Part2)) { // recupero regione del pezzo int nRegId = GetFlatPartRegion( pGeomDB, nId2) ; if ( nRegId != GDB_ID_NULL) vReg.emplace_back( nRegId) ; else return false ; // recupero regioni dei tagli del pezzo if ( ! GetFlatPartCutRegions( pGeomDB, nId2, bReducedCut, vCutReg)) return false ; } } nId2 = ( bInRoot ? ExeGetNextPart( nId2, true) : ExeGetNextGroup( nId2)) ; } // Creo SurfFlatRegion che delimita la regione valida int nBoxId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_SHEET_OUTREG) ; if ( nBoxId == GDB_ID_NULL) nBoxId = CreateOutBoxRegion( pGeomDB, nGroupId, dXmin, dYmin, dXmax, dYmax, b3Cluster.GetMin().z) ; if ( nBoxId == GDB_ID_NULL) return false ; // Verifico rotazione dei pezzi del cluster rispetto agli altri pezzi bool bOk = true ; double dAng = dRotAngDeg ; for ( auto nTrueId : vTrueIds) { // recupero regione del pezzo int nRegId = GetFlatPartRegion( pGeomDB, nTrueId) ; if ( nRegId == GDB_ID_NULL) { bOk = false ; break ; } // la confronto con il box ExeSurfFrRotateSimpleNoCollision( nRegId, nBoxId, ptCen, dAng, RTY_GLOB) ; // la confronto con le regioni degli altri pezzi for ( int nOthRegId : vReg) { ExeSurfFrRotateSimpleNoCollision( nRegId, nOthRegId, ptCen, dAng, RTY_GLOB) ; } // e con le regioni dei tagli degli altri pezzi for ( int nOthCutRegId : vCutReg) { ExeSurfFrRotateSimpleNoCollision( nRegId, nOthCutRegId, ptCen, dAng, RTY_GLOB) ; } // recupero regioni di lavorazione del pezzo INTVECTOR vCrId ; if ( ! GetFlatPartCutRegions( pGeomDB, nTrueId, bReducedCut, vCrId)) { bOk = false ; break ; } // le confronto con le regioni degli altri pezzi for ( int nCrId : vCrId) { for ( int nOthRegId : vReg) { ExeSurfFrRotateSimpleNoCollision( nCrId, nOthRegId, ptCen, dAng, RTY_GLOB) ; } } } // Se errore if ( ! bOk) return false ; // Se movimento risultante nullo, non faccio alcunché dRotAngDeg = dAng ; if ( fabs( dAng) < EPS_ANG_SMALL) return true ; // Eseguo rotazione dei pezzi del cluster for ( auto nTrueId : vTrueIds) pGeomDB->RotateGlob( nTrueId, ptCen, Z_AX, dRotAngDeg) ; ExeSetModified() ; return true ; } //---------------------------------------------------------------------------- static bool GetObstacleTangent( Vector3d& vtTang) { if ( s_scInfo.nType != SCI_PNT_LINE && s_scInfo.nType != SCI_LINE_LINE) return false ; vtTang = s_scInfo.vtDirF ; return vtTang.Normalize() ; } //---------------------------------------------------------------------------- static bool GetMovingTangent( Vector3d& vtTang) { if ( s_scInfo.nType != SCI_LINE_PNT && s_scInfo.nType != SCI_LINE_LINE) return false ; vtTang = s_scInfo.vtDirM ; return vtTang.Normalize() ; } //---------------------------------------------------------------------------- bool ExeTgMovePartClusterOnCollision( const INTVECTOR& vIds, bool bReducedCut, Vector3d& vtMove, double dXmin, double dYmin, double dXmax, double dYmax) { // recupero tangente lineare di ostacolo o di mobile Vector3d vtTang ; if ( ! GetObstacleTangent( vtTang) && ! GetMovingTangent( vtTang)) { vtMove = V_NULL ; return false ; } // calcolo il movimento tangente vtMove = ( vtMove * vtTang) * vtTang ; // riprovo con questo movimento if ( ! ExeMovePartCluster( vIds, bReducedCut, vtMove, dXmin, dYmin, dXmax, dYmax)) return false ; return true ; } //---------------------------------------------------------------------------- bool ExeAlignPartClusterOnCollision( const INTVECTOR& vIds, bool bReducedCut, double dXmin, double dYmin, double dXmax, double dYmax, bool& bMoved) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // verifico sia collisione punto->linea if ( s_scInfo.nType != SCI_PNT_LINE) return false ; // recupero la regione mobile interessata dalla collision ISurfFlatRegion* pSfr = GetSurfFlatRegion( pGeomDB->GetGeoObj( s_scInfo.nIdM)) ; if ( pSfr == nullptr) return false ; // recupero il suo sistema di riferimento Frame3d frSfr ; if ( ! pGeomDB->GetGlobFrame( s_scInfo.nIdM, frSfr)) return false ; // porto il punto di contatto nel riferimento della superficie Point3d ptCntL = s_scInfo.ptP1 ; ptCntL.ToLoc( frSfr) ; // cerco le direzioni tangenti prima e dopo il punto di contatto sulle parti mobili PtrOwner pCrv( pSfr->GetLoop( s_scInfo.nChunkM, 0)) ; if ( IsNull( pCrv)) return false ; double dU ; if ( ! pCrv->GetParamAtPoint( ptCntL, dU, 10 * EPS_SMALL)) return false ; Point3d ptPp ; Vector3d vtTp ; if ( ! pCrv->GetPointTang( dU, ICurve::FROM_MINUS, ptPp, vtTp)) return false ; Point3d ptPn ; Vector3d vtTn ; if ( ! pCrv->GetPointTang( dU, ICurve::FROM_PLUS, ptPn, vtTn)) return false ; // verifico che le tangenti siano diverse if ( AreSameVectorApprox( vtTp, vtTn)) return false ; // porto le tangenti nel riferimento globale e le confronto con la tangente dell'ostacolo vtTp.ToGlob( frSfr) ; vtTn.ToGlob( frSfr) ; // log per debug if ( false) { string sOut = "vtTp=(" + ToString( vtTp) + ") vtTn=(" + ToString( vtTn) + ")" ; LOG_INFO( GetLogger(), sOut.c_str()) ; } // ruoto dalla parte dell'angolo più piccolo (componente più grande) double dRotAngDeg = ( abs( vtTp * s_scInfo.vtDirF) > abs( vtTn * s_scInfo.vtDirF)) ? 90 : - 90 ; // provo a ruotare sul punto di collisione in senso orario Point3d ptCen = s_scInfo.ptP1 ; if ( ! ExeRotatePartCluster( vIds, bReducedCut, ptCen, dRotAngDeg, dXmin, dYmin, dXmax, dYmax)) return false ; bMoved = ( fabs( dRotAngDeg) > EPS_ANG_SMALL) ; return true ; } //---------------------------------------------------------------------------- bool ExeMoveToSnapPointOnCollision( const INTVECTOR& vIds, bool bReducedCut, double dMaxMove, double dXmin, double dYmin, double dXmax, double dYmax, bool& bMoved) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) IMachMgr* pMachMgr = GetCurrMachMgr() ; VERIFY_MACHMGR( pMachMgr, false) // la collisione deve essere di tipo linea-linea o punto linea if ( s_scInfo.nType != SCI_LINE_LINE && s_scInfo.nType != SCI_PNT_LINE) return false ; // cerco i due tagli in collisione int nCutM = GDB_ID_NULL ; int nGeoM = GDB_ID_NULL ; Point3d ptStartM, ptEndM ; Vector3d vtDirM ; Frame3d frGeoM ; int nCutF = GDB_ID_NULL ; int nGeoF = GDB_ID_NULL ; Point3d ptStartF, ptEndF ; Vector3d vtDirF ; Frame3d frGeoF ; // se mobile è già un taglio, ne ricavo i dati if ( s_scInfo.bIsCutM) { nCutM = s_scInfo.nIdM ; nGeoM = GetGeometryFromCut( pGeomDB, pMachMgr, nCutM) ; ICurveLine* pLineM = GetCurveLine( pGeomDB->GetGeoObj( nGeoM)) ; if ( nCutM == GDB_ID_NULL || nGeoM == GDB_ID_NULL || pLineM == nullptr || ! pGeomDB->GetGlobFrame( nGeoM, frGeoM)) return false ; ptStartM = pLineM->GetStart() ; ptStartM.ToGlob( frGeoM) ; ptEndM = pLineM->GetEnd() ; ptEndM.ToGlob( frGeoM) ; vtDirM = ptEndM - ptStartM ; vtDirM.Normalize() ; } // se fisso è già un taglio, ne ricavo i dati if ( s_scInfo.bIsCutF) { nCutF = s_scInfo.nIdF ; nGeoF = GetGeometryFromCut( pGeomDB, pMachMgr, nCutF) ; ICurveLine* pLineF = GetCurveLine( pGeomDB->GetGeoObj( nGeoF)) ; if ( nCutF == GDB_ID_NULL || nGeoF == GDB_ID_NULL || pLineF == nullptr || ! pGeomDB->GetGlobFrame( nGeoF, frGeoF)) return false ; ptStartF = pLineF->GetStart() ; ptStartF.ToGlob( frGeoF) ; ptEndF = pLineF->GetEnd() ; ptEndF.ToGlob( frGeoF) ; vtDirF = ptEndF - ptStartF ; vtDirF.Normalize() ; } // se fisso pezzo e mobile taglio, cerco il taglio sul fisso if ( ! s_scInfo.bIsCutF && s_scInfo.bIsCutM) { // cerco il pezzo del fisso int nPartId = GetFlatPartFromRegion( pGeomDB, s_scInfo.nIdF) ; // recupero i suoi tagli INTVECTOR vCuts ; if ( ! GetFlatPartCutRegions( pGeomDB, nPartId, bReducedCut, vCuts)) return false ; // cerco il taglio che si sovrappone a quello del mobile BBox3d b3CutM ; pGeomDB->GetGlobalBBox( nCutM, b3CutM) ; for ( auto nId : vCuts) { BBox3d b3Temp ; pGeomDB->GetGlobalBBox( nId, b3Temp) ; if ( b3Temp.OverlapsXY( b3CutM)) { int nGeom = GetGeometryFromCut( pGeomDB, pMachMgr, nId) ; ICurveLine* pLine = GetCurveLine( pGeomDB->GetGeoObj( nGeom)) ; if ( nGeom == GDB_ID_NULL || pLine == nullptr || ! pGeomDB->GetGlobFrame( nGeom, frGeoF)) continue ; ptStartF = pLine->GetStart() ; ptStartF.ToGlob( frGeoF) ; ptEndF = pLine->GetEnd() ; ptEndF.ToGlob( frGeoF) ; vtDirF = ptEndF - ptStartF ; vtDirF.Normalize() ; if ( AreOppositeVectorApprox( vtDirF, vtDirM)) { nCutF = nId ; nGeoF = nGeom ; break ; } } } } // se mobile pezzo e fisso taglio, cerco il taglio sul mobile if ( ! s_scInfo.bIsCutM && s_scInfo.bIsCutF) { // cerco il pezzo del mobile int nPartId = GetFlatPartFromRegion( pGeomDB, s_scInfo.nIdM) ; // recupero i suoi tagli INTVECTOR vCuts ; if ( ! GetFlatPartCutRegions( pGeomDB, nPartId, bReducedCut, vCuts)) return false ; // cerco il taglio che si sovrappone a quello del fisso BBox3d b3CutF ; pGeomDB->GetGlobalBBox( nCutF, b3CutF) ; for ( auto nId : vCuts) { BBox3d b3Temp ; pGeomDB->GetGlobalBBox( nId, b3Temp) ; if ( b3Temp.OverlapsXY( b3CutF)) { int nGeom = GetGeometryFromCut( pGeomDB, pMachMgr, nId) ; ICurveLine* pLine = GetCurveLine( pGeomDB->GetGeoObj( nGeom)) ; if ( nGeom == GDB_ID_NULL || pLine == nullptr || ! pGeomDB->GetGlobFrame( nGeom, frGeoM)) continue ; ptStartM = pLine->GetStart() ; ptStartM.ToGlob( frGeoM) ; ptEndM = pLine->GetEnd() ; ptEndM.ToGlob( frGeoM) ; vtDirM = ptEndM - ptStartM ; vtDirM.Normalize() ; if ( AreOppositeVectorApprox( vtDirF, vtDirM)) { nCutM = nId ; nGeoM = nGeom ; break ; } } } } // se un taglio non definito, esco if ( nCutM == GDB_ID_NULL || nCutF == GDB_ID_NULL) return false ; // linee adiacenti sul mobile int nGeoMp = pGeomDB->GetPrev( nGeoM) ; if ( nGeoMp == GDB_ID_NULL) nGeoMp = pGeomDB->GetLastInGroup( pGeomDB->GetParentId( nGeoM)) ; Vector3d vtDirMp ; if ( pGeomDB->GetGeoType( nGeoMp) == CRV_LINE) { ICurveLine* pLine = GetCurveLine( pGeomDB->GetGeoObj( nGeoMp)) ; pLine->GetStartDir( vtDirMp) ; vtDirMp.ToGlob( frGeoM) ; } int nGeoMn = pGeomDB->GetNext( nGeoM) ; if ( nGeoMn == GDB_ID_NULL) nGeoMn = pGeomDB->GetFirstInGroup( pGeomDB->GetParentId( nGeoM)) ; Vector3d vtDirMn ; if ( pGeomDB->GetGeoType( nGeoMn) == CRV_LINE) { ICurveLine* pLine = GetCurveLine( pGeomDB->GetGeoObj( nGeoMn)) ; pLine->GetStartDir( vtDirMn) ; vtDirMn.ToGlob( frGeoM) ; } // linee adiacenti sul fisso int nGeoFp = pGeomDB->GetPrev( nGeoF) ; if ( nGeoFp == GDB_ID_NULL) nGeoFp = pGeomDB->GetLastInGroup( pGeomDB->GetParentId( nGeoF)) ; Vector3d vtDirFp ; if ( pGeomDB->GetGeoType( nGeoFp) == CRV_LINE) { ICurveLine* pLine = GetCurveLine( pGeomDB->GetGeoObj( nGeoFp)) ; pLine->GetStartDir( vtDirFp) ; vtDirFp.ToGlob( frGeoF) ; } int nGeoFn = pGeomDB->GetNext( nGeoF) ; if ( nGeoFn == GDB_ID_NULL) nGeoFn = pGeomDB->GetFirstInGroup( pGeomDB->GetParentId( nGeoF)) ; Vector3d vtDirFn ; if ( pGeomDB->GetGeoType( nGeoFn) == CRV_LINE) { ICurveLine* pLine = GetCurveLine( pGeomDB->GetGeoObj( nGeoFn)) ; pLine->GetStartDir( vtDirFn) ; vtDirFn.ToGlob( frGeoF) ; } // verifico se possibile allineare i tagli precedente di mobile e successivo di fisso double dMoveMp = 2 * dMaxMove ; if ( ! vtDirMp.IsSmall() && ! vtDirFn.IsSmall()) { if ( AreSameVectorApprox( vtDirMp, vtDirFn)) { double dDenom = CrossXY( vtDirF, vtDirFn) ; if ( abs( dDenom) > EPS_ZERO) dMoveMp = CrossXY( ptEndF - ptStartM, vtDirFn) / dDenom ; } } double dMoveMn = 2 * dMaxMove ; if ( ! vtDirMn.IsSmall() && ! vtDirFp.IsSmall()) { if ( AreSameVectorApprox( vtDirMn, vtDirFp)) { double dDenom = CrossXY( vtDirF, vtDirFp) ; if ( abs( dDenom) > EPS_ZERO) dMoveMn = CrossXY( ptStartF - ptEndM, vtDirFp) / dDenom ; } } // pareggio la parte più vicina, se almeno una sotto soglia if ( abs( dMoveMp) < dMaxMove || abs( dMoveMn) < dMaxMove) { // calcolo movimento necessario, se nullo già a posto Vector3d vtMove = (( abs( dMoveMp) < abs( dMoveMn)) ? dMoveMp : dMoveMn) * vtDirF ; if ( vtMove.IsSmall()) { bMoved = false ; return true ; } // eseguo movimento if ( ExeMovePartCluster( vIds, bReducedCut, vtMove, dXmin, dYmin, dXmax, dYmax)) { if ( ! vtMove.IsSmall()) { bMoved = true ; return true ; } } } // verifico se possibile allineare i tagli correnti // calcolo ingombro dei tagli su direzione del taglio fisso Frame3d frCutF ; frCutF.Set( ptStartF, Z_AX, vtDirF) ; BBox3d b3CutF ; pGeomDB->GetRefBBox( nCutF, frCutF, b3CutF) ; BBox3d b3CutM ; pGeomDB->GetRefBBox( nCutM, frCutF, b3CutM) ; double dStartDelta = b3CutF.GetMin().x - b3CutM.GetMin().x ; double dEndDelta = b3CutF.GetMax().x - b3CutM.GetMax().x ; // pareggio la parte più vicina, se sotto soglia if ( abs( dStartDelta) > dMaxMove && abs( dEndDelta) > dMaxMove) return false ; Vector3d vtMove = (( abs( dStartDelta) < abs( dEndDelta)) ? dStartDelta : dEndDelta) * vtDirF ; if ( ! ExeMovePartCluster( vIds, bReducedCut, vtMove, dXmin, dYmin, dXmax, dYmax)) return false ; bMoved = ( ! vtMove.IsSmall()) ; return true ; } //---------------------------------------------------------------------------- void ExeSaveCollInfo( void) { s_scInfoSaved = s_scInfo ; } //---------------------------------------------------------------------------- void ExeRestoreCollInfo( void) { s_scInfo = s_scInfoSaved ; } //----------------------------------------------------------------------------- bool ExeGetPartClusterCenterGlob( const INTVECTOR& vIds, Point3d& ptCen) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Risolvo eventuali riferimenti a oggetti selezionati INTVECTOR vTrueIds ; vTrueIds.reserve( vIds.size()) ; for ( auto nId : vIds) { int nTrueId = (( nId != GDB_ID_SEL) ? nId : pGeomDB->GetFirstSelectedObj()) ; while ( nTrueId != GDB_ID_NULL) { vTrueIds.push_back( nTrueId) ; // passo al successivo nTrueId = (( nId != GDB_ID_SEL) ? GDB_ID_NULL : pGeomDB->GetNextSelectedObj()) ; } } // Se non sono rimasti oggetti, esco con errore if ( vTrueIds.empty()) return false ; // Recupero il centro della regione associata ad ogni oggetto int nCount = 0 ; ptCen = ORIG ; for ( auto nTrueId : vTrueIds) { // recupero regione del pezzo int nRegId = GetFlatPartRegion( pGeomDB, nTrueId) ; ISurfFlatRegion* pSfr = GetSurfFlatRegion( pGeomDB->GetGeoObj( nRegId)) ; if ( pSfr == nullptr) return false ; // ne ricavo il centro Point3d ptRcen ; if ( ! pSfr->GetCentroid( ptRcen)) return false ; // lo porto in globale Frame3d frRef ; if ( ! pGeomDB->GetGlobFrame( nRegId, frRef)) return false ; ptRcen.ToGlob( frRef) ; // lo sommo al centro complessivo ptCen += ptRcen ; ++ nCount ; } // Verifico di aver trovato qualcosa if ( nCount == 0) return false ; // Medio il centro ptCen /= nCount ; return true ; }