diff --git a/EXE_Nst.h b/EXE_Nst.h index 3754bf5..d04fe52 100644 --- a/EXE_Nst.h +++ b/EXE_Nst.h @@ -23,3 +23,4 @@ bool GetFlatPartDownCutRegions( IGeomDB* pGeomDB, int nId, bool bReduced, INTVEC int GetFlatPartFromRegion( IGeomDB* pGeomDB, int nId) ; int GetFlatPartFromCut( IGeomDB* pGeomDB, int nId) ; int GetGeometryFromCut( IGeomDB* pGeomDB, IMachMgr* pMachMgr, int nId) ; +bool GetFlatPartApproxContour( IGeomDB* pGeomDB, int nId, PolyLine& PL) ; diff --git a/EXE_NstCreateFlatParts.cpp b/EXE_NstCreateFlatParts.cpp index cb74b29..96faa38 100644 --- a/EXE_NstCreateFlatParts.cpp +++ b/EXE_NstCreateFlatParts.cpp @@ -16,6 +16,7 @@ #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/EXeCmdLogOff.h" @@ -955,6 +956,8 @@ ExeCalcFlatPartDownRegion( int nPartId, double dH) int GetFlatPartRegion( IGeomDB* pGeomDB, int nId) { + if ( pGeomDB == nullptr) + return GDB_ID_NULL ; // recupero regione del pezzo (č la prima del sottogruppo di nome Region) int nRegGrp = pGeomDB->GetFirstNameInGroup( nId, NST_PARTREG_LAYER) ; int nRegId = pGeomDB->GetFirstInGroup( nRegGrp) ; @@ -970,6 +973,8 @@ GetFlatPartRegion( IGeomDB* pGeomDB, int nId) int GetFlatPartDownRegion( IGeomDB* pGeomDB, int nId) { + if ( pGeomDB == nullptr) + return GDB_ID_NULL ; // recupero regione del pezzo (č la prima del sottogruppo di nome DwnReg) int nRegGrp = pGeomDB->GetFirstNameInGroup( nId, NST_PARTDOWNREG_LAYER) ; int nRegId = pGeomDB->GetFirstInGroup( nRegGrp) ; @@ -985,6 +990,8 @@ GetFlatPartDownRegion( IGeomDB* pGeomDB, int nId) bool GetFlatPartCutRegions( IGeomDB* pGeomDB, int nId, bool bReduced, INTVECTOR& vCrId) { + if ( pGeomDB == nullptr) + return GDB_ID_NULL ; // recupero gruppo preview lavorazioni del pezzo int nPVGrp = pGeomDB->GetFirstNameInGroup( nId, MCH_PV) ; if ( nPVGrp == GDB_ID_NULL) @@ -1010,6 +1017,8 @@ GetFlatPartCutRegions( IGeomDB* pGeomDB, int nId, bool bReduced, INTVECTOR& vCrI bool GetFlatPartDownCutRegions( IGeomDB* pGeomDB, int nId, bool bReduced, INTVECTOR& vDwnCrId) { + if ( pGeomDB == nullptr) + return GDB_ID_NULL ; // recupero gruppo preview lavorazioni del pezzo int nPVGrp = pGeomDB->GetFirstNameInGroup( nId, MCH_PV) ; if ( nPVGrp == GDB_ID_NULL) @@ -1038,6 +1047,8 @@ GetFlatPartDownCutRegions( IGeomDB* pGeomDB, int nId, bool bReduced, INTVECTOR& int GetFlatPartFromRegion( IGeomDB* pGeomDB, int nId) { + if ( pGeomDB == nullptr) + return GDB_ID_NULL ; // verifico che il layer di appartenenza sia una regione int nLayerId = pGeomDB->GetParentId( nId) ; string sName ; @@ -1053,6 +1064,8 @@ GetFlatPartFromRegion( IGeomDB* pGeomDB, int nId) int GetFlatPartFromCut( IGeomDB* pGeomDB, int nId) { + if ( pGeomDB == nullptr) + return GDB_ID_NULL ; // verifico appartenga al gruppo PreView (padre di padre di padre) int nPvId = pGeomDB->GetParentId( pGeomDB->GetParentId( pGeomDB->GetParentId( nId))) ; string sName ; @@ -1066,6 +1079,8 @@ GetFlatPartFromCut( IGeomDB* pGeomDB, int nId) int GetGeometryFromCut( IGeomDB* pGeomDB, IMachMgr* pMachMgr, int nId) { + if ( pGeomDB == nullptr || pMachMgr == nullptr) + return GDB_ID_NULL ; // verifico appartenga ad una lavorazione int nMchId ; if ( ! pGeomDB->GetInfo( pGeomDB->GetParentId( pGeomDB->GetParentId( nId)), "MId", nMchId)) @@ -1080,3 +1095,24 @@ GetGeometryFromCut( IGeomDB* pGeomDB, IMachMgr* pMachMgr, int nId) else return GDB_ID_NULL ; } + +//---------------------------------------------------------------------------- +bool +GetFlatPartApproxContour( IGeomDB* pGeomDB, int nId, PolyLine& PL) +{ + if ( pGeomDB == nullptr) + return false ; + // Recupero la superficie regione piana + int nRegId = GetFlatPartRegion( pGeomDB, nId) ; + const ISurfFlatRegion* pSfr = GetSurfFlatRegion( pGeomDB->GetGeoObj( nRegId)) ; + if ( pSfr == nullptr) + return false ; + // ne recupero il riferimento globale + Frame3d frSurf ; + pGeomDB->GetGlobFrame( nRegId, frSurf) ; + // ne approssimo il contorno con una polilinea che porto in globale + if ( ! pSfr->ApproxLoopWithLines( 0, 0, LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_STD, PL)) + return false ; + PL.ToGlob( frSurf) ; + return true ; +} \ No newline at end of file diff --git a/EXE_NstPartNesting.cpp b/EXE_NstPartNesting.cpp index a9e9660..5bac5a4 100644 --- a/EXE_NstPartNesting.cpp +++ b/EXE_NstPartNesting.cpp @@ -26,6 +26,7 @@ #include "/EgtDev/Include/EGkSimpleCDSurfFrMove.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EMkMachiningGeoConst.h" +#include "/EgtDev/Include/EGkIntervals.h" #include "/EgtDev/Include/EgtPointerOwner.h" using namespace std ; @@ -160,8 +161,6 @@ ExeCreateOutRegion( int nParentId, int nOutCrvId) if ( ! pOutCrv->IsClosed()) return false ; // la approssimo con linee - const double LIN_TOL_STD = 0.1 ; - const double ANG_TOL_STD_DEG = 15 ; PolyLine PL ; if ( ! pOutCrv->ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_STD, PL)) return false ; @@ -194,8 +193,10 @@ ExeCreateOutRegion( int nParentId, int nOutCrvId) if ( ! distPC.GetParamAtMinDistPoint( 0, dU, nFlag) || ! pCompo->ChangeStartPoint( dU)) return false ; - // accorcio inizio + // 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) ; @@ -203,11 +204,11 @@ ExeCreateOutRegion( int nParentId, int nOutCrvId) pCompo->GetEndPoint( ptEnd) ; PolyLine PL2 ; PL2.AddUPoint( 0, ptEnd) ; - PL2.AddUPoint( 1, Point3d( ptEnd.x, b3Box.GetMax().y, b3Box.GetMin().z)) ; + 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, ptStart.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()) ; @@ -263,8 +264,6 @@ ExeCreateDamagedRegion( int nParentId, int nDmgCrvId) if ( pCrv == nullptr || ! pCrv->IsClosed()) return false ; // la approssimo con linee - const double LIN_TOL_STD = 0.1 ; - const double ANG_TOL_STD_DEG = 15 ; PolyLine PL ; if ( ! pCrv->ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_STD, PL)) return GDB_ID_NULL ; @@ -345,6 +344,171 @@ UpdateToolOffset( IGeomDB* pGeomDB, const INTVECTOR& vIds, bool bReducedCut, dou 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 ; + 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 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 + const int BBF_PART_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ; + 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 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, 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) @@ -687,48 +851,88 @@ ExePackPartCluster( const INTVECTOR& vIds, bool bReducedCut, bool bBottomUp) } double dRegClDimX = b3RegCluster.GetMax().x - b3RegCluster.GetMin().x ; double dRegClDimY = b3RegCluster.GetMax().y - b3RegCluster.GetMin().y ; - - // Determino lo step per i tentativi di inserimento - const double STEP_STD = 50 ; - double dStepX = STEP_STD ; - double dStepY = STEP_STD ; - double dBoxDimX = b3Box.GetMax().x - b3Box.GetMin().x ; - double dRegCluDimX = b3RegCluster.GetMax().x - b3RegCluster.GetMin().x ; - if ( dBoxDimX - dRegCluDimX < 5 * STEP_STD) - dStepX = STEP_STD / 5 ; - double dBoxDimY = b3Box.GetMax().y - b3Box.GetMin().y ; - double dRegCluDimY = b3RegCluster.GetMax().y - b3RegCluster.GetMin().y ; - if ( dBoxDimY - dRegCluDimY < 5 * STEP_STD) - dStepY = STEP_STD / 5 ; - - // Procedo per tentativi - bool bFit = false ; Point3d ptOrig = b3RegCluster.GetMin() ; - Point3d ptLineStart = ( bBottomUp ? b3Box.GetMin() : b3Box.GetMax() - Vector3d(0, -dRegClDimY, 0)) ; - Point3d ptIns = ptLineStart ; - while ( true) { - // porto nella posizione di prova - Vector3d vtMove = ptIns - b3RegCluster.GetMin() ; - vtMove.z = 0 ; - for ( auto nId : vTrueIds) - pGeomDB->TranslateGlob( nId, vtMove) ; - b3Cluster.Translate( vtMove) ; - b3RegCluster.Translate( vtMove) ; - // verifico - if ( MyVerifyPartCluster( pGeomDB, vTrueIds, b3Cluster, bReducedCut)) { - bFit = true ; - break ; - } - // nuova posizione di inserimento (incrementando X) - ptIns += Vector3d( dStepX, 0, 0) ; - // se esco dal box torno all'inizio e incremento Y - if ( ! b3Box.EnclosesXY( ptIns + Vector3d( dRegClDimX, 0, 0))) { - ptLineStart += Vector3d( 0, ( bBottomUp ? dStepY : - dStepY), 0) ; - if ( ( ! b3Box.EnclosesXY( ptLineStart + Vector3d( 0, dRegClDimY, 0)))) - break ; - ptIns = ptLineStart ; + + // 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) { + // posizione di prova + Point3d ptIns = Point3d( dXmin + j * 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) {