Files
EgtExecutor/EXE_NstPartNesting.cpp
T
Dario Sassi 376695f29e EgtExecutor 1.6n12 :
- aggiunta gestione aree rovinate in nesting.
2016-03-07 09:56:52 +00:00

1460 lines
54 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/EGkSfrCreate.h"
#include "/EgtDev/Include/EGkSimpleCDSurfFrMove.h"
#include "/EgtDev/Include/EGkStringUtils3d.h"
#include "/EgtDev/Include/EMkMachiningGeoConst.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
using namespace std ;
//----------------------------------------------------------------------------
struct SCollInfoEx : public SCollInfo
{
int nIdM ; // identificativo della regione mobile
bool bIsCutM ; // flag di regione di pezzo o di taglio
int nIdF ; // identificativo della regione fissa
bool bIsCutF ; // flag di regione di pezzo o di taglio
// costruttori
SCollInfoEx() : SCollInfo(), nIdM( GDB_ID_NULL), bIsCutM( false),
nIdF( GDB_ID_NULL), bIsCutF( false) {}
SCollInfoEx( const SCollInfo& Sou) : SCollInfo( Sou), nIdM( GDB_ID_NULL), bIsCutM( false),
nIdF( GDB_ID_NULL), bIsCutF( false) {}
} ;
//----------------------------------------------------------------------------
static const double SPESS = 100 ;
//----------------------------------------------------------------------------
static bool MyMovePartCluster( IGeomDB* pGeomDB, const INTVECTOR& vTrueIds, BBox3d b3Cluster, bool bReducedCut, Vector3d& vtMove) ;
//----------------------------------------------------------------------------
static bool
AdjustClusterObjIds( IGeomDB* pGeomDB, const INTVECTOR& vIds, INTVECTOR& vTrueIds, BBox3d& b3Cluster)
{
if ( pGeomDB == nullptr)
return false ;
// Flag per calcolo box
const int BBF_PART_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ;
// Risolvo eventuali riferimenti a oggetti selezionati
vTrueIds.clear() ;
vTrueIds.reserve( vIds.size()) ;
b3Cluster.Reset() ;
for ( auto nId : vIds) {
int nTrueId = (( nId != GDB_ID_SEL) ? nId : pGeomDB->GetFirstSelectedObj()) ;
while ( nTrueId != GDB_ID_NULL) {
BBox3d b3Part ;
if ( pGeomDB->GetGlobalBBox( nTrueId, b3Part, BBF_PART_MY_FLAG)) {
// inserisco l'identificativo nel vettore dei validi
vTrueIds.push_back( nTrueId) ;
// aggiorno il box del cluster
b3Cluster.Add( b3Part) ;
}
// passo al successivo
nTrueId = (( nId != GDB_ID_SEL) ? GDB_ID_NULL : pGeomDB->GetNextSelectedObj()) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
ExeCreateOutRegion( int nParentId, double dXmin, double dYmin, double dXmax, double dYmax, double dZ)
{
IGeomDB* pGeomDB = GetCurrGeomDB() ;
VERIFY_GEOMDB( pGeomDB, false)
// Verifiche sui parametri
if ( dXmax < dXmin + EPS_SMALL ||
dYmax < dYmin + EPS_SMALL)
return false ;
// se già esiste, posso uscire
int nBoxId = pGeomDB->GetFirstNameInGroup( nParentId, NST_SHEET_OUTREG) ;
if ( nBoxId != GDB_ID_NULL)
return true ;
// creo polilinea attorno al box (avvolta a serpente)
const double DELTA = 1 ;
PolyLine PL ;
PL.AddUPoint( 0, Point3d( dXmin, dYmin, dZ)) ;
PL.AddUPoint( 1, Point3d( dXmin, dYmax, dZ)) ;
PL.AddUPoint( 2, Point3d( dXmax, dYmax, dZ)) ;
PL.AddUPoint( 3, Point3d( dXmax, dYmin + DELTA + 2 * EPS_SMALL, dZ)) ;
PL.AddUPoint( 4, Point3d( dXmax + SPESS, dYmin + DELTA + 2 * EPS_SMALL, dZ)) ;
PL.AddUPoint( 5, Point3d( dXmax + SPESS, dYmax + SPESS, dZ)) ;
PL.AddUPoint( 6, Point3d( dXmin - SPESS, dYmax + SPESS, dZ)) ;
PL.AddUPoint( 7, Point3d( dXmin - SPESS, dYmin - SPESS, dZ)) ;
PL.AddUPoint( 8, Point3d( dXmax + SPESS, dYmin - SPESS, dZ)) ;
PL.AddUPoint( 9, Point3d( dXmax + SPESS, dYmin + DELTA, dZ)) ;
PL.AddUPoint( 10, Point3d( dXmax, dYmin + DELTA, dZ)) ;
PL.AddUPoint( 11, Point3d( dXmax, dYmin, dZ)) ;
PL.Close() ;
// la converto in curva composita
PtrOwner<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->SetMaterial( nId, INVISIBLE) ;
return true ;
}
//----------------------------------------------------------------------------
bool
ExeCreateOutRegion( int nParentId, int nOutCrvId)
{
IGeomDB* pGeomDB = GetCurrGeomDB() ;
VERIFY_GEOMDB( pGeomDB, false)
// se già esiste, posso uscire
int nBoxId = pGeomDB->GetFirstNameInGroup( nParentId, NST_SHEET_OUTREG) ;
if ( nBoxId != GDB_ID_NULL)
return true ;
// recupero la curva
ICurve* pOutCrv = GetCurve( pGeomDB->GetGeoObj( nOutCrvId)) ;
if ( pOutCrv == nullptr)
return false ;
// verifico sia chiusa
if ( ! pOutCrv->IsClosed())
return false ;
// la approssimo con linee
const double LIN_TOL_STD = 0.1 ;
const double ANG_TOL_STD_DEG = 15 ;
PolyLine PL ;
if ( ! pOutCrv->ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_STD, PL))
return false ;
// porto la polilinea in globale
Frame3d frOutCrv ;
pGeomDB->GetGlobFrame( nOutCrvId, frOutCrv) ;
PL.ToGlob( frOutCrv) ;
// se antioraria la inverto
double dArea ;
if ( ! PL.GetAreaXY( dArea))
return false ;
if ( dArea > 0)
PL.Invert() ;
// la appiattisco sulla Z iniziale
Point3d ptP ;
PL.GetFirstPoint( ptP) ;
PL.Flatten( ptP.z) ;
// la converto in curva composita
PtrOwner<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(), *Get( pCompo)) ;
if ( ! distPC.GetParamAtMinDistPoint( 0, dU, nFlag) ||
! pCompo->ChangeStartPoint( dU))
return false ;
// accorcio inizio
pCompo->TrimStartAtLen( 5 * EPS_SMALL) ;
// creo curva della parte esterna
Point3d ptStart ;
pCompo->GetStartPoint( ptStart) ;
Point3d ptEnd ;
pCompo->GetEndPoint( ptEnd) ;
PolyLine PL2 ;
PL2.AddUPoint( 0, ptEnd) ;
PL2.AddUPoint( 1, Point3d( ptEnd.x, b3Box.GetMax().y, b3Box.GetMin().z)) ;
PL2.AddUPoint( 2, Point3d( b3Box.GetMin().x, b3Box.GetMax().y, b3Box.GetMin().z)) ;
PL2.AddUPoint( 3, b3Box.GetMin()) ;
PL2.AddUPoint( 4, Point3d( b3Box.GetMax().x, b3Box.GetMin().y, b3Box.GetMin().z)) ;
PL2.AddUPoint( 5, Point3d( b3Box.GetMax().x, ptStart.y, b3Box.GetMin().z)) ;
PL2.AddUPoint( 6, ptStart) ;
// la converto in curva composita
PtrOwner<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->SetMaterial( nId, INVISIBLE) ;
return true ;
}
//----------------------------------------------------------------------------
bool
ExeCreateDamagedRegion( int nParentId, int nDmgCrvId)
{
IGeomDB* pGeomDB = GetCurrGeomDB() ;
VERIFY_GEOMDB( pGeomDB, false)
// verifico se esiste già la regione associata
int nRegId = pGeomDB->GetFirstNameInGroup( nParentId, NST_DAMAGED_REG) ;
while ( nRegId != GDB_ID_NULL) {
// recupero l'indice della curva di origine
int nOriId ;
if ( pGeomDB->GetInfo( nRegId, CRV_ORIG, nOriId) && nOriId == nDmgCrvId)
return true ;
// passo alla regione successiva
nRegId = pGeomDB->GetNextName( nRegId, NST_DAMAGED_REG) ;
}
// recupero la curva e verifico sia chiusa
ICurve* pCrv = GetCurve( pGeomDB->GetGeoObj( nDmgCrvId)) ;
if ( pCrv == nullptr || ! pCrv->IsClosed())
return false ;
// la approssimo con linee
const double LIN_TOL_STD = 0.1 ;
const double ANG_TOL_STD_DEG = 15 ;
PolyLine PL ;
if ( ! pCrv->ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_STD, PL))
return GDB_ID_NULL ;
// porto la polilinea in globale
Frame3d frDmgCrv ;
pGeomDB->GetGlobFrame( nDmgCrvId, frDmgCrv) ;
PL.ToGlob( frDmgCrv) ;
// se oraria la inverto
double dArea ;
if ( ! PL.GetAreaXY( dArea))
return false ;
if ( dArea < 0)
PL.Invert() ;
// la appiattisco sulla Z iniziale
Point3d ptP ;
PL.GetFirstPoint( ptP) ;
PL.Flatten( ptP.z) ;
// la converto in curva composita
PtrOwner<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 ;
}
//----------------------------------------------------------------------------
static bool
MyVerifyPartCluster( IGeomDB* pGeomDB, const INTVECTOR& vTrueIds, const BBox3d& b3Cluster, bool bReducedCut)
{
// Flag per calcolo box
const int BBF_PART_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ;
// Determino le regioni dei pezzi
INTVECTOR vReg ;
INTVECTOR vCutReg ;
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 regioni dei tagli del pezzo
if ( ! GetFlatPartCutRegions( pGeomDB, nId, bReducedCut, vCutReg))
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) ;
// Verifico di essere nella regione valida
int nBoxId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_SHEET_OUTREG) ;
BBox3d b3Region ;
if ( nBoxId == GDB_ID_NULL || ! pGeomDB->GetGlobalBBox( nBoxId, b3Region))
return false ;
// box delle regioni dei pezzi rispetto al box dell'esterno
if ( ! b3Region.EnclosesXY( b3RegCluster))
return false ;
// regioni dei pezzi rispetto alla regione dell'esterno
for ( int nRegId : vReg) {
if ( ExeSurfFrChunkSimpleClassify( nRegId, 0, nBoxId, 0) != REGC_OUT)
return false ;
}
// Verifico con le eventuali aree danneggiate
// recupero le aree
INTVECTOR vDmgReg ;
int nId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_DAMAGED_REG) ;
while ( nId != GDB_ID_NULL) {
vDmgReg.emplace_back( nId) ;
nId = pGeomDB->GetNextName( nId, NST_DAMAGED_REG) ;
}
// regioni dei pezzi rispetto alle regioni delle aree danneggiate
for ( int nRegId : vReg) {
for ( int nDmgRegId : vDmgReg) {
if ( ExeSurfFrChunkSimpleClassify( nRegId, 0, nDmgRegId, 0) != REGC_OUT)
return false ;
}
}
// Determino le regioni di tutti gli altri pezzi compresi nella regione di interesse
INTVECTOR vOthReg ;
INTVECTOR vOthCutReg ;
int nId2 = ( bInRoot ? ExeGetFirstPart( true) : ExeGetFirstGroupInGroup( nGroupId)) ;
while ( nId2 != GDB_ID_NULL) {
if ( find( vTrueIds.begin(), vTrueIds.end(), nId2) == vTrueIds.end()) {
BBox3d b3Part2 ;
if ( pGeomDB->GetGlobalBBox( nId2, b3Part2, BBF_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 regioni dei tagli del pezzo
if ( ! GetFlatPartCutRegions( pGeomDB, nId2, bReducedCut, vOthCutReg))
return false ;
}
}
nId2 = ( bInRoot ? ExeGetNextPart( nId2, true) : ExeGetNextGroup( nId2)) ;
}
// Eseguo verifiche
// regioni dei pezzi
for ( int nRegId : vReg) {
// verifico con le regioni degli altri pezzi
for ( int nOthRegId : vOthReg) {
if ( ExeSurfFrChunkSimpleClassify( nRegId, 0, nOthRegId, 0) != REGC_OUT)
return false ;
}
// e con le regioni dei tagli degli altri pezzi
for ( int nOthCutRegId : vOthCutReg) {
if ( ExeSurfFrChunkSimpleClassify( nRegId, 0, nOthCutRegId, 0) != REGC_OUT)
return false ;
}
}
// regioni delle lavorazioni dei pezzi
for ( int nCutRegId : vCutReg) {
// le confronto con le regioni degli altri pezzi
for ( int nOthRegId : vOthReg) {
if ( ExeSurfFrChunkSimpleClassify( nCutRegId, 0, nOthRegId, 0) != REGC_OUT)
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
ExeVerifyPartCluster( const INTVECTOR& vIds, bool bReducedCut)
{
IGeomDB* pGeomDB = GetCurrGeomDB() ;
VERIFY_GEOMDB( pGeomDB, false)
// Risolvo identificativi a selezionati
INTVECTOR vTrueIds ;
BBox3d b3Cluster ;
AdjustClusterObjIds( pGeomDB, vIds, vTrueIds, b3Cluster) ;
if ( vTrueIds.empty())
return true ;
// Eseguo verifica
return MyVerifyPartCluster( pGeomDB, vTrueIds, b3Cluster, bReducedCut) ;
}
//----------------------------------------------------------------------------
static bool
MyPackPartCluster( const INTVECTOR& vTrueIds, bool bReducedCut,
double dXmin, double dYmin, double dXmax, double dYmax, bool bBottomUp)
{
IGeomDB* pGeomDB = GetCurrGeomDB() ;
VERIFY_GEOMDB( pGeomDB, false)
// Verifico se pezzi sotto la radice o pezzi in altro gruppo
int nGroupId = pGeomDB->GetParentId( vTrueIds[0]) ;
bool bInRoot = ( nGroupId == GDB_ID_ROOT) ;
// Box della regione di interesse
BBox3d b3Region( dXmin, dYmin, 0, dXmax, dYmax, 0) ;
// Flag per calcolo box
const int BBF_PART_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ;
// Determino tutti gli altri pezzi compresi nella regione di interesse
INTVECTOR vOtherIds ;
int nId2 = ( bInRoot ? ExeGetFirstPart( true) : ExeGetFirstGroupInGroup( nGroupId)) ;
while ( nId2 != GDB_ID_NULL) {
if ( find( vTrueIds.begin(), vTrueIds.end(), nId2) == vTrueIds.end()) {
BBox3d b3Part2 ;
if ( pGeomDB->GetGlobalBBox( nId2, b3Part2, BBF_PART_MY_FLAG) &&
b3Region.OverlapsXY( b3Part2)) {
vOtherIds.emplace_back( nId2) ;
}
}
nId2 = ( bInRoot ? ExeGetNextPart( nId2, true) : ExeGetNextGroup( nId2)) ;
}
// nascondo preview delle lavorazioni
SetPreviewStatus( pGeomDB, vTrueIds, false) ;
SetPreviewStatus( pGeomDB, vOtherIds, false) ;
// calcolo offset per ingombro lavorazioni
double dOffs = 0 ;
UpdateToolOffset( pGeomDB, vTrueIds, bReducedCut, dOffs) ;
UpdateToolOffset( pGeomDB, vOtherIds, bReducedCut, dOffs) ;
// eseguo primo movimento come box
bool bOk = ExePackBoxCluster( vTrueIds, dXmin, dYmin, dXmax, dYmax, dOffs, bBottomUp) ;
// ripristino preview delle lavorazioni
SetPreviewStatus( pGeomDB, vTrueIds, true) ;
SetPreviewStatus( pGeomDB, vOtherIds, true) ;
// verifica
bOk = bOk && ExeVerifyPartCluster( vTrueIds, bReducedCut) ;
// se inserimento di massima riuscito, provo a migliorare
if ( bOk) {
const double BIG_MOVE = 1000 ;
Vector3d vtMoveY = ( bBottomUp ? - 1 : 1) * BIG_MOVE * Y_AX ;
ExeMovePartCluster( vTrueIds, bReducedCut, vtMoveY) ;
Vector3d vtMoveX = - BIG_MOVE * X_AX ;
ExeMovePartCluster( vTrueIds, bReducedCut, vtMoveX) ;
}
return bOk ;
}
//----------------------------------------------------------------------------
bool
ExePackPartClusterInRectangle( const INTVECTOR& vIds, bool bReducedCut, bool bBottomUp)
{
IGeomDB* pGeomDB = GetCurrGeomDB() ;
VERIFY_GEOMDB( pGeomDB, false)
// Risolvo identificativi a selezionati
INTVECTOR vTrueIds ;
BBox3d b3Cluster ;
AdjustClusterObjIds( pGeomDB, vIds, vTrueIds, b3Cluster) ;
if ( vTrueIds.empty())
return true ;
// Recupero gruppo dei pezzi
int nGroupId = pGeomDB->GetParentId( vTrueIds[0]) ;
// Calcolo il box interno della regione valida
int nBoxId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_SHEET_OUTREG) ;
BBox3d b3Box ;
if ( ! pGeomDB->GetGlobalBBox( nBoxId, b3Box))
return false ;
b3Box.Expand( - SPESS, - SPESS, 0) ;
if ( b3Box.IsEmpty())
return false ;
double dXmin = b3Box.GetMin().x ;
double dYmin = b3Box.GetMin().y ;
double dXmax = b3Box.GetMax().x ;
double dYmax = b3Box.GetMax().y ;
// se con tagli ridotti
if ( bReducedCut) {
return MyPackPartCluster( vTrueIds, true, dXmin, dYmin, dXmax, dYmax, bBottomUp) ;
}
// altrimenti
else {
// provo con tagli ridotti
if ( ! MyPackPartCluster( vTrueIds, true, dXmin, dYmin, dXmax, dYmax, bBottomUp))
return false ;
// se posizione valida
if ( ExeVerifyPartCluster( vTrueIds, false)) {
return true ;
}
// altrimenti, riprovo con tagli standard
else {
return MyPackPartCluster( vTrueIds, false, dXmin, dYmin, dXmax, dYmax, bBottomUp) ;
}
}
}
//----------------------------------------------------------------------------
bool
ExePackPartCluster( const INTVECTOR& vIds, bool bReducedCut, bool bBottomUp)
{
IGeomDB* pGeomDB = GetCurrGeomDB() ;
VERIFY_GEOMDB( pGeomDB, false)
// Risolvo identificativi a selezionati
INTVECTOR vTrueIds ;
BBox3d b3Cluster ;
AdjustClusterObjIds( pGeomDB, vIds, vTrueIds, b3Cluster) ;
if ( vTrueIds.empty())
return true ;
// Recupero gruppo dei pezzi
int nGroupId = pGeomDB->GetParentId( vTrueIds[0]) ;
// Calcolo il box di ingombro interno della regione valida
int nBoxId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_SHEET_OUTREG) ;
BBox3d b3Box ;
if ( ! pGeomDB->GetGlobalBBox( nBoxId, b3Box))
return false ;
b3Box.Expand( - SPESS, - SPESS, 0) ;
if ( b3Box.IsEmpty())
return false ;
// Flag per calcolo box dei pezzi
const int BBF_PART_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ;
// Calcolo il box di ingombro delle regioni dei pezzi
BBox3d b3RegCluster ;
for ( int nId : vTrueIds) {
// recupero regione del pezzo
int nRegId = GetFlatPartRegion( pGeomDB, nId) ;
BBox3d b3Reg ;
if ( pGeomDB->GetGlobalBBox( nRegId, b3Reg, BBF_PART_MY_FLAG)) {
b3RegCluster.Add( b3Reg) ;
}
else
return false ;
}
double dRegClDimX = b3RegCluster.GetMax().x - b3RegCluster.GetMin().x ;
double dRegClDimY = b3RegCluster.GetMax().y - b3RegCluster.GetMin().y ;
// Determino lo step per i tentativi di inserimento
const double STEP_STD = 50 ;
double dStepX = STEP_STD ;
double dStepY = STEP_STD ;
double dBoxDimX = b3Box.GetMax().x - b3Box.GetMin().x ;
double dRegCluDimX = b3RegCluster.GetMax().x - b3RegCluster.GetMin().x ;
if ( dBoxDimX - dRegCluDimX < 5 * STEP_STD)
dStepX = STEP_STD / 5 ;
double dBoxDimY = b3Box.GetMax().y - b3Box.GetMin().y ;
double dRegCluDimY = b3RegCluster.GetMax().y - b3RegCluster.GetMin().y ;
if ( dBoxDimY - dRegCluDimY < 5 * STEP_STD)
dStepY = STEP_STD / 5 ;
// Procedo per tentativi
bool bFit = false ;
Point3d ptOrig = b3RegCluster.GetMin() ;
Point3d ptLineStart = ( bBottomUp ? b3Box.GetMin() : b3Box.GetMax() - Vector3d(0, -dRegClDimY, 0)) ;
Point3d ptIns = ptLineStart ;
while ( true) {
// porto nella posizione di prova
Vector3d vtMove = ptIns - b3RegCluster.GetMin() ;
vtMove.z = 0 ;
for ( auto nId : vTrueIds)
pGeomDB->TranslateGlob( nId, vtMove) ;
b3Cluster.Translate( vtMove) ;
b3RegCluster.Translate( vtMove) ;
// verifico
if ( MyVerifyPartCluster( pGeomDB, vTrueIds, b3Cluster, bReducedCut)) {
bFit = true ;
break ;
}
// nuova posizione di inserimento (incrementando X)
ptIns += Vector3d( dStepX, 0, 0) ;
// se esco dal box torno all'inizio e incremento Y
if ( ! b3Box.EnclosesXY( ptIns + Vector3d( dRegClDimX, 0, 0))) {
ptLineStart += Vector3d( 0, ( bBottomUp ? dStepY : - dStepY), 0) ;
if ( ( ! b3Box.EnclosesXY( ptLineStart + Vector3d( 0, dRegClDimY, 0))))
break ;
ptIns = ptLineStart ;
}
}
// Se inserimento non riuscito
if ( ! bFit) {
// riporto nella posizione originale
Vector3d vtMove = ptOrig - b3RegCluster.GetMin() ;
for ( auto nId : vTrueIds)
pGeomDB->TranslateGlob( nId, vtMove) ;
return false ;
}
// Inserimento riuscito, provo a migliorare
const double BIG_MOVE = 1000 ;
Vector3d vtMoveY = ( bBottomUp ? - 1 : 1) * BIG_MOVE * Y_AX ;
MyMovePartCluster( pGeomDB, vTrueIds, b3Cluster, bReducedCut, vtMoveY) ;
Vector3d vtMoveX = - BIG_MOVE * X_AX ;
MyMovePartCluster( pGeomDB, vTrueIds, b3Cluster, bReducedCut, vtMoveX) ;
return true ;
}
//----------------------------------------------------------------------------
static SCollInfoEx s_scInfo ;
static SCollInfoEx s_scInfoSaved ;
//----------------------------------------------------------------------------
static double
UpdateCollId( double dLen, double dPrevLen, int nId1, int nId2, bool bIsCut1, bool bIsCut2, SCollInfo scInfoCurr)
{
if ( abs( dLen - dPrevLen) < EPS_SMALL) {
if ( scInfoCurr.nType == SCI_PNT_LINE || scInfoCurr.nType == SCI_LINE_LINE) {
s_scInfo = scInfoCurr ;
s_scInfo.nIdM = nId1 ;
s_scInfo.nIdF = nId2 ;
s_scInfo.bIsCutM = bIsCut1 ;
s_scInfo.bIsCutF = bIsCut2 ;
}
return dPrevLen ;
}
else if ( dLen < dPrevLen) {
s_scInfo = scInfoCurr ;
s_scInfo.nIdM = nId1 ;
s_scInfo.nIdF = nId2 ;
s_scInfo.bIsCutM = bIsCut1 ;
s_scInfo.bIsCutF = bIsCut2 ;
return dLen ;
}
else
return dPrevLen ;
}
//----------------------------------------------------------------------------
static bool
MySurfFrMoveSimpleNoCollision( int nId1, int nId2, const Vector3d& vtDir, double& dLen, SCollInfo& scInfo)
{
IGeomDB* pGeomDB = GetCurrGeomDB() ;
VERIFY_GEOMDB( pGeomDB, GDB_ID_NULL)
// recupero la prima superficie FlatRegion
ISurfFlatRegion* pSfr1 = GetSurfFlatRegion( pGeomDB->GetGeoObj( nId1)) ;
bool bOk = ( pSfr1 != nullptr) ;
// recupero il riferimento della superficie
Frame3d frSurf1 ;
bOk = bOk && pGeomDB->GetGlobFrame( nId1, frSurf1) ;
// recupero la seconda superficie FlatRegion
const ISurfFlatRegion* pSfr2 = GetSurfFlatRegion( pGeomDB->GetGeoObj( nId2)) ;
bOk = bOk && ( pSfr2 != nullptr) ;
// recupero il riferimento della superficie
Frame3d frSurf2 ;
bOk = bOk && pGeomDB->GetGlobFrame( nId2, frSurf2) ;
// se riferimenti diversi, porto una copia della seconda nel riferimento della prima
const ISurfFlatRegion* pSfr2L = pSfr2 ;
PtrOwner<ISurfFlatRegion>pTmp ;
if ( ! AreSameFrame( frSurf1, frSurf2)) {
pTmp.Set( CloneSurfFlatRegion( pSfr2)) ;
bOk = bOk && ! IsNull( pTmp) ;
bOk = bOk && pTmp->LocToLoc( frSurf2, frSurf1) ;
pSfr2L = Get( pTmp) ;
}
// porto in locale alla prima superficie il versore di movimento
Vector3d vtDirL = vtDir ;
vtDirL.ToLoc( frSurf1) ;
// calcolo massima lunghezza di traslazione della prima regione senza semplice collisione con la seconda
SimpleCDSurfFrMove ScdSfrMove( *pSfr1, *pSfr2L) ;
bOk = bOk && ScdSfrMove.Translate( vtDirL, dLen) ;
if ( bOk) {
scInfo = ScdSfrMove.GetSCollInfo() ;
if ( scInfo.nType != SCI_NONE) {
scInfo.ptP1.ToGlob( frSurf1) ;
scInfo.vtDirM.ToGlob( frSurf1) ;
scInfo.vtDirF.ToGlob( frSurf1) ;
}
if ( scInfo.nType == SCI_LINE_LINE)
scInfo.ptP2.ToGlob( frSurf1) ;
}
return bOk ;
}
//----------------------------------------------------------------------------
static bool
MyMovePartCluster( IGeomDB* pGeomDB, const INTVECTOR& vTrueIds, BBox3d b3Cluster, bool bReducedCut, Vector3d& vtMove)
{
// Reset info di collisione
s_scInfo.nType = SCI_NONE ;
// Vettore movimento nel piano XY globale
Vector3d vtMoveXY( vtMove.x, vtMove.y, 0) ;
vtMove = V_NULL ;
if ( vtMoveXY.IsSmall())
return true ;
// Flag per calcolo box pezzi
const int BBF_PART_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ;
// Verifico se pezzi sotto la radice o pezzi in altro gruppo
int nGroupId = pGeomDB->GetParentId( vTrueIds[0]) ;
bool bInRoot = ( nGroupId == GDB_ID_ROOT) ;
// Recupero regione di interesse
int nBoxId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_SHEET_OUTREG) ;
BBox3d b3Region ;
if ( nBoxId == GDB_ID_NULL || ! pGeomDB->GetGlobalBBox( nBoxId, b3Region))
return false ;
// Recupero le eventuali aree danneggiate
INTVECTOR vDmgReg ;
int nId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_DAMAGED_REG) ;
while ( nId != GDB_ID_NULL) {
vDmgReg.emplace_back( nId) ;
nId = pGeomDB->GetNextName( nId, NST_DAMAGED_REG) ;
}
// Determino le regioni di tutti gli altri pezzi compresi nella regione di interesse
INTVECTOR vOthReg ;
INTVECTOR vOthCutReg ;
int nId2 = ( bInRoot ? ExeGetFirstPart( true) : ExeGetFirstGroupInGroup( nGroupId)) ;
while ( nId2 != GDB_ID_NULL) {
if ( find( vTrueIds.begin(), vTrueIds.end(), nId2) == vTrueIds.end()) {
BBox3d b3Part2 ;
if ( pGeomDB->GetGlobalBBox( nId2, b3Part2, BBF_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 regioni dei tagli del pezzo
if ( ! GetFlatPartCutRegions( pGeomDB, nId2, bReducedCut, vOthCutReg))
return false ;
}
}
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) {
// recupero regione del pezzo
int nRegId = GetFlatPartRegion( pGeomDB, nTrueId) ;
if ( nRegId == GDB_ID_NULL) {
bOk = false ;
break ;
}
// info di collisione correnti
SCollInfo scInfoCurr ;
// la confronto con il box
MySurfFrMoveSimpleNoCollision( nRegId, nBoxId, vtDir, dLen, scInfoCurr) ;
dPrevLen = UpdateCollId( dLen, dPrevLen, nRegId, nBoxId, false, false, scInfoCurr) ;
// la confronto con le aree danneggiate
for ( int nDmgRegId : vDmgReg) {
MySurfFrMoveSimpleNoCollision( nRegId, nDmgRegId, vtDir, dLen, scInfoCurr) ;
dPrevLen = UpdateCollId( dLen, dPrevLen, nRegId, nDmgRegId, false, false, scInfoCurr) ;
}
// la confronto con le regioni degli altri pezzi
for ( int nOthRegId : vOthReg) {
MySurfFrMoveSimpleNoCollision( nRegId, nOthRegId, vtDir, dLen, scInfoCurr) ;
dPrevLen = UpdateCollId( dLen, dPrevLen, nRegId, nOthRegId, false, false, scInfoCurr) ;
}
// e con le regioni dei tagli degli altri pezzi
for ( int nOthCutRegId : vOthCutReg) {
MySurfFrMoveSimpleNoCollision( nRegId, nOthCutRegId, vtDir, dLen, scInfoCurr) ;
dPrevLen = UpdateCollId( dLen, dPrevLen, nRegId, nOthCutRegId, false, true, scInfoCurr) ;
}
// recupero regioni di lavorazione del pezzo
INTVECTOR vCrId ;
if ( ! GetFlatPartCutRegions( pGeomDB, nTrueId, bReducedCut, vCrId)) {
bOk = false ;
break ;
}
// le confronto con le regioni degli altri pezzi
for ( int nCrId : vCrId) {
for ( int nOthRegId : vOthReg) {
MySurfFrMoveSimpleNoCollision( nCrId, nOthRegId, vtDir, dLen, scInfoCurr) ;
dPrevLen = UpdateCollId( dLen, dPrevLen, nCrId, nOthRegId, true, false, scInfoCurr) ;
}
}
}
// Se errore
if ( ! bOk)
return false ;
// Log per debug
if ( false) {
if ( s_scInfo.nType != SCI_NONE) {
string sOut = "Id1=" + ToString( s_scInfo.nIdM) + " Id2=" + ToString( s_scInfo.nIdF) + " Info type=" ;
switch ( s_scInfo.nType) {
case SCI_NONE : sOut += "NONE" ; break ;
case SCI_PNT_PNT : sOut += "PNT_PNT" ; break ;
case SCI_PNT_LINE : sOut += "PNT_LINE" ; break ;
case SCI_LINE_PNT : sOut += "LINE_PNT" ; break ;
case SCI_LINE_LINE : sOut += "LINE_LINE" ; break ;
}
sOut += " Crv1=" + ToString( s_scInfo.nCrvM) + " Crv2=" + ToString( s_scInfo.nCrvF) ;
sOut += " ptA=(" + ToString( s_scInfo.ptP1) + ")" ;
if ( s_scInfo.nType == SCI_LINE_LINE)
sOut += " ptB=(" + ToString( s_scInfo.ptP2) + ")" ;
if ( s_scInfo.nType == SCI_LINE_PNT || s_scInfo.nType == SCI_LINE_LINE)
sOut += " Dir1=(" + ToString( s_scInfo.vtDirM) + ")" ;
if ( s_scInfo.nType == SCI_PNT_LINE || s_scInfo.nType == SCI_LINE_LINE)
sOut += " Dir2=(" + ToString( s_scInfo.vtDirF) + ")" ;
LOG_INFO( GetLogger(), sOut.c_str()) ;
}
}
// Se movimento risultante nullo, non faccio alcunché
vtMoveXY = vtDir * dLen ;
if ( vtMoveXY.IsSmall())
return true ;
// Eseguo movimento dei pezzi del cluster
for ( auto nTrueId : vTrueIds)
pGeomDB->TranslateGlob( nTrueId, vtMoveXY) ;
ExeSetModified() ;
vtMove = vtMoveXY ;
return true ;
}
//----------------------------------------------------------------------------
bool
ExeMovePartCluster( const INTVECTOR& vIds, bool bReducedCut, Vector3d& vtMove)
{
IGeomDB* pGeomDB = GetCurrGeomDB() ;
VERIFY_GEOMDB( pGeomDB, false)
// Risolvo identificativi a selezionati
INTVECTOR vTrueIds ;
BBox3d b3Cluster ;
AdjustClusterObjIds( pGeomDB, vIds, vTrueIds, b3Cluster) ;
if ( vTrueIds.empty())
return true ;
// se con tagli ridotti
if ( bReducedCut) {
return MyMovePartCluster( pGeomDB, vTrueIds, b3Cluster, true, vtMove) ;
}
// altrimenti
else {
// provo con tagli ridotti
Vector3d vtM = vtMove ;
if ( ! MyMovePartCluster( pGeomDB, vTrueIds, b3Cluster, true, vtM))
return false ;
// se posizione valida
BBox3d b3CluMoved = b3Cluster ;
b3CluMoved.Translate( vtM) ;
if ( MyVerifyPartCluster( pGeomDB, vTrueIds, b3CluMoved, false)) {
vtMove = vtM ;
return true ;
}
// altrimenti, riprovo con tagli standard
else {
// annullo il movimento
for ( int nId : vTrueIds)
pGeomDB->TranslateGlob( nId, - vtM) ;
// riprovo
return MyMovePartCluster( pGeomDB, vTrueIds, b3Cluster, false, vtMove) ;
}
}
}
//----------------------------------------------------------------------------
bool
MyRotatePartCluster( IGeomDB* pGeomDB, const INTVECTOR& vTrueIds, BBox3d& b3Cluster, bool bReducedCut,
const Point3d& ptCen, double& dRotAngDeg)
{
// Reset info di collisione
s_scInfo.nType = SCI_NONE ;
// Rotazione nel piano XY globale
// Flag per calcolo box
const int BBF_PART_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ;
// Verifico se pezzi sotto la radice o pezzi in altro gruppo
int nGroupId = pGeomDB->GetParentId( vTrueIds[0]) ;
bool bInRoot = ( nGroupId == GDB_ID_ROOT) ;
// Recupero regione di interesse
int nBoxId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_SHEET_OUTREG) ;
BBox3d b3Region ;
if ( nBoxId == GDB_ID_NULL || ! pGeomDB->GetGlobalBBox( nBoxId, b3Region))
return false ;
// Recupero le eventuali aree danneggiate
INTVECTOR vDmgReg ;
int nId = pGeomDB->GetFirstNameInGroup( nGroupId, NST_DAMAGED_REG) ;
while ( nId != GDB_ID_NULL) {
vDmgReg.emplace_back( nId) ;
nId = pGeomDB->GetNextName( nId, NST_DAMAGED_REG) ;
}
// Determino le regioni di tutti gli altri pezzi compresi nella regione di interesse
INTVECTOR vReg ;
INTVECTOR vCutReg ;
int nId2 = ( bInRoot ? ExeGetFirstPart( true) : ExeGetFirstGroupInGroup( nGroupId)) ;
while ( nId2 != GDB_ID_NULL) {
if ( find( vTrueIds.begin(), vTrueIds.end(), nId2) == vTrueIds.end()) {
BBox3d b3Part2 ;
if ( pGeomDB->GetGlobalBBox( nId2, b3Part2, BBF_PART_MY_FLAG) &&
b3Region.OverlapsXY( b3Part2)) {
// recupero regione del pezzo
int nRegId = GetFlatPartRegion( pGeomDB, nId2) ;
if ( nRegId != GDB_ID_NULL)
vReg.emplace_back( nRegId) ;
else
return false ;
// recupero regioni dei tagli del pezzo
if ( ! GetFlatPartCutRegions( pGeomDB, nId2, bReducedCut, vCutReg))
return false ;
}
}
nId2 = ( bInRoot ? ExeGetNextPart( nId2, true) : ExeGetNextGroup( nId2)) ;
}
// Verifico rotazione dei pezzi del cluster rispetto al contorno, alle aree danneggiate e agli altri pezzi
bool bOk = true ;
double dAng = dRotAngDeg ;
for ( auto nTrueId : vTrueIds) {
// recupero regione del pezzo
int nRegId = GetFlatPartRegion( pGeomDB, nTrueId) ;
if ( nRegId == GDB_ID_NULL) {
bOk = false ;
break ;
}
// la confronto con il box
ExeSurfFrRotateSimpleNoCollision( nRegId, nBoxId, ptCen, dAng, RTY_GLOB) ;
// la confronto con le aree danneggiate
for ( int nDmgRegId : vDmgReg) {
ExeSurfFrRotateSimpleNoCollision( nRegId, nDmgRegId, ptCen, dAng, RTY_GLOB) ;
}
// la confronto con le regioni degli altri pezzi
for ( int nOthRegId : vReg) {
ExeSurfFrRotateSimpleNoCollision( nRegId, nOthRegId, ptCen, dAng, RTY_GLOB) ;
}
// e con le regioni dei tagli degli altri pezzi
for ( int nOthCutRegId : vCutReg) {
ExeSurfFrRotateSimpleNoCollision( nRegId, nOthCutRegId, ptCen, dAng, RTY_GLOB) ;
}
// recupero regioni di lavorazione del pezzo
INTVECTOR vCrId ;
if ( ! GetFlatPartCutRegions( pGeomDB, nTrueId, bReducedCut, vCrId)) {
bOk = false ;
break ;
}
// le confronto con le regioni degli altri pezzi
for ( int nCrId : vCrId) {
for ( int nOthRegId : vReg) {
ExeSurfFrRotateSimpleNoCollision( nCrId, nOthRegId, ptCen, dAng, RTY_GLOB) ;
}
}
}
// Se errore
if ( ! bOk)
return false ;
// Se movimento risultante nullo, non faccio alcunché
dRotAngDeg = dAng ;
if ( fabs( dAng) < EPS_ANG_SMALL)
return true ;
// Eseguo rotazione dei pezzi del cluster
for ( auto nTrueId : vTrueIds)
pGeomDB->RotateGlob( nTrueId, ptCen, Z_AX, dRotAngDeg) ;
ExeSetModified() ;
return true ;
}
//----------------------------------------------------------------------------
bool
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, 0)) ;
if ( IsNull( pCrv))
return false ;
double dU ;
if ( ! pCrv->GetParamAtPoint( ptCntL, dU, 10 * EPS_SMALL))
return false ;
if ( fabs( dU - round( dU)) < 100 * EPS_PARAM)
dU = round( dU) ;
Point3d ptPp ;
Vector3d vtTp ;
if ( ! pCrv->GetPointTang( dU, ICurve::FROM_MINUS, ptPp, vtTp))
return false ;
Point3d ptPn ;
Vector3d vtTn ;
if ( ! pCrv->GetPointTang( dU, ICurve::FROM_PLUS, ptPn, vtTn))
return false ;
// verifico che le tangenti siano diverse
if ( AreSameVectorApprox( vtTp, vtTn))
return false ;
// porto le tangenti nel riferimento globale e le confronto con la tangente dell'ostacolo
vtTp.ToGlob( frSfr) ;
vtTn.ToGlob( frSfr) ;
// log per debug
if ( false) {
string sOut = "vtTp=(" + ToString( vtTp) + ") vtTn=(" + ToString( vtTn) + ")" ;
LOG_INFO( GetLogger(), sOut.c_str()) ;
}
// ruoto dalla parte dell'angolo più piccolo (componente più grande)
double dRotAngDeg = ( abs( vtTp * s_scInfo.vtDirF) > abs( vtTn * s_scInfo.vtDirF)) ? 90 : - 90 ;
// provo a ruotare sul punto di collisione in senso orario
Point3d ptCen = s_scInfo.ptP1 ;
if ( ! ExeRotatePartCluster( vIds, bReducedCut, ptCen, dRotAngDeg))
return false ;
bMoved = ( fabs( dRotAngDeg) > EPS_ANG_SMALL) ;
return true ;
}
//----------------------------------------------------------------------------
bool
ExeMoveToSnapPointOnCollision( const INTVECTOR& vIds, bool bReducedCut, double dMaxMove, bool& bMoved)
{
IGeomDB* pGeomDB = GetCurrGeomDB() ;
VERIFY_GEOMDB( pGeomDB, false)
IMachMgr* pMachMgr = GetCurrMachMgr() ;
VERIFY_MACHMGR( pMachMgr, false)
// la collisione deve essere di tipo linea-linea o punto linea
if ( s_scInfo.nType != SCI_LINE_LINE && s_scInfo.nType != SCI_PNT_LINE)
return false ;
// cerco i due tagli in collisione
int nCutM = GDB_ID_NULL ;
int nGeoM = GDB_ID_NULL ;
Point3d ptStartM, ptEndM ;
Vector3d vtDirM ;
Frame3d frGeoM ;
int nCutF = GDB_ID_NULL ;
int nGeoF = GDB_ID_NULL ;
Point3d ptStartF, ptEndF ;
Vector3d vtDirF ;
Frame3d frGeoF ;
// se mobile è già un taglio, ne ricavo i dati
if ( s_scInfo.bIsCutM) {
nCutM = s_scInfo.nIdM ;
nGeoM = GetGeometryFromCut( pGeomDB, pMachMgr, nCutM) ;
ICurveLine* pLineM = GetCurveLine( pGeomDB->GetGeoObj( nGeoM)) ;
if ( nCutM == GDB_ID_NULL || nGeoM == GDB_ID_NULL ||
pLineM == nullptr || ! pGeomDB->GetGlobFrame( nGeoM, frGeoM))
return false ;
ptStartM = pLineM->GetStart() ;
ptStartM.ToGlob( frGeoM) ;
ptEndM = pLineM->GetEnd() ;
ptEndM.ToGlob( frGeoM) ;
vtDirM = ptEndM - ptStartM ;
vtDirM.Normalize() ;
}
// se fisso è già un taglio, ne ricavo i dati
if ( s_scInfo.bIsCutF) {
nCutF = s_scInfo.nIdF ;
nGeoF = GetGeometryFromCut( pGeomDB, pMachMgr, nCutF) ;
ICurveLine* pLineF = GetCurveLine( pGeomDB->GetGeoObj( nGeoF)) ;
if ( nCutF == GDB_ID_NULL || nGeoF == GDB_ID_NULL ||
pLineF == nullptr || ! pGeomDB->GetGlobFrame( nGeoF, frGeoF))
return false ;
ptStartF = pLineF->GetStart() ;
ptStartF.ToGlob( frGeoF) ;
ptEndF = pLineF->GetEnd() ;
ptEndF.ToGlob( frGeoF) ;
vtDirF = ptEndF - ptStartF ;
vtDirF.Normalize() ;
}
// se fisso pezzo e mobile taglio, cerco il taglio sul fisso
if ( ! s_scInfo.bIsCutF && s_scInfo.bIsCutM) {
// cerco il pezzo del fisso
int nPartId = GetFlatPartFromRegion( pGeomDB, s_scInfo.nIdF) ;
// recupero i suoi tagli
INTVECTOR vCuts ;
if ( ! GetFlatPartCutRegions( pGeomDB, nPartId, bReducedCut, vCuts))
return false ;
// cerco il taglio che si sovrappone a quello del mobile
BBox3d b3CutM ;
pGeomDB->GetGlobalBBox( nCutM, b3CutM) ;
for ( auto nId : vCuts) {
BBox3d b3Temp ;
pGeomDB->GetGlobalBBox( nId, b3Temp) ;
if ( b3Temp.OverlapsXY( b3CutM)) {
int nGeom = GetGeometryFromCut( pGeomDB, pMachMgr, nId) ;
ICurveLine* pLine = GetCurveLine( pGeomDB->GetGeoObj( nGeom)) ;
if ( nGeom == GDB_ID_NULL || pLine == nullptr || ! pGeomDB->GetGlobFrame( nGeom, frGeoF))
continue ;
ptStartF = pLine->GetStart() ;
ptStartF.ToGlob( frGeoF) ;
ptEndF = pLine->GetEnd() ;
ptEndF.ToGlob( frGeoF) ;
vtDirF = ptEndF - ptStartF ;
vtDirF.Normalize() ;
if ( AreOppositeVectorApprox( vtDirF, vtDirM)) {
nCutF = nId ;
nGeoF = nGeom ;
break ;
}
}
}
}
// se mobile pezzo e fisso taglio, cerco il taglio sul mobile
if ( ! s_scInfo.bIsCutM && s_scInfo.bIsCutF) {
// cerco il pezzo del mobile
int nPartId = GetFlatPartFromRegion( pGeomDB, s_scInfo.nIdM) ;
// recupero i suoi tagli
INTVECTOR vCuts ;
if ( ! GetFlatPartCutRegions( pGeomDB, nPartId, bReducedCut, vCuts))
return false ;
// cerco il taglio che si sovrappone a quello del fisso
BBox3d b3CutF ;
pGeomDB->GetGlobalBBox( nCutF, b3CutF) ;
for ( auto nId : vCuts) {
BBox3d b3Temp ;
pGeomDB->GetGlobalBBox( nId, b3Temp) ;
if ( b3Temp.OverlapsXY( b3CutF)) {
int nGeom = GetGeometryFromCut( pGeomDB, pMachMgr, nId) ;
ICurveLine* pLine = GetCurveLine( pGeomDB->GetGeoObj( nGeom)) ;
if ( nGeom == GDB_ID_NULL || pLine == nullptr || ! pGeomDB->GetGlobFrame( nGeom, frGeoM))
continue ;
ptStartM = pLine->GetStart() ;
ptStartM.ToGlob( frGeoM) ;
ptEndM = pLine->GetEnd() ;
ptEndM.ToGlob( frGeoM) ;
vtDirM = ptEndM - ptStartM ;
vtDirM.Normalize() ;
if ( AreOppositeVectorApprox( vtDirF, vtDirM)) {
nCutM = nId ;
nGeoM = nGeom ;
break ;
}
}
}
}
// se un taglio non definito, esco
if ( nCutM == GDB_ID_NULL || nCutF == GDB_ID_NULL)
return false ;
// linee adiacenti sul mobile
int nGeoMp = pGeomDB->GetPrev( nGeoM) ;
if ( nGeoMp == GDB_ID_NULL)
nGeoMp = pGeomDB->GetLastInGroup( pGeomDB->GetParentId( nGeoM)) ;
Vector3d vtDirMp ;
if ( pGeomDB->GetGeoType( nGeoMp) == CRV_LINE) {
ICurveLine* pLine = GetCurveLine( pGeomDB->GetGeoObj( nGeoMp)) ;
pLine->GetStartDir( vtDirMp) ;
vtDirMp.ToGlob( frGeoM) ;
}
int nGeoMn = pGeomDB->GetNext( nGeoM) ;
if ( nGeoMn == GDB_ID_NULL)
nGeoMn = pGeomDB->GetFirstInGroup( pGeomDB->GetParentId( nGeoM)) ;
Vector3d vtDirMn ;
if ( pGeomDB->GetGeoType( nGeoMn) == CRV_LINE) {
ICurveLine* pLine = GetCurveLine( pGeomDB->GetGeoObj( nGeoMn)) ;
pLine->GetStartDir( vtDirMn) ;
vtDirMn.ToGlob( frGeoM) ;
}
// linee adiacenti sul fisso
int nGeoFp = pGeomDB->GetPrev( nGeoF) ;
if ( nGeoFp == GDB_ID_NULL)
nGeoFp = pGeomDB->GetLastInGroup( pGeomDB->GetParentId( nGeoF)) ;
Vector3d vtDirFp ;
if ( pGeomDB->GetGeoType( nGeoFp) == CRV_LINE) {
ICurveLine* pLine = GetCurveLine( pGeomDB->GetGeoObj( nGeoFp)) ;
pLine->GetStartDir( vtDirFp) ;
vtDirFp.ToGlob( frGeoF) ;
}
int nGeoFn = pGeomDB->GetNext( nGeoF) ;
if ( nGeoFn == GDB_ID_NULL)
nGeoFn = pGeomDB->GetFirstInGroup( pGeomDB->GetParentId( nGeoF)) ;
Vector3d vtDirFn ;
if ( pGeomDB->GetGeoType( nGeoFn) == CRV_LINE) {
ICurveLine* pLine = GetCurveLine( pGeomDB->GetGeoObj( nGeoFn)) ;
pLine->GetStartDir( vtDirFn) ;
vtDirFn.ToGlob( frGeoF) ;
}
// verifico se possibile allineare i tagli precedente di mobile e successivo di fisso
double dMoveMp = 2 * dMaxMove ;
if ( ! vtDirMp.IsSmall() && ! vtDirFn.IsSmall()) {
if ( AreSameVectorApprox( vtDirMp, vtDirFn)) {
double dDenom = CrossXY( vtDirF, vtDirFn) ;
if ( abs( dDenom) > EPS_ZERO)
dMoveMp = CrossXY( ptEndF - ptStartM, vtDirFn) / dDenom ;
}
}
double dMoveMn = 2 * dMaxMove ;
if ( ! vtDirMn.IsSmall() && ! vtDirFp.IsSmall()) {
if ( AreSameVectorApprox( vtDirMn, vtDirFp)) {
double dDenom = CrossXY( vtDirF, vtDirFp) ;
if ( abs( dDenom) > EPS_ZERO)
dMoveMn = CrossXY( ptStartF - ptEndM, vtDirFp) / dDenom ;
}
}
// pareggio la parte più vicina, se almeno una sotto soglia
if ( abs( dMoveMp) < dMaxMove || abs( dMoveMn) < dMaxMove) {
// calcolo movimento necessario, se nullo già a posto
Vector3d vtMove = (( abs( dMoveMp) < abs( dMoveMn)) ? dMoveMp : dMoveMn) * vtDirF ;
if ( vtMove.IsSmall()) {
bMoved = false ;
return true ;
}
// eseguo movimento
if ( ExeMovePartCluster( vIds, bReducedCut, vtMove)) {
if ( ! vtMove.IsSmall()) {
bMoved = true ;
return true ;
}
}
}
// verifico se possibile allineare i tagli correnti
// calcolo ingombro dei tagli su direzione del taglio fisso
Frame3d frCutF ;
frCutF.Set( ptStartF, Z_AX, vtDirF) ;
BBox3d b3CutF ;
pGeomDB->GetRefBBox( nCutF, frCutF, b3CutF) ;
BBox3d b3CutM ;
pGeomDB->GetRefBBox( nCutM, frCutF, b3CutM) ;
double dStartDelta = b3CutF.GetMin().x - b3CutM.GetMin().x ;
double dEndDelta = b3CutF.GetMax().x - b3CutM.GetMax().x ;
// pareggio la parte più vicina, se sotto soglia
if ( abs( dStartDelta) > dMaxMove && abs( dEndDelta) > dMaxMove)
return false ;
Vector3d vtMove = (( abs( dStartDelta) < abs( dEndDelta)) ? dStartDelta : dEndDelta) * vtDirF ;
if ( ! ExeMovePartCluster( vIds, bReducedCut, vtMove))
return false ;
bMoved = ( ! vtMove.IsSmall()) ;
return true ;
}
//----------------------------------------------------------------------------
void
ExeSaveCollInfo( void)
{
s_scInfoSaved = s_scInfo ;
}
//----------------------------------------------------------------------------
void
ExeRestoreCollInfo( void)
{
s_scInfo = s_scInfoSaved ;
}
//-----------------------------------------------------------------------------
bool
ExeGetPartClusterCenterGlob( const INTVECTOR& vIds, Point3d& ptCen)
{
IGeomDB* pGeomDB = GetCurrGeomDB() ;
VERIFY_GEOMDB( pGeomDB, false)
// Risolvo eventuali riferimenti a oggetti selezionati
INTVECTOR vTrueIds ;
vTrueIds.reserve( vIds.size()) ;
for ( auto nId : vIds) {
int nTrueId = (( nId != GDB_ID_SEL) ? nId : pGeomDB->GetFirstSelectedObj()) ;
while ( nTrueId != GDB_ID_NULL) {
vTrueIds.push_back( nTrueId) ;
// passo al successivo
nTrueId = (( nId != GDB_ID_SEL) ? GDB_ID_NULL : pGeomDB->GetNextSelectedObj()) ;
}
}
// Se non sono rimasti oggetti, esco con errore
if ( vTrueIds.empty())
return false ;
// Recupero il centro della regione associata ad ogni oggetto
int nCount = 0 ;
ptCen = ORIG ;
for ( auto nTrueId : vTrueIds) {
// recupero regione del pezzo
int nRegId = GetFlatPartRegion( pGeomDB, nTrueId) ;
ISurfFlatRegion* pSfr = GetSurfFlatRegion( pGeomDB->GetGeoObj( nRegId)) ;
if ( pSfr == nullptr)
return false ;
// ne ricavo il centro
Point3d ptRcen ;
if ( ! pSfr->GetCentroid( ptRcen))
return false ;
// lo porto in globale
Frame3d frRef ;
if ( ! pGeomDB->GetGlobFrame( nRegId, frRef))
return false ;
ptRcen.ToGlob( frRef) ;
// lo sommo al centro complessivo
ptCen += ptRcen ;
++ nCount ;
}
// Verifico di aver trovato qualcosa
if ( nCount == 0)
return false ;
// Medio il centro
ptCen /= nCount ;
return true ;
}