//---------------------------------------------------------------------------- // 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/EgkDistPointCurve.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) {} } ; //---------------------------------------------------------------------------- static const double SPESS = 100 ; //---------------------------------------------------------------------------- static bool MyMovePartCluster( IGeomDB* pGeomDB, const INTVECTOR& vTrueIds, BBox3d b3Cluster, bool bReducedCut, Vector3d& vtMove) ; //---------------------------------------------------------------------------- static bool AdjustClusterObjIds( IGeomDB* pGeomDB, const INTVECTOR& vIds, INTVECTOR& vTrueIds, BBox3d& b3Cluster) { if ( pGeomDB == nullptr) return false ; // Flag per calcolo box const int BBF_PART_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ; // Risolvo eventuali riferimenti a oggetti selezionati vTrueIds.clear() ; vTrueIds.reserve( vIds.size()) ; b3Cluster.Reset() ; 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_PART_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()) ; } } return true ; } //---------------------------------------------------------------------------- bool ExeCreateOutRegion( int nParentId, double dXmin, double dYmin, double dXmax, double dYmax, double dZ) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Verifiche sui parametri if ( dXmax < dXmin + EPS_SMALL || dYmax < dYmin + EPS_SMALL) return false ; // se già esiste, posso uscire int nBoxId = pGeomDB->GetFirstNameInGroup( nParentId, NST_SHEET_OUTREG) ; if ( nBoxId != GDB_ID_NULL) return true ; // creo polilinea attorno al box (avvolta a serpente) 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 false ; // costruisco la regione piana SurfFlatRegionByContours SfrCntr ; SfrCntr.AddCurve( Release( pCompo)) ; ISurfFlatRegion* pSfr = SfrCntr.GetSurf() ; if ( pSfr == nullptr) return false ; // recupero il riferimento del gruppo di inserimento Frame3d frLoc ; if ( ! pGeomDB->GetGroupGlobFrame( nParentId, frLoc)) return false ; // 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 false ; // assegno nome e la dichiaro di sistema e invisibile pGeomDB->SetName( nId, NST_SHEET_OUTREG) ; pGeomDB->SetLevel( nId, GDB_LV_SYSTEM) ; pGeomDB->SetMaterial( nId, INVISIBLE) ; return true ; } //---------------------------------------------------------------------------- bool ExeCreateOutRegion( int nParentId, int nOutCrvId) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // se già esiste, posso uscire int nBoxId = pGeomDB->GetFirstNameInGroup( nParentId, NST_SHEET_OUTREG) ; if ( nBoxId != GDB_ID_NULL) return true ; // recupero la curva ICurve* pOutCrv = GetCurve( pGeomDB->GetGeoObj( nOutCrvId)) ; if ( pOutCrv == nullptr) return false ; // verifico sia chiusa if ( ! pOutCrv->IsClosed()) return false ; // la approssimo con linee const double LIN_TOL_STD = 0.1 ; const double ANG_TOL_STD_DEG = 15 ; PolyLine PL ; if ( ! pOutCrv->ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_STD, PL)) return false ; // porto la polilinea in globale Frame3d frOutCrv ; pGeomDB->GetGlobFrame( nOutCrvId, frOutCrv) ; PL.ToGlob( frOutCrv) ; // se antioraria la inverto double dArea ; if ( ! PL.GetAreaXY( dArea)) return false ; if ( dArea > 0) PL.Invert() ; // la appiattisco sulla Z iniziale Point3d ptP ; PL.GetFirstPoint( ptP) ; PL.Flatten( ptP.z) ; // la converto in curva composita PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo) || ! pCompo->FromPolyLine( PL)) return false ; // ne ricavo il bbox e lo ingrandisco BBox3d b3Box ; pCompo->GetLocalBBox( b3Box) ; b3Box.Expand( SPESS, SPESS, 0) ; // determino il punto più vicino al massimo del box e lo faccio diventare il nuovo inizio int nFlag ; double dU ; DistPointCurve distPC( b3Box.GetMax(), *pCompo) ; if ( ! distPC.GetParamAtMinDistPoint( 0, dU, nFlag) || ! pCompo->ChangeStartPoint( dU)) return false ; // accorcio inizio pCompo->TrimStartAtLen( 5 * EPS_SMALL) ; // creo curva della parte esterna Point3d ptStart ; pCompo->GetStartPoint( ptStart) ; Point3d ptEnd ; pCompo->GetEndPoint( ptEnd) ; PolyLine PL2 ; PL2.AddUPoint( 0, ptEnd) ; PL2.AddUPoint( 1, Point3d( ptEnd.x, b3Box.GetMax().y, b3Box.GetMin().z)) ; PL2.AddUPoint( 2, Point3d( b3Box.GetMin().x, b3Box.GetMax().y, b3Box.GetMin().z)) ; PL2.AddUPoint( 3, b3Box.GetMin()) ; PL2.AddUPoint( 4, Point3d( b3Box.GetMax().x, b3Box.GetMin().y, b3Box.GetMin().z)) ; PL2.AddUPoint( 5, Point3d( b3Box.GetMax().x, ptStart.y, b3Box.GetMin().z)) ; PL2.AddUPoint( 6, ptStart) ; // la converto in curva composita PtrOwner pCompo2( CreateCurveComposite()) ; if ( IsNull( pCompo2) || ! pCompo2->FromPolyLine( PL2)) return false ; // unisco le due curve composite if ( ! pCompo->AddCurve( Release( pCompo2))) return false ; // costruisco la regione piana SurfFlatRegionByContours SfrCntr ; SfrCntr.AddCurve( Release( pCompo)) ; ISurfFlatRegion* pSfr = SfrCntr.GetSurf() ; if ( pSfr == nullptr) return false ; // recupero il riferimento del gruppo di inserimento Frame3d frLoc ; if ( ! pGeomDB->GetGroupGlobFrame( nParentId, frLoc)) return false ; // 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 false ; // assegno nome e la dichiaro di sistema e invisibile pGeomDB->SetName( nId, NST_SHEET_OUTREG) ; pGeomDB->SetLevel( nId, GDB_LV_SYSTEM) ; pGeomDB->SetMaterial( nId, INVISIBLE) ; return true ; } //---------------------------------------------------------------------------- bool ExeCreateDamagedRegion( int nParentId, int nDmgCrvId) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // verifico se esiste già la regione associata int nRegId = pGeomDB->GetFirstNameInGroup( nParentId, NST_DAMAGED_REG) ; while ( nRegId != GDB_ID_NULL) { // recupero l'indice della curva di origine int nOriId ; if ( pGeomDB->GetInfo( nRegId, CRV_ORIG, nOriId) && nOriId == nDmgCrvId) return true ; // passo alla regione successiva nRegId = pGeomDB->GetNextName( nRegId, NST_DAMAGED_REG) ; } // recupero la curva e verifico sia chiusa ICurve* pCrv = GetCurve( pGeomDB->GetGeoObj( nDmgCrvId)) ; if ( pCrv == nullptr || ! pCrv->IsClosed()) return false ; // la approssimo con linee const double LIN_TOL_STD = 0.1 ; const double ANG_TOL_STD_DEG = 15 ; PolyLine PL ; if ( ! pCrv->ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_STD, PL)) return GDB_ID_NULL ; // porto la polilinea in globale Frame3d frDmgCrv ; pGeomDB->GetGlobFrame( nDmgCrvId, frDmgCrv) ; PL.ToGlob( frDmgCrv) ; // se oraria la inverto double dArea ; if ( ! PL.GetAreaXY( dArea)) return false ; if ( dArea < 0) PL.Invert() ; // la appiattisco sulla Z iniziale Point3d ptP ; PL.GetFirstPoint( ptP) ; PL.Flatten( ptP.z) ; // la converto in curva composita PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo) || ! pCompo->FromPolyLine( PL)) return false ; // costruisco la regione piana SurfFlatRegionByContours SfrCntr ; SfrCntr.AddCurve( Release( pCompo)) ; ISurfFlatRegion* pSfr = SfrCntr.GetSurf() ; if ( pSfr == nullptr) return false ; // recupero il riferimento del gruppo di inserimento Frame3d frLoc ; if ( ! pGeomDB->GetGroupGlobFrame( nParentId, frLoc)) return false ; // 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 false ; // assegno nome, id curva di origine e la dichiaro di sistema e invisibile pGeomDB->SetName( nId, NST_DAMAGED_REG) ; pGeomDB->SetInfo( nId, CRV_ORIG, nDmgCrvId) ; pGeomDB->SetLevel( nId, GDB_LV_SYSTEM) ; pGeomDB->SetMaterial( nId, INVISIBLE) ; return true ; } //---------------------------------------------------------------------------- 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 ; } //---------------------------------------------------------------------------- static bool MyVerifyPartCluster( IGeomDB* pGeomDB, const INTVECTOR& vTrueIds, const BBox3d& b3Cluster, bool bReducedCut) { // Flag per calcolo box const int BBF_PART_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ; // Determino le regioni dei pezzi INTVECTOR vReg ; INTVECTOR vDwnReg ; INTVECTOR vCutReg ; INTVECTOR vDwnCutReg ; BBox3d b3RegCluster ; for ( int nId : vTrueIds) { // recupero regione del pezzo int nRegId = GetFlatPartRegion( pGeomDB, nId) ; BBox3d b3Reg ; if ( pGeomDB->GetGlobalBBox( nRegId, b3Reg, BBF_PART_MY_FLAG)) { vReg.emplace_back( nRegId) ; b3RegCluster.Add( b3Reg) ; } else return false ; // recupero eventuale regione in basso del pezzo int nDwnRegId = GetFlatPartDownRegion( pGeomDB, nId) ; vDwnReg.emplace_back( nDwnRegId) ; // recupero regioni dei tagli del pezzo if ( ! GetFlatPartCutRegions( pGeomDB, nId, bReducedCut, vCutReg)) return false ; // recupero regioni in basso dei tagli del pezzo GetFlatPartDownCutRegions( pGeomDB, nId, bReducedCut, vDwnCutReg) ; } // Verifico se pezzi sotto la radice o pezzi in altro gruppo int nGroupId = pGeomDB->GetParentId( vTrueIds[0]) ; bool bInRoot = ( nGroupId == GDB_ID_ROOT) ; // Verifico di essere nella regione valida int nBoxId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_SHEET_OUTREG) ; BBox3d b3Region ; if ( nBoxId == GDB_ID_NULL || ! pGeomDB->GetGlobalBBox( nBoxId, b3Region)) return false ; // box delle regioni dei pezzi rispetto al box dell'esterno if ( ! b3Region.EnclosesXY( b3RegCluster)) return false ; // regioni dei pezzi rispetto alla regione dell'esterno for ( int nRegId : vReg) { if ( ExeSurfFrChunkSimpleClassify( nRegId, 0, nBoxId, 0) != REGC_OUT) return false ; } for ( int nDwnRegId : vDwnReg) { if ( nDwnRegId != GDB_ID_NULL && ExeSurfFrChunkSimpleClassify( nDwnRegId, 0, nBoxId, 0) != REGC_OUT) return false ; } // Verifico con le eventuali aree danneggiate // recupero le aree INTVECTOR vDmgReg ; int nId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_DAMAGED_REG) ; while ( nId != GDB_ID_NULL) { vDmgReg.emplace_back( nId) ; nId = pGeomDB->GetNextName( nId, NST_DAMAGED_REG) ; } // regioni dei pezzi rispetto alle regioni delle aree danneggiate for ( int nRegId : vReg) { for ( int nDmgRegId : vDmgReg) { if ( ExeSurfFrChunkSimpleClassify( nRegId, 0, nDmgRegId, 0) != REGC_OUT) return false ; } } for ( int nDwnRegId : vDwnReg) { if ( nDwnRegId != GDB_ID_NULL) { for ( int nDmgRegId : vDmgReg) { if ( ExeSurfFrChunkSimpleClassify( nDwnRegId, 0, nDmgRegId, 0) != REGC_OUT) return false ; } } } // Determino le regioni di tutti gli altri pezzi compresi nella regione di interesse INTVECTOR vOthReg ; INTVECTOR vOthDwnReg ; INTVECTOR vOthCutReg ; INTVECTOR vOthDwnCutReg ; 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_PART_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 eventuale regione in basso del pezzo int nDwnRegId = GetFlatPartDownRegion( pGeomDB, nId2) ; vOthDwnReg.emplace_back( nDwnRegId) ; // recupero regioni dei tagli del pezzo if ( ! GetFlatPartCutRegions( pGeomDB, nId2, bReducedCut, vOthCutReg)) return false ; // recupero regioni in basso dei tagli del pezzo GetFlatPartDownCutRegions( pGeomDB, nId2, bReducedCut, vOthDwnCutReg) ; } } nId2 = ( bInRoot ? ExeGetNextPart( nId2, true) : ExeGetNextGroup( nId2)) ; } // Eseguo verifiche // 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) return false ; } // e con le regioni dei tagli degli altri pezzi for ( int nOthCutRegId : vOthCutReg) { if ( ExeSurfFrChunkSimpleClassify( nRegId, 0, nOthCutRegId, 0) != REGC_OUT) return false ; } } // regioni sotto dei pezzi for ( size_t i = 0 ; i < vDwnReg.size() ; ++ i) { // verifico con le regioni sotto degli altri pezzi for ( size_t j = 0 ; j < vOthDwnReg.size() ; ++ j) { if ( vDwnReg[i] != GDB_ID_NULL || vOthDwnReg[j] != GDB_ID_NULL) { int nDwnRegId = ( vDwnReg[i] != GDB_ID_NULL ? vDwnReg[i] : vReg[i]) ; int nOthDwnRegId = ( vOthDwnReg[j] != GDB_ID_NULL ? vOthDwnReg[j] : vOthReg[j]) ; if ( ExeSurfFrChunkSimpleClassify( nDwnRegId, 0, nOthDwnRegId, 0) != REGC_OUT) return false ; } } // e con le regioni sotto dei tagli degli altri pezzi for ( size_t j = 0 ; j < vOthDwnCutReg.size() ; ++ j) { if ( vDwnReg[i] != GDB_ID_NULL || vOthDwnCutReg[j] != GDB_ID_NULL) { int nDwnRegId = ( vDwnReg[i] != GDB_ID_NULL ? vDwnReg[i] : vReg[i]) ; int nOthDwnCutRegId = ( vOthDwnCutReg[j] != GDB_ID_NULL ? vOthDwnCutReg[j] : vOthCutReg[j]) ; if ( ExeSurfFrChunkSimpleClassify( nDwnRegId, 0, nOthDwnCutRegId, 0) != REGC_OUT) return 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) return false ; } } // regioni sotto delle lavorazioni dei pezzi for ( size_t i = 0 ; i < vDwnCutReg.size() ; ++ i) { // le confronto con le regioni sotto degli altri pezzi for ( size_t j = 0 ; j < vOthDwnReg.size() ; ++ j) { if ( vDwnCutReg[i] != GDB_ID_NULL || vOthDwnReg[j] != GDB_ID_NULL) { int nDwnCutRegId = ( vDwnCutReg[i] != GDB_ID_NULL ? vDwnCutReg[i] : vCutReg[i]) ; int nOthDwnRegId = ( vOthDwnReg[j] != GDB_ID_NULL ? vOthDwnReg[j] : vOthReg[j]) ; if ( ExeSurfFrChunkSimpleClassify( nDwnCutRegId, 0, nOthDwnRegId, 0) != REGC_OUT) return false ; } } } return true ; } //---------------------------------------------------------------------------- bool ExeVerifyPartCluster( const INTVECTOR& vIds, bool bReducedCut) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Risolvo identificativi a selezionati INTVECTOR vTrueIds ; BBox3d b3Cluster ; AdjustClusterObjIds( pGeomDB, vIds, vTrueIds, b3Cluster) ; if ( vTrueIds.empty()) return true ; // Eseguo verifica return MyVerifyPartCluster( pGeomDB, vTrueIds, b3Cluster, bReducedCut) ; } //---------------------------------------------------------------------------- static bool MyPackPartCluster( const INTVECTOR& vTrueIds, bool bReducedCut, double dXmin, double dYmin, double dXmax, double dYmax, bool bBottomUp) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // 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_PART_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_PART_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) ; // verifica bOk = bOk && ExeVerifyPartCluster( vTrueIds, bReducedCut) ; // 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) ; Vector3d vtMoveX = - BIG_MOVE * X_AX ; ExeMovePartCluster( vTrueIds, bReducedCut, vtMoveX) ; } return bOk ; } //---------------------------------------------------------------------------- bool ExePackPartClusterInRectangle( const INTVECTOR& vIds, bool bReducedCut, bool bBottomUp) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Risolvo identificativi a selezionati INTVECTOR vTrueIds ; BBox3d b3Cluster ; AdjustClusterObjIds( pGeomDB, vIds, vTrueIds, b3Cluster) ; if ( vTrueIds.empty()) return true ; // Recupero gruppo dei pezzi int nGroupId = pGeomDB->GetParentId( vTrueIds[0]) ; // Calcolo il box interno della regione valida int nBoxId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_SHEET_OUTREG) ; BBox3d b3Box ; if ( ! pGeomDB->GetGlobalBBox( nBoxId, b3Box)) return false ; b3Box.Expand( - SPESS, - SPESS, 0) ; if ( b3Box.IsEmpty()) return false ; double dXmin = b3Box.GetMin().x ; double dYmin = b3Box.GetMin().y ; double dXmax = b3Box.GetMax().x ; double dYmax = b3Box.GetMax().y ; // 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)) { return true ; } // altrimenti, riprovo con tagli standard else { return MyPackPartCluster( vTrueIds, false, dXmin, dYmin, dXmax, dYmax, bBottomUp) ; } } } //---------------------------------------------------------------------------- bool ExePackPartCluster( const INTVECTOR& vIds, bool bReducedCut, bool bBottomUp) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Risolvo identificativi a selezionati INTVECTOR vTrueIds ; BBox3d b3Cluster ; AdjustClusterObjIds( pGeomDB, vIds, vTrueIds, b3Cluster) ; if ( vTrueIds.empty()) return true ; // Recupero gruppo dei pezzi int nGroupId = pGeomDB->GetParentId( vTrueIds[0]) ; // Calcolo il box di ingombro interno della regione valida int nBoxId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_SHEET_OUTREG) ; BBox3d b3Box ; if ( ! pGeomDB->GetGlobalBBox( nBoxId, b3Box)) return false ; b3Box.Expand( - SPESS, - SPESS, 0) ; if ( b3Box.IsEmpty()) return false ; // Flag per calcolo box dei pezzi const int BBF_PART_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ; // Calcolo il box di ingombro delle regioni dei pezzi BBox3d b3RegCluster ; for ( int nId : vTrueIds) { // recupero regione del pezzo int nRegId = GetFlatPartRegion( pGeomDB, nId) ; BBox3d b3Reg ; if ( pGeomDB->GetGlobalBBox( nRegId, b3Reg, BBF_PART_MY_FLAG)) { b3RegCluster.Add( b3Reg) ; } else return false ; } double dRegClDimX = b3RegCluster.GetMax().x - b3RegCluster.GetMin().x ; double dRegClDimY = b3RegCluster.GetMax().y - b3RegCluster.GetMin().y ; // Determino lo step per i tentativi di inserimento const double STEP_STD = 50 ; double dStepX = STEP_STD ; double dStepY = STEP_STD ; double dBoxDimX = b3Box.GetMax().x - b3Box.GetMin().x ; double dRegCluDimX = b3RegCluster.GetMax().x - b3RegCluster.GetMin().x ; if ( dBoxDimX - dRegCluDimX < 5 * STEP_STD) dStepX = STEP_STD / 5 ; double dBoxDimY = b3Box.GetMax().y - b3Box.GetMin().y ; double dRegCluDimY = b3RegCluster.GetMax().y - b3RegCluster.GetMin().y ; if ( dBoxDimY - dRegCluDimY < 5 * STEP_STD) dStepY = STEP_STD / 5 ; // Procedo per tentativi bool bFit = false ; Point3d ptOrig = b3RegCluster.GetMin() ; Point3d ptLineStart = ( bBottomUp ? b3Box.GetMin() : b3Box.GetMax() - Vector3d(0, -dRegClDimY, 0)) ; Point3d ptIns = ptLineStart ; while ( true) { // porto nella posizione di prova Vector3d vtMove = ptIns - b3RegCluster.GetMin() ; vtMove.z = 0 ; for ( auto nId : vTrueIds) pGeomDB->TranslateGlob( nId, vtMove) ; b3Cluster.Translate( vtMove) ; b3RegCluster.Translate( vtMove) ; // verifico if ( MyVerifyPartCluster( pGeomDB, vTrueIds, b3Cluster, bReducedCut)) { bFit = true ; break ; } // nuova posizione di inserimento (incrementando X) ptIns += Vector3d( dStepX, 0, 0) ; // se esco dal box torno all'inizio e incremento Y if ( ! b3Box.EnclosesXY( ptIns + Vector3d( dRegClDimX, 0, 0))) { ptLineStart += Vector3d( 0, ( bBottomUp ? dStepY : - dStepY), 0) ; if ( ( ! b3Box.EnclosesXY( ptLineStart + Vector3d( 0, dRegClDimY, 0)))) break ; ptIns = ptLineStart ; } } // Se inserimento non riuscito if ( ! bFit) { // riporto nella posizione originale Vector3d vtMove = ptOrig - b3RegCluster.GetMin() ; for ( auto nId : vTrueIds) pGeomDB->TranslateGlob( nId, vtMove) ; return false ; } // Inserimento riuscito, provo a migliorare const double BIG_MOVE = 1000 ; Vector3d vtMoveY = ( bBottomUp ? - 1 : 1) * BIG_MOVE * Y_AX ; MyMovePartCluster( pGeomDB, vTrueIds, b3Cluster, bReducedCut, vtMoveY) ; Vector3d vtMoveX = - BIG_MOVE * X_AX ; MyMovePartCluster( pGeomDB, vTrueIds, b3Cluster, bReducedCut, vtMoveX) ; return true ; } //---------------------------------------------------------------------------- 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 ; PtrOwner pTmp ; if ( ! AreSameFrame( frSurf1, frSurf2)) { pTmp.Set( CloneSurfFlatRegion( pSfr2)) ; bOk = bOk && ! IsNull( pTmp) ; bOk = bOk && pTmp->LocToLoc( frSurf2, frSurf1) ; pSfr2L = 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( IGeomDB* pGeomDB, const INTVECTOR& vTrueIds, BBox3d b3Cluster, bool bReducedCut, Vector3d& vtMove) { // 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 ; // Flag per calcolo box pezzi const int BBF_PART_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ; // Verifico se pezzi sotto la radice o pezzi in altro gruppo int nGroupId = pGeomDB->GetParentId( vTrueIds[0]) ; bool bInRoot = ( nGroupId == GDB_ID_ROOT) ; // Recupero regione di interesse int nBoxId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_SHEET_OUTREG) ; BBox3d b3Region ; if ( nBoxId == GDB_ID_NULL || ! pGeomDB->GetGlobalBBox( nBoxId, b3Region)) return false ; // Recupero le eventuali aree danneggiate INTVECTOR vDmgReg ; int nId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_DAMAGED_REG) ; while ( nId != GDB_ID_NULL) { vDmgReg.emplace_back( nId) ; nId = pGeomDB->GetNextName( nId, NST_DAMAGED_REG) ; } // Determino le regioni di tutti gli altri pezzi compresi nella regione di interesse INTVECTOR vOthReg ; INTVECTOR vOthDwnReg ; INTVECTOR vOthCutReg ; INTVECTOR vOthDwnCutReg ; 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_PART_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 eventuale regione in basso del pezzo int nDwnRegId = GetFlatPartDownRegion( pGeomDB, nId2) ; vOthDwnReg.emplace_back( nDwnRegId) ; // recupero regioni dei tagli del pezzo if ( ! GetFlatPartCutRegions( pGeomDB, nId2, bReducedCut, vOthCutReg)) return false ; // recupero regioni in basso dei tagli del pezzo GetFlatPartDownCutRegions( pGeomDB, nId2, bReducedCut, vOthDwnCutReg) ; } } nId2 = ( bInRoot ? ExeGetNextPart( nId2, true) : ExeGetNextGroup( nId2)) ; } // Verifico movimento dei pezzi del cluster rispetto al contorno, alle aree danneggiate e 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) { // info di collisione correnti SCollInfo scInfoCurr ; // ----------------------------------------- // recupero regione del pezzo int nRegId = GetFlatPartRegion( pGeomDB, nTrueId) ; if ( nRegId == GDB_ID_NULL) { bOk = false ; break ; } // la confronto con il box MySurfFrMoveSimpleNoCollision( nRegId, nBoxId, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nRegId, nBoxId, false, false, scInfoCurr) ; // la confronto con le aree danneggiate for ( int nDmgRegId : vDmgReg) { MySurfFrMoveSimpleNoCollision( nRegId, nDmgRegId, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nRegId, nDmgRegId, 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 regione in basso del pezzo int nDwnRegId = GetFlatPartDownRegion( pGeomDB, nTrueId) ; // la confronto con il box if ( nDwnRegId != GDB_ID_NULL) { MySurfFrMoveSimpleNoCollision( nDwnRegId, nBoxId, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nDwnRegId, nBoxId, false, false, scInfoCurr) ; } // la confronto con le aree danneggiate if ( nDwnRegId != GDB_ID_NULL) { for ( int nDmgRegId : vDmgReg) { MySurfFrMoveSimpleNoCollision( nDwnRegId, nDmgRegId, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nDwnRegId, nDmgRegId, false, false, scInfoCurr) ; } } // la confronto con le regioni in basso degli altri pezzi for ( size_t j = 0 ; j < vOthDwnReg.size() ; ++ j) { if ( nDwnRegId != GDB_ID_NULL || vOthDwnReg[j] != GDB_ID_NULL) { int nTmpDwnRegId = ( nDwnRegId != GDB_ID_NULL ? nDwnRegId : nRegId) ; int nOthDwnRegId = ( vOthDwnReg[j] != GDB_ID_NULL ? vOthDwnReg[j] : vOthReg[j]) ; MySurfFrMoveSimpleNoCollision( nTmpDwnRegId, nOthDwnRegId, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nTmpDwnRegId, nOthDwnRegId, false, false, scInfoCurr) ; } } // e con le regioni in basso dei tagli degli altri pezzi for ( size_t j = 0 ; j < vOthDwnCutReg.size() ; ++ j) { if ( nDwnRegId != GDB_ID_NULL || vOthDwnCutReg[j] != GDB_ID_NULL) { int nTmpDwnRegId = ( nDwnRegId != GDB_ID_NULL ? nDwnRegId : nRegId) ; int nOthDwnCutRegId = ( vOthDwnCutReg[j] != GDB_ID_NULL ? vOthDwnCutReg[j] : vOthCutReg[j]) ; MySurfFrMoveSimpleNoCollision( nTmpDwnRegId, nOthDwnCutRegId, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nTmpDwnRegId, nOthDwnCutRegId, 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) ; } } // ----------------------------------------- // recupero regioni in basso di lavorazione del pezzo INTVECTOR vDwnCrId ; if ( ! GetFlatPartDownCutRegions( pGeomDB, nTrueId, bReducedCut, vDwnCrId)) { bOk = false ; break ; } // le confronto con le regioni in basso degli altri pezzi for ( size_t j = 0 ; j < vDwnCrId.size() ; ++ j) { for ( size_t k = 0 ; k < vOthDwnReg.size() ; ++ k) { if ( vDwnCrId[j] != GDB_ID_NULL || vOthDwnReg[k] != GDB_ID_NULL) { int nTmpDwnCrId = ( vDwnCrId[j] != GDB_ID_NULL ? vDwnCrId[j] : vCrId[j]) ; int nOthDwnRegId = ( vOthDwnReg[k] != GDB_ID_NULL ? vOthDwnReg[k] : vOthReg[k]) ; MySurfFrMoveSimpleNoCollision( nTmpDwnCrId, nOthDwnRegId, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nTmpDwnCrId, nOthDwnRegId, 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) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Risolvo identificativi a selezionati INTVECTOR vTrueIds ; BBox3d b3Cluster ; AdjustClusterObjIds( pGeomDB, vIds, vTrueIds, b3Cluster) ; if ( vTrueIds.empty()) return true ; // se con tagli ridotti if ( bReducedCut) { return MyMovePartCluster( pGeomDB, vTrueIds, b3Cluster, true, vtMove) ; } // altrimenti else { // provo con tagli ridotti Vector3d vtM = vtMove ; if ( ! MyMovePartCluster( pGeomDB, vTrueIds, b3Cluster, true, vtM)) return false ; // se posizione valida BBox3d b3CluMoved = b3Cluster ; b3CluMoved.Translate( vtM) ; if ( MyVerifyPartCluster( pGeomDB, vTrueIds, b3CluMoved, false)) { vtMove = vtM ; return true ; } // altrimenti, riprovo con tagli standard else { // annullo il movimento for ( int nId : vTrueIds) pGeomDB->TranslateGlob( nId, - vtM) ; // riprovo return MyMovePartCluster( pGeomDB, vTrueIds, b3Cluster, false, vtMove) ; } } } //---------------------------------------------------------------------------- bool MyRotatePartCluster( IGeomDB* pGeomDB, const INTVECTOR& vTrueIds, BBox3d& b3Cluster, bool bReducedCut, const Point3d& ptCen, double& dRotAngDeg) { // Reset info di collisione s_scInfo.nType = SCI_NONE ; // Rotazione nel piano XY globale // Flag per calcolo box const int BBF_PART_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ; // Verifico se pezzi sotto la radice o pezzi in altro gruppo int nGroupId = pGeomDB->GetParentId( vTrueIds[0]) ; bool bInRoot = ( nGroupId == GDB_ID_ROOT) ; // Recupero regione di interesse int nBoxId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_SHEET_OUTREG) ; BBox3d b3Region ; if ( nBoxId == GDB_ID_NULL || ! pGeomDB->GetGlobalBBox( nBoxId, b3Region)) return false ; // Recupero le eventuali aree danneggiate INTVECTOR vDmgReg ; int nId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_DAMAGED_REG) ; while ( nId != GDB_ID_NULL) { vDmgReg.emplace_back( nId) ; nId = pGeomDB->GetNextName( nId, NST_DAMAGED_REG) ; } // Determino le regioni di tutti gli altri pezzi compresi nella regione di interesse INTVECTOR vOthReg ; INTVECTOR vOthDwnReg ; INTVECTOR vOthCutReg ; INTVECTOR vOthDwnCutReg ; 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_PART_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 eventuale regione in basso del pezzo int nDwnRegId = GetFlatPartDownRegion( pGeomDB, nId2) ; vOthDwnReg.emplace_back( nDwnRegId) ; // recupero regioni dei tagli del pezzo if ( ! GetFlatPartCutRegions( pGeomDB, nId2, bReducedCut, vOthCutReg)) return false ; // recupero eventuali regioni in basso dei tagli del pezzo GetFlatPartDownCutRegions( pGeomDB, nId2, bReducedCut, vOthDwnCutReg) ; } } nId2 = ( bInRoot ? ExeGetNextPart( nId2, true) : ExeGetNextGroup( nId2)) ; } // Verifico rotazione dei pezzi del cluster rispetto al contorno, alle aree danneggiate e 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 aree danneggiate for ( int nDmgRegId : vDmgReg) { ExeSurfFrRotateSimpleNoCollision( nRegId, nDmgRegId, ptCen, dAng, RTY_GLOB) ; } // la confronto con le regioni degli altri pezzi for ( int nOthRegId : vOthReg) { ExeSurfFrRotateSimpleNoCollision( nRegId, nOthRegId, ptCen, dAng, RTY_GLOB) ; } // e con le regioni dei tagli degli altri pezzi for ( int nOthCutRegId : vOthCutReg) { ExeSurfFrRotateSimpleNoCollision( nRegId, nOthCutRegId, ptCen, dAng, RTY_GLOB) ; } // ----------------------------------------- // recupero regione in basso del pezzo int nDwnRegId = GetFlatPartDownRegion( pGeomDB, nTrueId) ; // la confronto con il box if ( nDwnRegId != GDB_ID_NULL) ExeSurfFrRotateSimpleNoCollision( nDwnRegId, nBoxId, ptCen, dAng, RTY_GLOB) ; // la confronto con le aree danneggiate if ( nDwnRegId != GDB_ID_NULL) { for ( int nDmgRegId : vDmgReg) { ExeSurfFrRotateSimpleNoCollision( nDwnRegId, nDmgRegId, ptCen, dAng, RTY_GLOB) ; } } // la confronto con le regioni in basso degli altri pezzi for ( size_t j = 0 ; j < vOthDwnReg.size() ; ++ j) { if ( nDwnRegId != GDB_ID_NULL || vOthDwnReg[j] != GDB_ID_NULL) { int nTmpDwnRegId = ( nDwnRegId != GDB_ID_NULL ? nDwnRegId : nRegId) ; int nOthDwnRegId = ( vOthDwnReg[j] != GDB_ID_NULL ? vOthDwnReg[j] : vOthReg[j]) ; ExeSurfFrRotateSimpleNoCollision( nTmpDwnRegId, nOthDwnRegId, ptCen, dAng, RTY_GLOB) ; } } // e con le regioni in basso dei tagli degli altri pezzi for ( size_t j = 0 ; j < vOthDwnCutReg.size() ; ++ j) { if ( nDwnRegId != GDB_ID_NULL || vOthDwnCutReg[j] != GDB_ID_NULL) { int nTmpDwnRegId = ( nDwnRegId != GDB_ID_NULL ? nDwnRegId : nRegId) ; int nOthDwnCutRegId = ( vOthDwnCutReg[j] != GDB_ID_NULL ? vOthDwnCutReg[j] : vOthCutReg[j]) ; ExeSurfFrRotateSimpleNoCollision( nTmpDwnRegId, nOthDwnCutRegId, 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 : vOthReg) { ExeSurfFrRotateSimpleNoCollision( nCrId, nOthRegId, ptCen, dAng, RTY_GLOB) ; } } // ----------------------------------------- // recupero regioni in basso di lavorazione del pezzo INTVECTOR vDwnCrId ; if ( ! GetFlatPartDownCutRegions( pGeomDB, nTrueId, bReducedCut, vDwnCrId)) { bOk = false ; break ; } // le confronto con le regioni in basso degli altri pezzi for ( size_t j = 0 ; j < vDwnCrId.size() ; ++ j) { for ( size_t k = 0 ; k < vOthDwnReg.size() ; ++ k) { if ( vDwnCrId[j] != GDB_ID_NULL || vOthDwnReg[k] != GDB_ID_NULL) { int nTmpDwnCrId = ( vDwnCrId[j] != GDB_ID_NULL ? vDwnCrId[j] : vCrId[j]) ; int nOthDwnRegId = ( vOthDwnReg[j] != GDB_ID_NULL ? vOthDwnReg[j] : vOthReg[j]) ; ExeSurfFrRotateSimpleNoCollision( nTmpDwnCrId, nOthDwnRegId, 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 ; } //---------------------------------------------------------------------------- bool ExeRotatePartCluster( const INTVECTOR& vIds, bool bReducedCut, const Point3d& ptCen, double& dRotAngDeg) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Risolvo identificativi a selezionati INTVECTOR vTrueIds ; BBox3d b3Cluster ; AdjustClusterObjIds( pGeomDB, vIds, vTrueIds, b3Cluster) ; if ( vTrueIds.empty()) return true ; // Eseguo rotazione return MyRotatePartCluster( pGeomDB, vTrueIds, b3Cluster, bReducedCut, ptCen, dRotAngDeg) ; } //---------------------------------------------------------------------------- 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) { // 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)) return false ; return true ; } //---------------------------------------------------------------------------- bool ExeAlignPartClusterOnCollision( const INTVECTOR& vIds, bool bReducedCut, 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 ; if ( fabs( dU - round( dU)) < 100 * EPS_PARAM) dU = round( dU) ; 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)) return false ; bMoved = ( fabs( dRotAngDeg) > EPS_ANG_SMALL) ; return true ; } //---------------------------------------------------------------------------- bool ExeMoveToSnapPointOnCollision( const INTVECTOR& vIds, bool bReducedCut, double dMaxMove, 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 ; GetFlatPartDownCutRegions( pGeomDB, nPartId, bReducedCut, vCuts) ; // 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 ; GetFlatPartDownCutRegions( pGeomDB, nPartId, bReducedCut, vCuts) ; // 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)) { 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)) 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 ; }