//---------------------------------------------------------------------------- // 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 "/EgtDev/Include/EXeExecutor.h" #include "/EgtDev/Include/EXeConst.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" #include using namespace std ; //---------------------------------------------------------------------------- static int GetFlatPartRegion( IGeomDB* pGeomDB, int nId) { // recupero regione del pezzo (è la prima del sottogruppo di nome Region) int nRegGrp = pGeomDB->GetFirstNameInGroup( nId, NST_PART_REG) ; int nRegId = pGeomDB->GetFirstInGroup( nRegGrp) ; while ( nRegId != GDB_ID_NULL) { if ( pGeomDB->GetGeoType( nRegId) == SRF_FLATRGN) break ; nRegId = pGeomDB->GetNext( nRegId) ; } return nRegId ; } //---------------------------------------------------------------------------- static 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 false ; // 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 ; } //---------------------------------------------------------------------------- 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 SCollInfo s_scInfo ; //---------------------------------------------------------------------------- static double UpdateCollId( double dLen, double dPrevLen, int nId1, int nId2, 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 ; } return dPrevLen ; } else if ( dLen < dPrevLen) { s_scInfo = scInfoCurr ; s_scInfo.nIdM = nId1 ; s_scInfo.nIdF = nId2 ; 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, 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, 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, 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, scInfoCurr) ; } } } // Se errore if ( ! bOk) return false ; // Log provvisorio 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 ExeGetObstacleTangent( Vector3d& vtTang) { if ( s_scInfo.nType != SCI_PNT_LINE && s_scInfo.nType != SCI_LINE_LINE) return false ; vtTang = s_scInfo.vtDirF ; return vtTang.Normalize() ; } //---------------------------------------------------------------------------- bool ExeGetMovingTangent( 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 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 ; } //---------------------------------------------------------------------------- bool ExeAlignPartClusterOnCollision( const INTVECTOR& vIds, bool bReducedCut, double dXmin, double dYmin, double dXmax, double dYmax) { 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) ; 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 ; return ExeRotatePartCluster( vIds, bReducedCut, ptCen, dRotAngDeg, dXmin, dYmin, dXmax, dYmax) ; } //----------------------------------------------------------------------------- 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 ; }