//---------------------------------------------------------------------------- // 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/EGkDistPointLine.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EGkCAvSimpleSurfFrMove.h" #include "/EgtDev/Include/EGkCAvSurfFrMove.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EMkMachiningGeoConst.h" #include "/EgtDev/Include/EGkIntervals.h" #include "/EgtDev/Include/EgtPointerOwner.h" using namespace std ; //---------------------------------------------------------------------------- // collisioni semplici 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 const int BBF_PART_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ; //---------------------------------------------------------------------------- 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 ; // 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 const double GAP = 5 * EPS_SMALL ; if ( dXmax < dXmin + GAP + 2 * EPS_SMALL || dYmax < dYmin + GAP + 2 * EPS_SMALL) return false ; // se già esiste, posso uscire int nBoxId = pGeomDB->GetFirstNameInGroup( nParentId, NST_SHEET_OUTREG) ; if ( nBoxId != GDB_ID_NULL) return true ; // gap per garantire simile risoluzione tra spazio parametrico e spazio geometrico double dGap = GAP * max( 1.0, ( 4 * ( dXmax - dXmin) + 4 * ( dYmax - dYmin)) * EPS_PARAM / EPS_SMALL) ; // creo polilinea attorno al box (avvolta a serpente) PolyLine PL ; PL.AddUPoint( 0, Point3d( dXmax, dYmax - dGap, dZ)) ; PL.AddUPoint( 1, Point3d( dXmax, dYmin, dZ)) ; PL.AddUPoint( 2, Point3d( dXmin, dYmin, dZ)) ; PL.AddUPoint( 3, Point3d( dXmin, dYmax, dZ)) ; PL.AddUPoint( 4, Point3d( dXmax - dGap, dYmax, dZ)) ; PL.AddUPoint( 5, Point3d( dXmax - dGap + 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, dYmax - dGap + SPESS, 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->SetStatus( nId, GDB_ST_OFF) ; 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 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 e fine pCompo->TrimStartAtLen( 5 * EPS_SMALL) ; double dCrvLen ; pCompo->GetLength( dCrvLen) && pCompo->TrimEndAtLen( dCrvLen - 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( b3Box.GetMax().x - 5 * EPS_SMALL, 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, b3Box.GetMax().y - 5 * EPS_SMALL, 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->SetStatus( nId, GDB_ST_OFF) ; pGeomDB->SetMaterial( nId, INVISIBLE) ; return true ; } //---------------------------------------------------------------------------- bool ExeCreateReferenceRegion( int nParentId, int nOutCrvId, bool bBottomUp) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // se già esiste, posso uscire int nRegId = pGeomDB->GetFirstNameInGroup( nParentId, NST_REFERENCE_REG) ; if ( nRegId != 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 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 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) ; // ne ricavo il bbox BBox3d b3Box ; PL.GetLocalBBox( b3Box) ; // cerco i punti più vicini ai quattro vertici (0=BL, 1=BR, 2=TR, 3=TL) double dU[4] = { -1, -1, -1, -1} ; double dMinSqDist[4] = { SQ_INFINITO, SQ_INFINITO, SQ_INFINITO, SQ_INFINITO} ; Point3d ptVert[4] ; ptVert[0] = b3Box.GetMin() ; ptVert[2] = b3Box.GetMax() ; ptVert[1] = ptVert[0] ; ptVert[1].x = ptVert[2].x ; ptVert[3] = ptVert[0] ; ptVert[3].y = ptVert[2].y ; Point3d ptQ ; double dPar ; bool bFound = PL.GetFirstUPoint( &dPar, &ptQ, true) ; while ( bFound) { for ( int i = 0 ; i < 4 ; ++ i) { double dSqDist = SqDistXY( ptQ, ptVert[i]) ; if ( dSqDist < dMinSqDist[i]) { dMinSqDist[i] = dSqDist ; dU[i] = dPar ; } } bFound = PL.GetNextUPoint( &dPar, &ptQ, true) ; } for ( int i = 0 ; i < 4 ; ++ i) { if ( dU[i] == - 1) return false ; if ( abs( dU[i] - dU[( i > 0 ? i-1 : 3)]) < EPS_SMALL) return false ; } // calcolo i box dei tre lati di interesse BBox3d b3Down ; BBox3d b3Left ; BBox3d b3Up ; bFound = PL.GetFirstUPoint( &dPar, &ptQ, true) ; while ( bFound) { // per lato sotto ( 0 -> 1) if ( ( dU[1] > dU[0] && dPar > dU[0] - EPS_ZERO && dPar < dU[1] + EPS_ZERO) || ( dU[1] < dU[0] && ( dPar > dU[0] - EPS_ZERO || dPar < dU[1] + EPS_ZERO))) b3Down.Add( ptQ) ; // per lato sopra ( 2 -> 3) if ( ( dU[3] > dU[2] && dPar > dU[2] - EPS_ZERO && dPar < dU[3] + EPS_ZERO) || ( dU[3] < dU[2] && ( dPar > dU[2] - EPS_ZERO || dPar < dU[3] + EPS_ZERO))) b3Up.Add( ptQ) ; // per lato a sinistra ( 3 -> 0) if ( ( dU[0] > dU[3] && dPar > dU[3] - EPS_ZERO && dPar < dU[0] + EPS_ZERO) || ( dU[0] < dU[3] && ( dPar > dU[3] - EPS_ZERO || dPar < dU[0] + EPS_ZERO))) b3Left.Add( ptQ) ; // prossimo punto bFound = PL.GetNextUPoint( &dPar, &ptQ, true) ; } // verifiche su box del lato a sinistra const double MAX_WIDTH_SIDE = 400 ; double dLeftDimX = b3Left.GetMax().x - b3Left.GetMin().x ; if ( dLeftDimX > MAX_WIDTH_SIDE) { b3Left.Translate( Vector3d( -dLeftDimX + 0.25 * MAX_WIDTH_SIDE, 0, 0)) ; } // costruisco la regione di riferimento PolyLine PL2 ; if ( bBottomUp) { PL2.AddUPoint( 0, Point3d( b3Box.GetMin().x - SPESS, b3Box.GetMin().y - SPESS, b3Box.GetMin().z)) ; PL2.AddUPoint( 1, Point3d( b3Box.GetMax().x + SPESS, b3Box.GetMin().y - SPESS, b3Box.GetMin().z)) ; PL2.AddUPoint( 2, Point3d( b3Box.GetMax().x + SPESS, b3Down.GetMax().y, b3Box.GetMin().z)) ; PL2.AddUPoint( 3, Point3d( b3Left.GetMax().x, b3Down.GetMax().y, b3Box.GetMin().z)) ; PL2.AddUPoint( 4, Point3d( b3Left.GetMax().x, b3Box.GetMax().y + SPESS, b3Box.GetMin().z)) ; PL2.AddUPoint( 5, Point3d( b3Box.GetMin().x - SPESS, b3Box.GetMax().y + SPESS, b3Box.GetMin().z)) ; PL2.Close() ; } else { PL2.AddUPoint( 0, Point3d( b3Box.GetMin().x - SPESS, b3Box.GetMin().y - SPESS, b3Box.GetMin().z)) ; PL2.AddUPoint( 1, Point3d( b3Left.GetMax().x, b3Box.GetMin().y - SPESS, b3Box.GetMin().z)) ; PL2.AddUPoint( 2, Point3d( b3Left.GetMax().x, b3Up.GetMin().y, b3Box.GetMin().z)) ; PL2.AddUPoint( 3, Point3d( b3Box.GetMax().x + SPESS, b3Up.GetMin().y, b3Box.GetMin().z)) ; PL2.AddUPoint( 4, Point3d( b3Box.GetMax().x + SPESS, b3Box.GetMax().y + SPESS, b3Box.GetMin().z)) ; PL2.AddUPoint( 5, Point3d( b3Box.GetMin().x - SPESS, b3Box.GetMax().y + SPESS, b3Box.GetMin().z)) ; PL2.Close() ; } // la converto in curva composita PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo) || ! pCompo->FromPolyLine( PL2)) 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_REFERENCE_REG) ; 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 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 ; } //---------------------------------------------------------------------------- class TrimLine { public : bool Init( IGeomDB* pGeomDB, const INTVECTOR& vTrueIds, bool bReducedCut) ; bool Verify( double dLineY, Intervals& inOk) ; private : bool TrimLineWithRegion( const ICurveLine* pLine, int nRegId, bool bOn, Intervals& inOut) ; private : IGeomDB* m_pGeomDB ; int m_nBoxId ; BBox3d m_b3Box ; int m_nRefReg ; INTVECTOR m_vDmgReg ; INTVECTOR m_vOthReg ; INTVECTOR m_vOthDwnReg ; INTVECTOR m_vOthCutReg ; INTVECTOR m_vOthDwnCutReg ; } ; //---------------------------------------------------------------------------- bool TrimLine::Init( IGeomDB* pGeomDB, const INTVECTOR& vTrueIds, bool bReducedCut) { // Assegno e verifico gestore DB geometrico m_pGeomDB = pGeomDB ; if ( m_pGeomDB == nullptr) 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) ; // Recupero box della regione valida m_nBoxId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_SHEET_OUTREG) ; if ( m_nBoxId == GDB_ID_NULL || ! pGeomDB->GetGlobalBBox( m_nBoxId, m_b3Box)) return false ; // Recupero la regione di riferimento e verifico se disabilitata m_nRefReg = pGeomDB->GetFirstNameInGroup( nGroupId, NST_REFERENCE_REG) ; if ( pGeomDB->ExistsInfo( m_nRefReg, KEY_NST_OFF)) m_nRefReg = GDB_ID_NULL ; // Recupero le aree danneggiate int nId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_DAMAGED_REG) ; while ( nId != GDB_ID_NULL) { m_vDmgReg.emplace_back( nId) ; nId = pGeomDB->GetNextName( nId, NST_DAMAGED_REG) ; } // Determino le regioni di tutti gli altri pezzi compresi nella regione di interesse 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) && m_b3Box.OverlapsXY( b3Part2)) { // recupero regione del pezzo int nRegId = GetFlatPartRegion( pGeomDB, nId2) ; if ( nRegId != GDB_ID_NULL) m_vOthReg.emplace_back( nRegId) ; else return false ; // recupero eventuale regione in basso del pezzo int nDwnRegId = GetFlatPartDownRegion( pGeomDB, nId2) ; m_vOthDwnReg.emplace_back( nDwnRegId) ; // recupero regioni dei tagli del pezzo if ( ! GetFlatPartCutRegions( pGeomDB, nId2, bReducedCut, m_vOthCutReg)) return false ; // recupero regioni in basso dei tagli del pezzo GetFlatPartDownCutRegions( pGeomDB, nId2, bReducedCut, m_vOthDwnCutReg) ; } } nId2 = ( bInRoot ? ExeGetNextPart( nId2, true) : ExeGetNextGroup( nId2)) ; } return true ; } //---------------------------------------------------------------------------- bool TrimLine::Verify( double dLineY, Intervals& inOk) { // Verifico se correttamente inizializzato if ( m_pGeomDB == nullptr || m_nBoxId == GDB_ID_NULL) return false ; // Limito la linea alla regione valida PtrOwner pLine( CreateCurveLine()) ; if ( IsNull( pLine) || ! pLine->Set( Point3d( m_b3Box.GetMin().x + 10 * EPS_SMALL, dLineY, 0), Point3d( m_b3Box.GetMax().x - 10 * EPS_SMALL, dLineY, 0))) return false ; if ( ! TrimLineWithRegion( pLine, m_nBoxId, true, inOk)) return false ; // Verifico con la regione di riferimento if ( m_nRefReg != GDB_ID_NULL) { Intervals inOut ; if ( ! TrimLineWithRegion( pLine, m_nRefReg, true, inOut)) return false ; inOk.Intersect( inOut) ; } // Verifico con le eventuali aree danneggiate for ( int nDmgRegId : m_vDmgReg) { Intervals inOut ; if ( ! TrimLineWithRegion( pLine, nDmgRegId, true, inOut)) return false ; inOk.Intersect( inOut) ; } // Verifico con le regioni degli altri pezzi for ( int nOthRegId : m_vOthReg) { Intervals inOut ; if ( ! TrimLineWithRegion( pLine, nOthRegId, false, inOut)) return false ; inOk.Intersect( inOut) ; } // e con le regioni dei tagli degli altri pezzi for ( int nOthCutRegId : m_vOthCutReg) { Intervals inOut ; if ( ! TrimLineWithRegion( pLine, nOthCutRegId, true, inOut)) return false ; inOk.Intersect( inOut) ; } // Verifico con le regioni sotto degli altri pezzi for ( int nOthDwnRegId : m_vOthDwnReg) { if ( nOthDwnRegId != GDB_ID_NULL) { Intervals inOut ; if ( ! TrimLineWithRegion( pLine, nOthDwnRegId, false, inOut)) return false ; inOk.Intersect( inOut) ; } } // e con le regioni sotto dei tagli degli altri pezzi for ( int nOthDwnCutRegId : m_vOthDwnCutReg) { if ( nOthDwnCutRegId != GDB_ID_NULL) { Intervals inOut ; if ( ! TrimLineWithRegion( pLine, nOthDwnCutRegId, true, inOut)) return false ; inOk.Intersect( inOut) ; } } return true ; } //---------------------------------------------------------------------------- bool TrimLine::TrimLineWithRegion( const ICurveLine* pLine, int nRegId, bool bOn, Intervals& inOut) { // recupero la regione const ISurfFlatRegion* pSFR = GetSurfFlatRegion( m_pGeomDB->GetGeoObj( nRegId)) ; if ( pSFR == nullptr) return false ; // recupero il riferimento della regione Frame3d frSFR ; if ( ! m_pGeomDB->GetGlobFrame( nRegId, frSFR)) return false ; // creo una copia della linea espressa nel riferimento della regione PtrOwnerpLocCrv( pLine->Clone()) ; if ( IsNull( pLocCrv) || ! pLocCrv->ToLoc( frSFR)) return false ; // calcolo la classificazione della curva rispetto alla regione CRVCVECTOR ccClass ; if ( ! pSFR->GetCurveClassification( *pLocCrv, EPS_SMALL, ccClass)) return false ; // determino gli intervalli di curva esterni alla regione inOut.Reset() ; for ( auto& ccOne : ccClass) { if ( ccOne.nClass == CRVC_OUT || ( bOn && ( ccOne.nClass == CRVC_ON_P || ccOne.nClass == CRVC_ON_M))) { double dXmin = pLine->GetStart().x + ccOne.dParS * ( pLine->GetEnd().x - pLine->GetStart().x) ; double dXmax = pLine->GetStart().x + ccOne.dParE * ( pLine->GetEnd().x - pLine->GetStart().x) ; inOut.Add( dXmin, dXmax) ; } } return true ; } //---------------------------------------------------------------------------- static bool MyVerifyPartCluster( IGeomDB* pGeomDB, const INTVECTOR& vTrueIds, const BBox3d& b3Cluster, bool bReducedCut) { // Determino le regioni dei pezzi INTVECTOR vReg ; INTVECTOR vUpReg ; 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 alto del pezzo int nUpRegId = GetFlatPartUpRegion( pGeomDB, nId) ; vUpReg.emplace_back( nUpRegId) ; // 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 (controllo semplice) 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 l'eventuale regione di riferimento (controllo semplice) // recupero la regione int nRefReg = pGeomDB->GetFirstNameInGroup( nGroupId, NST_REFERENCE_REG) ; if ( pGeomDB->ExistsInfo( nRefReg, KEY_NST_OFF)) nRefReg = GDB_ID_NULL ; if ( nRefReg != GDB_ID_NULL) { // regioni dei pezzi rispetto alla regione di riferimento for ( int nRegId : vReg) { if ( ExeSurfFrChunkSimpleClassify( nRegId, 0, nRefReg, 0) != REGC_OUT) return false ; } for ( int nDwnRegId : vDwnReg) { if ( nDwnRegId != GDB_ID_NULL) { if ( ExeSurfFrChunkSimpleClassify( nDwnRegId, 0, nRefReg, 0) != REGC_OUT) return false ; } } } // Verifico con le eventuali aree danneggiate // recupero le aree INTVECTOR vDmgReg ; int nId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_DAMAGED_REG) ; if ( nId != GDB_ID_NULL) { 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 (controllo completo) for ( int nRegId : vReg) { for ( int nDmgRegId : vDmgReg) { if ( ExeSurfFlatRegionInterference( nRegId, 0, nDmgRegId, 0) != REGC_OUT) return false ; } } for ( int nDwnRegId : vDwnReg) { if ( nDwnRegId != GDB_ID_NULL) { for ( int nDmgRegId : vDmgReg) { if ( ExeSurfFlatRegionInterference( nDwnRegId, 0, nDmgRegId, 0) != REGC_OUT) return false ; } } } } // Determino le regioni di tutti gli altri pezzi compresi nella regione di interesse INTVECTOR vOthReg ; INTVECTOR vOthUpReg ; 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 alto del pezzo int nUpRegId = GetFlatPartUpRegion( pGeomDB, nId2) ; vOthUpReg.emplace_back( nUpRegId) ; // 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 (controllo completo) // regioni dei pezzi for ( int i = 0 ; i < ssize( vReg) ; ++ i) { // verifico con le regioni degli altri pezzi for ( int nOthRegId : vOthReg) { if ( ExeSurfFlatRegionInterference( vReg[i], 0, nOthRegId, 0) != REGC_OUT) return false ; } // e con le regioni dei tagli degli altri pezzi (se esistono le regioni up devo usarle) int nRegUpId = ( ( vUpReg[i] == GDB_ID_NULL) ? vReg[i] : vUpReg[i]) ; for ( int nOthCutRegId : vOthCutReg) { if ( ExeSurfFlatRegionInterference( nRegUpId, 0, nOthCutRegId, 0) != REGC_OUT) return false ; } } // regioni sotto dei pezzi (controllo completo) for ( int i = 0 ; i < ssize( vDwnReg) ; ++ i) { // verifico con le regioni sotto degli altri pezzi for ( int j = 0 ; j < ssize( vOthDwnReg) ; ++ 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 ( ExeSurfFlatRegionInterference( nDwnRegId, 0, nOthDwnRegId, 0) != REGC_OUT) return false ; } } // e con le regioni sotto dei tagli degli altri pezzi for ( int j = 0 ; j < ssize( vOthDwnCutReg) ; ++ 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 ( ExeSurfFlatRegionInterference( 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 (controllo completo) for ( int j = 0 ; j < ssize( vOthReg) ; ++ j) { int nOthUpRegId = ( ( vOthUpReg[j] == GDB_ID_NULL) ? vOthReg[j] : vOthUpReg[j]) ; if ( ExeSurfFlatRegionInterference( nCutRegId, 0, nOthUpRegId, 0) != REGC_OUT) return false ; } } // regioni sotto delle lavorazioni dei pezzi for ( int i = 0 ; i < ssize( vDwnCutReg) ; ++ i) { // le confronto con le regioni sotto degli altri pezzi (controllo completo) for ( int j = 0 ; j < ssize( vOthDwnReg) ; ++ 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 ( ExeSurfFlatRegionInterference( 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) ; // 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 ; // 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 ; Point3d ptOrig = b3RegCluster.GetMin() ; // Determino punto più in basso a sinistra del cluster Point3d ptBL = b3RegCluster.GetMax() ; double dDimBottom = 0 ; for ( int nId : vTrueIds) { // recupero l'approssimazione lineare del contorno del pezzo ( in globale) PolyLine PL ; if ( GetFlatPartApproxContour( pGeomDB, nId, PL)) { // cerco il punto più in basso a sinistra Point3d ptP ; bool bFound = PL.GetFirstPoint( ptP) ; while ( bFound) { if ( abs( ptP.y - ptBL.y) < EPS_SMALL) { ptBL.x = min( ptBL.x, ptP.x) ; dDimBottom = max( dDimBottom, abs( ptBL.x - ptP.x)) ; } else if ( ptP.y < ptBL.y) { ptBL = ptP ; dDimBottom = 0 ; } bFound = PL.GetNextPoint( ptP) ; } } } double dRegCLDeltaX = ptBL.x - ptOrig.x ; // Assegno gli step per i tentativi di inserimento e la minima lughezza utile const double STEP_X = 20 ; const double STEP_Y = 20 ; double dMinRange = max( dDimBottom, 20.) ; // Inserimento per tentativi con metodo delle linee TrimLine tlObj ; tlObj.Init( pGeomDB, vTrueIds, bReducedCut) ; bool bFit = false ; double dYmin = b3Box.GetMin().y ; double dYmax = b3Box.GetMax().y - dRegClDimY ; double dRangeY = dYmax - dYmin ; int nStepY = ( dRangeY > - EPS_SMALL ? int( ceil( dRangeY / STEP_Y)) : -1) ; double dStepY = ( nStepY > 0 ? ( dRangeY / nStepY) : 0) ; for ( int j = 0 ; j <= nStepY ; ++j) { double dLineY = ( bBottomUp ? dYmin + j * dStepY : dYmax - j * dStepY) ; // recupero la prossima linea valida Intervals inOk ; if ( tlObj.Verify( dLineY, inOk)) { // ciclo sugli intervalli validi della linea double dXmin, dXmax ; bool bOk = inOk.GetFirst( dXmin, dXmax) ; while ( bOk && ! bFit) { // limito minimo per box cluster a sinistra del box lastra dXmin = max( dXmin, b3Box.GetMin().x + dRegCLDeltaX) ; // limito massimo per min range e per box cluster a destra del box lastra dXmax = min( dXmax - dMinRange, b3Box.GetMax().x - ( dRegClDimX - dRegCLDeltaX)) ; // ciclo sui punti double dRangeX = dXmax - dXmin ; int nStepX = ( dRangeX > - EPS_SMALL ? int( ceil( dRangeX / STEP_X)) : -1) ; double dStepX = ( nStepX > 0 ? (dRangeX / nStepX) : 0) ; for ( int j = 0 ; j <= nStepX ; ++j) { int k = ( j > 1 ? j : 1 - j) ; // posizione di prova Point3d ptIns = Point3d( dXmin + k * dStepX, dLineY, b3Box.GetMin().z) ; // porto nella posizione di prova Vector3d vtMove = ptIns - ( b3RegCluster.GetMin() + Vector3d( dRegCLDeltaX, 0, 0)) ; 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 ; } } // passo all'intervallo successivo sulla linea bOk = inOk.GetNext( dXmin, dXmax) ; } } // se trovato, esco if ( bFit) break ; } // 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, const 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 ; } //---------------------------------------------------------------------------- // Collisione semplice 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)) ; if ( pSfr1 == nullptr) return false ; // recupero il riferimento della superficie Frame3d frSurf1 ; if ( ! pGeomDB->GetGlobFrame( nId1, frSurf1)) return false ; // recupero la seconda superficie FlatRegion const ISurfFlatRegion* pSfr2 = GetSurfFlatRegion( pGeomDB->GetGeoObj( nId2)) ; if ( pSfr2 == nullptr) return false ; // recupero il riferimento della superficie Frame3d frSurf2 ; if ( ! pGeomDB->GetGlobFrame( nId2, frSurf2)) return false ; // se riferimenti diversi, porto una copia della seconda nel riferimento della prima const ISurfFlatRegion* pSfr2L = pSfr2 ; PtrOwner pTmp ; if ( ! AreSameFrame( frSurf1, frSurf2)) { pTmp.Set( pSfr2->Clone()) ; if ( IsNull( pTmp) || ! pTmp->LocToLoc( frSurf2, frSurf1)) return false ; 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 CAvSimpleSurfFrMove ScdSfrMove( *pSfr1, *pSfr2L) ; if ( ! ScdSfrMove.Translate( vtDirL, dLen)) return false ; 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 true ; } //---------------------------------------------------------------------------- // Collisione completa static bool MySurfFrMoveNoCollision( int nId1, int nId2, const Vector3d& vtDir, double& dLen, SCollInfo& cInfo) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, GDB_ID_NULL) // recupero la prima superficie FlatRegion ISurfFlatRegion* pSfr1 = GetSurfFlatRegion( pGeomDB->GetGeoObj( nId1)) ; if ( pSfr1 == nullptr) return false ; // recupero il riferimento della superficie Frame3d frSurf1 ; if ( ! pGeomDB->GetGlobFrame( nId1, frSurf1)) return false ; // recupero la seconda superficie FlatRegion const ISurfFlatRegion* pSfr2 = GetSurfFlatRegion( pGeomDB->GetGeoObj( nId2)) ; if ( pSfr2 == nullptr) return false ; // recupero il riferimento della superficie Frame3d frSurf2 ; if ( ! pGeomDB->GetGlobFrame( nId2, frSurf2)) return false ; // se riferimenti diversi, porto una copia della seconda nel riferimento della prima const ISurfFlatRegion* pSfr2L = pSfr2 ; PtrOwner pTmp ; if ( ! AreSameFrame( frSurf1, frSurf2)) { pTmp.Set( pSfr2->Clone()) ; if ( IsNull( pTmp) || ! pTmp->LocToLoc( frSurf2, frSurf1)) return false ; 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 collisione con la seconda CAvSurfFrMove cdSfrMove( *pSfr1, *pSfr2L) ; if ( ! cdSfrMove.Translate( vtDirL, dLen)) return false ; cInfo = cdSfrMove.GetCollInfo() ; if ( cInfo.nType != SCI_NONE) { cInfo.ptP1.ToGlob( frSurf1) ; cInfo.vtDirM.ToGlob( frSurf1) ; cInfo.vtDirF.ToGlob( frSurf1) ; } if ( cInfo.nType == SCI_LINE_LINE) cInfo.ptP2.ToGlob( frSurf1) ; return true ; } //---------------------------------------------------------------------------- // Traslazione con CAvSurfFr 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 ; // 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 eventuale regione di riferimento int nRefReg = pGeomDB->GetFirstNameInGroup( nGroupId, NST_REFERENCE_REG) ; if ( pGeomDB->ExistsInfo( nRefReg, KEY_NST_OFF)) nRefReg = GDB_ID_NULL ; // 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 vOthUpReg ; 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 alto del pezzo int nUpRegId = GetFlatPartUpRegion( pGeomDB, nId2) ; vOthUpReg.emplace_back( nUpRegId) ; // 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 (collisione semplice) MySurfFrMoveSimpleNoCollision( nRegId, nBoxId, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nRegId, nBoxId, false, false, scInfoCurr) ; // la confronto con la regione di riferimento (collisione semplice) if ( nRefReg != GDB_ID_NULL) { MySurfFrMoveSimpleNoCollision( nRegId, nRefReg, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nRegId, nRefReg, false, false, scInfoCurr) ; } // la confronto con le aree danneggiate (collisione completa) for ( int nDmgRegId : vDmgReg) { MySurfFrMoveNoCollision( nRegId, nDmgRegId, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nRegId, nDmgRegId, false, false, scInfoCurr) ; } // la confronto con le regioni degli altri pezzi (collisione completa) for ( int nOthRegId : vOthReg) { MySurfFrMoveNoCollision( nRegId, nOthRegId, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nRegId, nOthRegId, false, false, scInfoCurr) ; } // e con le regioni dei tagli degli altri pezzi // recupero regione in alto del pezzo (collisione completa) int nUpRegId = GetFlatPartUpRegion( pGeomDB, nTrueId) ; int nTestRegId = (( nUpRegId == GDB_ID_NULL) ? nRegId : nUpRegId) ; for ( int nOthCutRegId : vOthCutReg) { MySurfFrMoveNoCollision( nTestRegId, nOthCutRegId, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nTestRegId, nOthCutRegId, false, true, scInfoCurr) ; } // ----------------------------------------- // recupero regione in basso del pezzo int nDwnRegId = GetFlatPartDownRegion( pGeomDB, nTrueId) ; // la confronto con il box (collisone semplice) if ( nDwnRegId != GDB_ID_NULL) { MySurfFrMoveSimpleNoCollision( nDwnRegId, nBoxId, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nDwnRegId, nBoxId, false, false, scInfoCurr) ; } // la confronto con la regione di riferimento (collisione completa) if ( nDwnRegId != GDB_ID_NULL && nRefReg != GDB_ID_NULL) { MySurfFrMoveNoCollision( nDwnRegId, nRefReg, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nDwnRegId, nRefReg, false, false, scInfoCurr) ; } // la confronto con le aree danneggiate (collisione completa) if ( nDwnRegId != GDB_ID_NULL) { for ( int nDmgRegId : vDmgReg) { MySurfFrMoveNoCollision( nDwnRegId, nDmgRegId, vtDir, dLen, scInfoCurr) ; dPrevLen = UpdateCollId( dLen, dPrevLen, nDwnRegId, nDmgRegId, false, false, scInfoCurr) ; } } // la confronto con le regioni in basso degli altri pezzi (collisione completa) for ( int j = 0 ; j < ssize( vOthDwnReg) ; ++ 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]) ; MySurfFrMoveNoCollision( 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 (collisione completa) for ( int j = 0 ; j < ssize( vOthDwnCutReg) ; ++ 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]) ; MySurfFrMoveNoCollision( 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 (collisione completa) for ( int nCrId : vCrId) { for ( int k = 0 ; k < ssize( vOthReg) ; ++ k) { int nOthRegId = ( vOthUpReg[k] == GDB_ID_NULL ? vOthReg[k] : vOthUpReg[k]) ; MySurfFrMoveNoCollision( 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 (collisione completa) for ( int j = 0 ; j < ssize( vDwnCrId) ; ++ j) { for ( int k = 0 ; k < ssize( vOthDwnReg) ; ++ 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]) ; MySurfFrMoveNoCollision( 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) ; } } } //---------------------------------------------------------------------------- static bool MySurfFrRotateNoCollision( int nId1, int nId2, const Point3d& ptCen, double& dAngDeg, SCollInfo& cInfo) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, GDB_ID_NULL) // recupero la prima superficie FlatRegion ISurfFlatRegion* pSfr1 = GetSurfFlatRegion( pGeomDB->GetGeoObj( nId1)) ; if ( pSfr1 == nullptr) return false ; // recupero il riferimento della superficie Frame3d frSurf1 ; if ( ! pGeomDB->GetGlobFrame( nId1, frSurf1)) return false ; // recupero la seconda superficie FlatRegion const ISurfFlatRegion* pSfr2 = GetSurfFlatRegion( pGeomDB->GetGeoObj( nId2)) ; if ( pSfr2 == nullptr) return false ; // recupero il riferimento della superficie Frame3d frSurf2 ; if ( ! pGeomDB->GetGlobFrame( nId2, frSurf2)) return false ; // se riferimenti diversi, porto una copia della seconda nel riferimento della prima const ISurfFlatRegion* pSfr2L = pSfr2 ; PtrOwner pTmp ; if ( ! AreSameFrame( frSurf1, frSurf2)) { pTmp.Set( pSfr2->Clone()) ; if ( IsNull( pTmp) || ! pTmp->LocToLoc( frSurf2, frSurf1)) return false ; pSfr2L = pTmp ; } // porto in locale alla prima superficie il punto di rotazione Point3d ptCenL = ptCen ; ptCenL.ToLoc( frSurf1) ; // calcolo massima lunghezza di traslazione della prima regione senza collisione con la seconda CAvSurfFrMove cdSfrMove( *pSfr1, *pSfr2L) ; if ( ! cdSfrMove.Rotate( ptCenL, dAngDeg)) return false ; return true ; } //---------------------------------------------------------------------------- // Rotazione con CAvSurfFr 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 // 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 eventuale regione di riferimento int nRefReg = pGeomDB->GetFirstNameInGroup( nGroupId, NST_REFERENCE_REG) ; if ( pGeomDB->ExistsInfo( nRefReg, KEY_NST_OFF)) nRefReg = GDB_ID_NULL ; // 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 vOthUpReg ; 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 alto del pezzo int nUpRegId = GetFlatPartUpRegion( pGeomDB, nId2) ; vOthUpReg.emplace_back( nUpRegId) ; // 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 (collisione semplice) ExeSurfFrRotateSimpleNoCollision( nRegId, nBoxId, ptCen, dAng, RTY_GLOB) ; // la confronto con la regione di riferimento (collisione semplice) if ( nRefReg != GDB_ID_NULL) { ExeSurfFrRotateSimpleNoCollision( nRegId, nRefReg, ptCen, dAng, RTY_GLOB) ; } // la confronto con le aree danneggiate (collisione completa) for ( int nDmgRegId : vDmgReg) { MySurfFrRotateNoCollision( nRegId, nDmgRegId, ptCen, dAng, s_scInfo) ; } // la confronto con le regioni degli altri pezzi (collisione completa) for ( int nOthRegId : vOthReg) { MySurfFrRotateNoCollision( nRegId, nOthRegId, ptCen, dAng, s_scInfo) ; } // e con le regioni dei tagli degli altri pezzi (collisione completa) // recupero regione in alto del pezzo int nUpRegId = GetFlatPartUpRegion( pGeomDB, nTrueId) ; int nTestRegId = (( nUpRegId == GDB_ID_NULL) ? nRegId : nUpRegId) ; for ( int nOthCutRegId : vOthCutReg) { ExeSurfFrRotateSimpleNoCollision( nTestRegId, nOthCutRegId, ptCen, dAng, RTY_GLOB) ; } // ----------------------------------------- // recupero regione in basso del pezzo int nDwnRegId = GetFlatPartDownRegion( pGeomDB, nTrueId) ; // la confronto con il box (collisione semplice) if ( nDwnRegId != GDB_ID_NULL) ExeSurfFrRotateSimpleNoCollision( nDwnRegId, nBoxId, ptCen, dAng, RTY_GLOB) ; // la confronto con la regione di riferimento (collisione semplice) if ( nRefReg != GDB_ID_NULL) { ExeSurfFrRotateSimpleNoCollision( nDwnRegId, nRefReg, ptCen, dAng, RTY_GLOB) ; } // la confronto con le aree danneggiate (collisione completa) if ( nDwnRegId != GDB_ID_NULL) { for ( int nDmgRegId : vDmgReg) { MySurfFrRotateNoCollision( nDwnRegId, nDmgRegId, ptCen, dAng, s_scInfo) ; } } // la confronto con le regioni in basso degli altri pezzi (collisione completa) for ( int j = 0 ; j < ssize( vOthDwnReg) ; ++ 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]) ; MySurfFrRotateNoCollision( nTmpDwnRegId, nOthDwnRegId, ptCen, dAng, s_scInfo) ; } } // e con le regioni in basso dei tagli degli altri pezzi (collisione completa) for ( int j = 0 ; j < ssize( vOthDwnCutReg) ; ++ 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]) ; MySurfFrRotateNoCollision( nTmpDwnRegId, nOthDwnCutRegId, ptCen, dAng, s_scInfo) ; } } // ----------------------------------------- // 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 (collisione completa) for ( int nCrId : vCrId) { for ( int k = 0 ; k < ssize( vOthReg) ; ++ k) { int nOthRegId = ( vOthUpReg[k] == GDB_ID_NULL ? vOthReg[k] : vOthUpReg[k]) ; MySurfFrRotateNoCollision( nCrId, nOthRegId, ptCen, dAng, s_scInfo) ; } } // ----------------------------------------- // 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 (collisione completa) for ( int j = 0 ; j < ssize( vDwnCrId) ; ++ j) { for ( int k = 0 ; k < ssize( vOthDwnReg) ; ++ 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]) ; MySurfFrRotateNoCollision( nTmpDwnCrId, nOthDwnRegId, ptCen, dAng, s_scInfo) ; } } } } // Se errore if ( ! bOk) return false ; // Se movimento risultante nullo, non faccio alcunché dRotAngDeg = dAng ; if ( abs( 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, s_scInfo.nLoopM)) ; if ( IsNull( pCrv)) return false ; double dU ; if ( ! pCrv->GetParamAtPoint( ptCntL, dU, 10 * EPS_SMALL)) return false ; if ( abs( 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 = ( abs( dRotAngDeg) > 100.0 * EPS_ANG_ZERO) ; 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 ; INTVECTOR vnGeoM, vnGeoF ; 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) { if ( s_scInfo.nIdM == GDB_ID_NULL) return false ; nCutM = s_scInfo.nIdM ; vnGeoM = GetGeometryFromCut( pGeomDB, pMachMgr, nCutM) ; if ( vnGeoM.empty()) return false ; ICurveLine* pLineM = nullptr ; // se ho un solo taglio, allora è quello if ( ssize( vnGeoM) == 1) { pLineM = GetCurveLine( pGeomDB->GetGeoObj( vnGeoM[0])) ; nGeoM = vnGeoM[0] ; } // se più tagli, cerco quello più vicino alla linea corrente else { double dMinSqDist = INFINITO ; for ( int i = 0 ; i < ssize( vnGeoM) ; ++ i) { Frame3d frCurrGeoM ; ICurveLine* pCurrLineM = GetCurveLine( pGeomDB->GetGeoObj( vnGeoM[i])) ; if ( pCurrLineM == nullptr || ! pGeomDB->GetGlobFrame( vnGeoM[i], frCurrGeoM)) return false ; double dCurrSqDist ; DistPointLine( GetToLoc( s_scInfo.ptP1, frCurrGeoM), *pCurrLineM).GetSqDist( dCurrSqDist) ; if ( dCurrSqDist < dMinSqDist) { dMinSqDist = dCurrSqDist ; pLineM = pCurrLineM ; nGeoM = vnGeoM[i] ; } } } if ( 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) { if ( s_scInfo.nChunkF == GDB_ID_NULL) return false ; nCutF = s_scInfo.nIdF ; vnGeoF = GetGeometryFromCut( pGeomDB, pMachMgr, nCutF) ; ICurveLine* pLineF = GetCurveLine( pGeomDB->GetGeoObj( nGeoF)) ; // se ho un solo taglio, allora è quello if ( ssize( vnGeoF) == 1) { pLineF = GetCurveLine( pGeomDB->GetGeoObj( vnGeoF[0])) ; nGeoF = vnGeoF[0] ; } // se più tagli, cerco quello più vicino alla linea corrente else { double dMinSqDist = INFINITO ; for ( int i = 0 ; i < ssize( vnGeoF) ; ++ i) { Frame3d frCurrGeoF ; ICurveLine* pCurrLineF = GetCurveLine( pGeomDB->GetGeoObj( vnGeoF[i])) ; if ( pCurrLineF == nullptr || ! pGeomDB->GetGlobFrame( vnGeoF[i], frCurrGeoF)) return false ; double dCurrSqDist ; DistPointLine( GetToLoc( s_scInfo.ptP1, frCurrGeoF), *pCurrLineF).GetSqDist( dCurrSqDist) ; if ( dCurrSqDist < dMinSqDist) { dMinSqDist = dCurrSqDist ; pLineF = pCurrLineF ; nGeoF = vnGeoF[i] ; } } } if ( 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 = GDB_ID_NULL ; INTVECTOR vnGeom = GetGeometryFromCut( pGeomDB, pMachMgr, nId) ; ICurveLine* pLine = nullptr ; // se ho un solo taglio, allora è quello if ( ssize( vnGeom) == 1) { pLine = GetCurveLine( pGeomDB->GetGeoObj( vnGeom[0])) ; nGeom = vnGeom[0] ; } // se ho più tagli, cerco quello più vicino alla linea corrente else { double dMinSqDist = INFINITO ; for ( int i = 0 ; i < ssize( vnGeom) ; ++ i) { Frame3d frCurrGeo ; ICurveLine* pCurrLine = GetCurveLine( pGeomDB->GetGeoObj( vnGeom[i])) ; if ( pCurrLine == nullptr || ! pGeomDB->GetGlobFrame( vnGeom[i], frCurrGeo)) return false ; double dCurrSqDist ; DistPointLine( GetToLoc( s_scInfo.ptP1, frCurrGeo), *pCurrLine).GetSqDist( dCurrSqDist) ; if ( dCurrSqDist < dMinSqDist) { dMinSqDist = dCurrSqDist ; pLine = pCurrLine ; nGeom = vnGeom[i] ; } } } 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 = GDB_ID_NULL ; INTVECTOR vnGeom = GetGeometryFromCut( pGeomDB, pMachMgr, nId) ; ICurveLine* pLine = nullptr ; // se ho un solo taglio, allora è quello if ( ssize( vnGeom) == 1) { pLine = GetCurveLine( pGeomDB->GetGeoObj( vnGeom[0])) ; nGeom = vnGeom[0] ; } // se ho più tagli, cerco quello più vicino alla linea corrente else { double dMinSqDist = INFINITO ; for ( int i = 0 ; i < ssize( vnGeom) ; ++ i) { Frame3d frCurrGeo ; ICurveLine* pCurrLine = GetCurveLine( pGeomDB->GetGeoObj( vnGeom[0])) ; if ( pCurrLine == nullptr || ! pGeomDB->GetGlobFrame( vnGeom[i], frCurrGeo)) return false ; double dCurrSqDist ; DistPointLine( GetToLoc( s_scInfo.ptP1, frCurrGeo), *pCurrLine).GetSqDist( dCurrSqDist) ; if ( dCurrSqDist < dMinSqDist) { dMinSqDist = dCurrSqDist ; pLine = pCurrLine ; nGeom = vnGeom[i] ; } } } 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 double dTotArea = 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 e l'area Point3d ptRcen ; if ( ! pSfr->GetCentroid( ptRcen)) return false ; double dArea ; if ( ! pSfr->GetArea( dArea)) 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 * dArea ; dTotArea += dArea ; } // Verifico di aver trovato qualcosa if ( dTotArea < EPS_SMALL * EPS_SMALL) return false ; // Medio il centro ptCen /= dTotArea ; return true ; } //---------------------------------------------------------------------------- bool ExeAutomaticPackParts( INTVECTOR& vIds, bool bMinimizeOnXvsY, bool bReducedCut, bool bGuillotineMode, int nMaxTime) { // Dichiaro tutti i pezzi non nestati for ( int i = 0 ; i < int( vIds.size()) ; ++ i) vIds[i] = - vIds[i] ; // Verifico gestore DB geometrico IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Verifico pezzi e determino se sotto la radice o in altro gruppo int nGroupId = pGeomDB->GetParentId( ( vIds.size() > 0 ? abs( vIds[0]) : GDB_ID_NULL)) ; if ( nGroupId == GDB_ID_NULL) return false ; bool bInRoot = ( nGroupId == GDB_ID_ROOT) ; // Avvio nesting automatico ExeAutoNestStart() ; // Modalità ghigliottina incompatibile con tagli completi if ( ! bReducedCut) bGuillotineMode = false ; // Definisco un solo pannello int nSheetId = 1 ; // Assegno il contorno del pannello ( parte utile) int nKerfId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_SHEET_KERF) ; if ( nKerfId == GDB_ID_NULL) return false ; bool bIsRect = false ; ExeAutoNestAddSheet( nSheetId, nKerfId, 0.0, 0, 1, &bIsRect) ; // Recupero la regione di riferimento e verifico se disabilitata int nRefReg = pGeomDB->GetFirstNameInGroup( nGroupId, NST_REFERENCE_REG) ; if ( ! pGeomDB->ExistsInfo( nRefReg, KEY_NST_OFF)) ExeAutoNestAddDefectToSheet( nSheetId, nRefReg) ; // Recupero le aree danneggiate int nDamId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_DAMAGED_REG) ; while ( nDamId != GDB_ID_NULL) { ExeAutoNestAddDefectToSheet( nSheetId, nDamId) ; nDamId = pGeomDB->GetNextName( nDamId, NST_DAMAGED_REG) ; } // Modalità ghigliottina incompatibile con pannelli non rettangolari if ( ! bIsRect) bGuillotineMode = false ; // Assegno le aree occupate dai pezzi già nestati bool bPartAlreadyNested = false ; BBox3d b3Sheet ; pGeomDB->GetGlobalBBox( nRefReg, b3Sheet) ; int nId = ( bInRoot ? ExeGetFirstPart( true) : ExeGetFirstGroupInGroup( nGroupId)) ; while ( nId != GDB_ID_NULL) { // se pezzo non nell'elenco if ( find( vIds.begin(), vIds.end(), -nId) == vIds.end()) { BBox3d b3Part ; if ( pGeomDB->GetGlobalBBox( nId, b3Part, BBF_PART_MY_FLAG) && b3Sheet.OverlapsXY( b3Part)) { // recupero regione del pezzo int nRegId = GetFlatPartRegion( pGeomDB, nId) ; ExeAutoNestAddDefectToSheet( nSheetId, nRegId) ; // recupero eventuale regione in basso del pezzo int nDwnRegId = GetFlatPartDownRegion( pGeomDB, nId) ; if ( nDwnRegId != GDB_ID_NULL) ExeAutoNestAddDefectToSheet( nSheetId, nDwnRegId) ; // recupero regioni dei tagli del pezzo INTVECTOR vCutReg ; if ( ! GetFlatPartCutRegions( pGeomDB, nId, bReducedCut, vCutReg)) return false ; // recupero eventuali regioni in basso dei tagli del pezzo GetFlatPartDownCutRegions( pGeomDB, nId, bReducedCut, vCutReg) ; for ( int nRegId : vCutReg) ExeAutoNestAddDefectToSheet( nSheetId, nRegId) ; // dichiaro ci sono pezzi già nestati bPartAlreadyNested = true ; } } nId = ( bInRoot ? ExeGetNextPart( nId, true) : ExeGetNextGroup( nId)) ; } // Pezzi già nestati incompatibili con ghigliottina if ( bPartAlreadyNested) bGuillotineMode = false ; // Se richiesta modalità ghigliottina if ( bGuillotineMode) { // cerco il gap necessario tra le parti double dGap = 0 ; for ( int nPartId : vIds) { nPartId = abs( nPartId) ; double dCurrGap = 0 ; if ( GetFlatPartInterpartGap( pGeomDB, nPartId, dCurrGap) && dCurrGap > dGap) dGap = dCurrGap ; } // se non trovato disabilito richiesta modalità ghigliottina if ( dGap < EPS_SMALL) bGuillotineMode = false ; // altrimenti lo imposto else ExeAutoNestSetInterpartGap( dGap) ; } // Se richiesto e abilitato, imposto modalità ghigliottina if ( bGuillotineMode) ExeAutoNestSetGuillotineMode() ; // Assegno i pezzi da nestare for ( int nPartId : vIds) { nPartId = abs( nPartId) ; // flag rotazione bool bEnableRot = ! pGeomDB->ExistsInfo( nPartId, NST_PART_ROT) ; // recupero regione del pezzo int nRegId = GetFlatPartRegion( pGeomDB, nPartId) ; ExeAutoNestAddPart( nPartId, nRegId, false, bEnableRot, 0.0, 0, 1) ; // recupero eventuale regione in basso del pezzo int nDwnRegId = GetFlatPartDownRegion( pGeomDB, nPartId) ; if ( nDwnRegId != GDB_ID_NULL) ExeAutoNestAddAnotherOutlineToPart( nPartId, nDwnRegId) ; // se non è ghigliottina imposto le regioni dei tagli (con ghigliottina si usa il gap) if ( ! bGuillotineMode) { // recupero regioni dei tagli del pezzo INTVECTOR vCutReg ; if ( ! GetFlatPartCutRegions( pGeomDB, nPartId, bReducedCut, vCutReg)) return false ; // recupero eventuali regioni in basso dei tagli del pezzo GetFlatPartDownCutRegions( pGeomDB, nPartId, bReducedCut, vCutReg) ; for ( int nRegId : vCutReg) ExeAutoNestAddToolOutlineToPart( nPartId, nRegId) ; } } // Eseguo il nesting ExeAutoNestCompute( bMinimizeOnXvsY, nMaxTime) ; bool bOk = true ; int nTime = 0 ; while ( bOk) { int nStat ; bOk = ExeAutoNestGetComputationStatus( nStat) ; if ( nStat == 2 || nStat == 3) { // eventuale raccolta dati e visualizzazione dinamica } if ( nStat == 3) break ; nTime += 1 ; if ( ExeProcessEvents( int( 1.0 * nTime / nMaxTime * 100), 995) == 1) { bOk = ExeAutoNestCancelComputation() ; break ; } } // Recupero i risultati int nNestedParts, nParts, nSheets, nNestings ; double dTotFillRatio ; if ( ! ExeAutoNestGetResults( nNestedParts, nParts, nSheets, nNestings, dTotFillRatio)) return false ; for ( int j = 0 ; ; ++ j) { int nType, nId, nFlag ; double dX, dY, dAngRot ; if ( ! ExeAutoNestGetOneResult( j, nType, nId, nFlag, dX, dY, dAngRot)) break ; if ( nType == 0) { // flip su Y escluso, si fanno rotazione e spostamento pGeomDB->RotateGlob( nId, ORIG, Z_AX, dAngRot) ; pGeomDB->TranslateGlob( nId, Vector3d( dX, dY, 0)) ; // segnalo che pezzo nestato for ( int i = 0 ; i < int( vIds.size()) ; ++ i) { if ( vIds[i] == - nId) vIds[i] = nId ; } } } return true ; }