Files
EgtExecutor/EXE_NstPartNesting.cpp
T
Riccardo Elitropi 1d9ecd9b78 EgtExecutor (Nst_SurfFr) :
- migliorata la collisione e l'allineamento per Regioni Piane.
2026-03-31 13:22:51 +02:00

2433 lines
96 KiB
C++

//----------------------------------------------------------------------------
// 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<ICurveComposite> 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<ICurveComposite> 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<ICurveComposite> 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<ICurveComposite> 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<ICurveComposite> 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<ICurveLine> 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
PtrOwner<ICurve>pLocCrv( 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<ISurfFlatRegion> 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<ISurfFlatRegion> 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<ISurfFlatRegion> 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<ICurve> 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 ;
}