Files
EgtExecutor/EXE_NstBoxNesting.cpp
T
Dario Sassi da88af65ed EgtExecutor 1.9l4 :
- fabs sostituito da abs.
2018-12-27 11:22:01 +00:00

497 lines
19 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2015-2016
//----------------------------------------------------------------------------
// File : EXE_NstBoxNesting.cpp Data : 11.08.16 Versione : 1.6t2
// Contenuto : Funzioni Nesting di Box per EXE.
//
//
//
// Modifiche : 20.09.15 DS Creazione modulo.
// 11.08.16 DS Corretto caso con pezzo più grande del pannello.
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "EXE.h"
#include "EXE_Macro.h"
#include "/EgtDev/Include/EXeExecutor.h"
#include "/EgtDev/Include/EXeConst.h"
#include <functional>
using namespace std ;
//----------------------------------------------------------------------------
static bool
VerifyBox( const BBox3d& b3Test, const Vector3d& vtMove, const BOXVECTOR& vb3OnPlace)
{
BBox3d b3Moved = b3Test ;
b3Moved.Translate( vtMove) ;
for ( const auto& Box : vb3OnPlace) {
if ( b3Moved.OverlapsXY( Box))
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
static bool
VerifyBoxAndMoveOnX( const BBox3d& b3Test, const Vector3d& vtMove, const BOXVECTOR& vb3OnPlace,
double dXmax, double& dExtraMove)
{
// verifica iniziale
BBox3d b3Moved = b3Test ;
b3Moved.Translate( vtMove) ;
dExtraMove = 0 ;
if ( b3Moved.GetMax().x > dXmax + EPS_SMALL)
return false ;
// verifico con altri pezzi
for ( const auto& Box : vb3OnPlace) {
if ( b3Moved.OverlapsXY( Box)) {
double dNewMove = Box.GetMax().x - b3Moved.GetMin().x + 2 * EPS_SMALL ;
dExtraMove += dNewMove ;
b3Moved.Translate( Vector3d( dNewMove, 0, 0)) ;
if ( b3Moved.GetMax().x > dXmax + EPS_SMALL)
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
ExePackBox( int nId, double dXmin, double dYmin, double dXmax, double dYmax, double dOffs, bool bBottomUp)
{
IGeomDB* pGeomDB = GetCurrGeomDB() ;
VERIFY_GEOMDB( pGeomDB, false)
// verifiche sui parametri
if ( dOffs < - EPS_ZERO ||
dXmax < dXmin + 2 * dOffs + EPS_SMALL ||
dYmax < dYmin + 2 * dOffs + EPS_SMALL)
return false ;
// Determino il box del pezzo
BBox3d b3Part ;
if ( ! pGeomDB->GetGlobalBBox( nId, b3Part, BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM))
return false ;
double dLarPz = b3Part.GetMax().x - b3Part.GetMin().x ;
Point3d ptPart = ( bBottomUp ? b3Part.GetMin() : Point3d( b3Part.GetMin().x, b3Part.GetMax().y, b3Part.GetMin().z)) ;
b3Part.Expand( dOffs - 2 * EPS_SMALL, dOffs - 2 * EPS_SMALL, 0) ;
// Box della regione di interesse
BBox3d b3Region( dXmin, dYmin, 0, dXmax, dYmax, 0) ;
// Verifico se pezzo sotto la radice o pezzo in altro gruppo
int nGroupId = pGeomDB->GetParentId( nId) ;
bool bInRoot = ( nGroupId == GDB_ID_ROOT) ;
// Determino il box di tutti gli altri pezzi compresi nella regione di interesse
BOXVECTOR vBox ;
int nId2 = ( bInRoot ? ExeGetFirstPart( true) : ExeGetFirstGroupInGroup( nGroupId)) ;
while ( nId2 != GDB_ID_NULL) {
if ( nId2 != nId) {
BBox3d b3Part2 ;
if ( pGeomDB->GetGlobalBBox( nId2, b3Part2, BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM) &&
b3Region.OverlapsXY( b3Part2))
vBox.emplace_back( b3Part2) ;
}
nId2 = ( bInRoot ? ExeGetNextPart( nId2, true) : ExeGetNextGroup( nId2)) ;
}
// Ordino i box dei pezzi secondo la X crescente
sort( vBox.begin(), vBox.end(), []( const BBox3d& a, const BBox3d& b)
{ return a.GetMin().x < b.GetMin().x ; }) ;
// Determino le Y interessanti
DBLVECTOR vY ;
if ( bBottomUp) {
// Ymin del rettangolo e Ymax dei vari box
vY.push_back( dYmin) ;
for ( auto& Box : vBox) {
double dY = Box.GetMax().y + dOffs ;
if ( dY > dYmin && dY < dYmax)
vY.push_back( dY) ;
}
// Le ordino in senso crescente
sort( vY.begin(), vY.end()) ;
}
else {
// Ymax del rettangolo e Ymin dei vari box
vY.push_back( dYmax) ;
for ( auto& Box : vBox) {
double dY = Box.GetMin().y - dOffs ;
if ( dY > dYmin && dY < dYmax)
vY.push_back( dY) ;
}
// Le ordino in senso decrescente
sort( vY.begin(), vY.end(), greater<double>()) ;
}
// Elimino i valori coincidenti
vY.erase( unique( vY.begin(), vY.end(), [](double a, double b){ return abs( a - b) < EPS_SMALL ;}), vY.end()) ;
// Testo le Y in ordine opportuno
bool bFound = false ;
double dXok = INFINITO, dYok = INFINITO ;
for ( auto dY : vY) {
double dExtraMove ;
if ( VerifyBoxAndMoveOnX( b3Part, Point3d( dXmin, dY, 0) - ptPart, vBox, dXmax + dOffs, dExtraMove)) {
dXok = dXmin + dExtraMove ;
dYok = dY ;
bFound = true ;
break ;
}
}
if ( ! bFound)
return false ;
// Verifico che il pezzo nella nuova posizione non esca da Ymax o Y min
if ( bBottomUp && b3Part.GetMax().y - ptPart.y + dYok > dYmax + dOffs + EPS_SMALL)
return false ;
else if ( ! bBottomUp && b3Part.GetMin().y - ptPart.y + dYok < dYmin - dOffs - EPS_SMALL)
return false ;
// Porto il pezzo nella giusta posizione
if ( ! pGeomDB->TranslateGlob( nId, Point3d( dXok, dYok, ptPart.z) - ptPart))
return false ;
ExeSetModified() ;
return true ;
}
//----------------------------------------------------------------------------
bool
ExePackBoxCluster( const INTVECTOR& vIds, double dXmin, double dYmin, double dXmax, double dYmax,
double dOffs, bool bBottomUp)
{
IGeomDB* pGeomDB = GetCurrGeomDB() ;
VERIFY_GEOMDB( pGeomDB, false)
// verifiche sui parametri
if ( dOffs < - EPS_ZERO ||
dXmax < dXmin + 2 * dOffs + EPS_SMALL ||
dYmax < dYmin + 2 * dOffs + EPS_SMALL)
return false ;
// Risolvo eventuali riferimenti a oggetti selezionati
INTVECTOR vTrueIds ;
vTrueIds.reserve( vIds.size()) ;
for ( auto nId : vIds) {
int nTrueId = (( nId != GDB_ID_SEL) ? nId : pGeomDB->GetFirstSelectedObj()) ;
while ( nTrueId != GDB_ID_NULL) {
vTrueIds.push_back( nTrueId) ;
// passo al successivo
nTrueId = (( nId != GDB_ID_SEL) ? GDB_ID_NULL : pGeomDB->GetNextSelectedObj()) ;
}
}
// Se non sono rimasti oggetti, esco con successo
if ( vTrueIds.empty())
return true ;
// Flag per calcolo box
const int BBF_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ;
// Determino il box del cluster (insieme di pezzi)
BBox3d b3Cluster ;
for ( auto nTrueId : vTrueIds) {
BBox3d b3Part ;
if ( ! pGeomDB->GetGlobalBBox( nTrueId, b3Part, BBF_MY_FLAG))
return false ;
b3Cluster.Add( b3Part) ;
}
double dLarCl = b3Cluster.GetMax().x - b3Cluster.GetMin().x ;
Point3d ptCluster = ( bBottomUp ? b3Cluster.GetMin() : Point3d( b3Cluster.GetMin().x, b3Cluster.GetMax().y, b3Cluster.GetMin().z)) ;
b3Cluster.Expand( dOffs - 2 * EPS_SMALL, dOffs - 2 * EPS_SMALL, 0) ;
// Box della regione di interesse
BBox3d b3Region( dXmin, dYmin, 0, dXmax, dYmax, 0) ;
// Verifico se pezzi sotto la radice o pezzi in altro gruppo
int nGroupId = pGeomDB->GetParentId( vTrueIds[0]) ;
bool bInRoot = ( nGroupId == GDB_ID_ROOT) ;
// Determino il box di tutti gli altri pezzi compresi nella regione di interesse
BOXVECTOR vBox ;
int nId2 = ( bInRoot ? ExeGetFirstPart( true) : ExeGetFirstGroupInGroup( nGroupId)) ;
while ( nId2 != GDB_ID_NULL) {
if ( find( vTrueIds.begin(), vTrueIds.end(), nId2) == vTrueIds.end()) {
BBox3d b3Part2 ;
if ( pGeomDB->GetGlobalBBox( nId2, b3Part2, BBF_MY_FLAG) &&
b3Region.OverlapsXY( b3Part2))
vBox.emplace_back( b3Part2) ;
}
nId2 = ( bInRoot ? ExeGetNextPart( nId2, true) : ExeGetNextGroup( nId2)) ;
}
// Ordino i box dei pezzi secondo la X crescente
sort( vBox.begin(), vBox.end(), []( const BBox3d& a, const BBox3d& b)
{ return a.GetMin().x < b.GetMin().x ; }) ;
// Determino le Y interessanti
DBLVECTOR vY ;
if ( bBottomUp) {
// Ymin del rettangolo e Ymax dei vari box
vY.push_back( dYmin) ;
for ( auto& Box : vBox) {
double dY = Box.GetMax().y + dOffs ;
if ( dY > dYmin && dY < dYmax)
vY.push_back( dY) ;
}
// Le ordino in senso crescente
sort( vY.begin(), vY.end()) ;
}
else {
// Ymax del rettangolo e Ymin dei vari box
vY.push_back( dYmax) ;
for ( auto& Box : vBox) {
double dY = Box.GetMin().y - dOffs ;
if ( dY > dYmin && dY < dYmax)
vY.push_back( dY) ;
}
// Le ordino in senso decrescente
sort( vY.begin(), vY.end(), greater<double>()) ;
}
// Elimino i valori coincidenti
vY.erase( unique( vY.begin(), vY.end(), [](double a, double b){ return abs( a - b) < EPS_SMALL ;}), vY.end()) ;
// Testo le Y in ordine opportuno
bool bFound = false ;
double dXok = INFINITO, dYok = INFINITO ;
for ( auto dY : vY) {
double dExtraMove ;
if ( VerifyBoxAndMoveOnX( b3Cluster, Point3d( dXmin, dY, 0) - ptCluster, vBox, dXmax + dOffs, dExtraMove)) {
dXok = dXmin + dExtraMove ;
dYok = dY ;
bFound = true ;
break ;
}
}
if ( ! bFound)
return false ;
// Verifico che il cluster nella nuova posizione non esca da Ymax
if ( bBottomUp && b3Cluster.GetMax().y - ptCluster.y + dYok > dYmax + dOffs + EPS_SMALL)
return false ;
else if ( ! bBottomUp && b3Cluster.GetMin().y - ptCluster.y + dYok < dYmin - dOffs - EPS_SMALL)
return false ;
// Porto il cluster nella giusta posizione
for ( auto nTrueId : vTrueIds) {
pGeomDB->TranslateGlob( nTrueId, Point3d( dXok, dYok, ptCluster.z) - ptCluster) ;
}
ExeSetModified() ;
return true ;
}
//-----------------------------------------------------------------------------
bool
ExeGetClusterBBoxGlob( const INTVECTOR& vIds, BBox3d& b3Box)
{
IGeomDB* pGeomDB = GetCurrGeomDB() ;
VERIFY_GEOMDB( pGeomDB, false)
// Flag per calcolo box
const int BBF_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ;
// Determino il box del cluster (insieme di pezzi)
b3Box.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_MY_FLAG))
return false ;
b3Box.Add( b3Part) ;
// passo al successivo
nTrueId = (( nId != GDB_ID_SEL) ? GDB_ID_NULL : pGeomDB->GetNextSelectedObj()) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
static void
VerifyBoxMoveInBox( const BBox3d& b3Region, const BBox3d& b3Box, Vector3d& vtMoveXY)
{
BBox3d b3Moved = b3Box ;
b3Moved.Translate( vtMoveXY) ;
if ( vtMoveXY.x < - EPS_SMALL) {
double dDeltaX = b3Moved.GetMin().x - b3Region.GetMin().x ;
if ( dDeltaX < - EPS_SMALL) {
double dDeltaY = dDeltaX * vtMoveXY.y / vtMoveXY.x ;
Vector3d vtCorr( - dDeltaX, - dDeltaY, 0) ;
vtMoveXY += vtCorr ;
b3Moved.Translate( vtCorr) ;
}
}
if ( vtMoveXY.y < - EPS_SMALL) {
double dDeltaY = b3Moved.GetMin().y - b3Region.GetMin().y ;
if ( dDeltaY < - EPS_SMALL) {
double dDeltaX = dDeltaY * vtMoveXY.x / vtMoveXY.y ;
Vector3d vtCorr( - dDeltaX, - dDeltaY, 0) ;
vtMoveXY += vtCorr ;
b3Moved.Translate( vtCorr) ;
}
}
if ( vtMoveXY.x > EPS_SMALL) {
double dDeltaX = b3Moved.GetMax().x - b3Region.GetMax().x ;
if ( dDeltaX > EPS_SMALL) {
double dDeltaY = dDeltaX * vtMoveXY.y / vtMoveXY.x ;
Vector3d vtCorr( - dDeltaX, - dDeltaY, 0) ;
vtMoveXY += vtCorr ;
b3Moved.Translate( vtCorr) ;
}
}
if ( vtMoveXY.y > EPS_SMALL) {
double dDeltaY = b3Moved.GetMax().y - b3Region.GetMax().y ;
if ( dDeltaY > EPS_SMALL) {
double dDeltaX = dDeltaY * vtMoveXY.x / vtMoveXY.y ;
Vector3d vtCorr( - dDeltaX, - dDeltaY, 0) ;
vtMoveXY += vtCorr ;
b3Moved.Translate( vtCorr) ;
}
}
}
//----------------------------------------------------------------------------
static void
VerifyBoxMoveOutBox( const BBox3d& b3Other, const BBox3d& b3Box, Vector3d& vtMoveXY)
{
// box spostato
BBox3d b3Moved = b3Box ;
b3Moved.Translate( vtMoveXY) ;
// verifico se collidono in modo significativo
BBox3d b3Int ;
if ( ! b3Other.FindIntersectionXY( b3Moved, b3Int) || b3Int.IsEpsilonXY( 2 * EPS_SMALL))
return ;
// calcolo le possibili riduzioni di movimento
Vector3d vtCorr[4] ;
vtCorr[0] = - vtMoveXY ;
if ( vtMoveXY.x < - EPS_SMALL) {
double dDeltaX = b3Moved.GetMin().x - b3Other.GetMax().x ;
if ( dDeltaX < EPS_SMALL) {
double dDeltaY = dDeltaX * vtMoveXY.y / vtMoveXY.x ;
vtCorr[0].Set( - dDeltaX, - dDeltaY, 0) ;
}
}
vtCorr[1] = - vtMoveXY ;
if ( vtMoveXY.y < - EPS_SMALL) {
double dDeltaY = b3Moved.GetMin().y - b3Other.GetMax().y ;
if ( dDeltaY < EPS_SMALL) {
double dDeltaX = dDeltaY * vtMoveXY.x / vtMoveXY.y ;
vtCorr[1].Set( - dDeltaX, - dDeltaY, 0) ;
}
}
vtCorr[2] = - vtMoveXY ;
if ( vtMoveXY.x > EPS_SMALL) {
double dDeltaX = b3Moved.GetMax().x - b3Other.GetMin().x ;
if ( dDeltaX > - EPS_SMALL) {
double dDeltaY = dDeltaX * vtMoveXY.y / vtMoveXY.x ;
vtCorr[2].Set( - dDeltaX, - dDeltaY, 0) ;
}
}
vtCorr[3] = - vtMoveXY ;
if ( vtMoveXY.y > EPS_SMALL) {
double dDeltaY = b3Moved.GetMax().y - b3Other.GetMin().y ;
if ( dDeltaY > - EPS_SMALL) {
double dDeltaX = dDeltaY * vtMoveXY.x / vtMoveXY.y ;
vtCorr[3].Set( - dDeltaX, - dDeltaY, 0) ;
}
}
// prendo la riduzione più piccola in modulo
Vector3d vtMinCorr = vtCorr[0] ;
for ( int i = 1 ; i < 4 ; ++ i) {
if ( vtCorr[i].SqLenXY() < vtMinCorr.SqLenXY())
vtMinCorr = vtCorr[i] ;
}
vtMoveXY += vtMinCorr ;
}
//----------------------------------------------------------------------------
bool
ExeMoveBoxCluster( const INTVECTOR& vIds, Vector3d& vtMove,
double dXmin, double dYmin, double dXmax, double dYmax, double dOffs)
{
IGeomDB* pGeomDB = GetCurrGeomDB() ;
VERIFY_GEOMDB( pGeomDB, false)
// Verifiche sui parametri
if ( dOffs < - EPS_ZERO ||
dXmax < dXmin + 2 * dOffs + EPS_SMALL ||
dYmax < dYmin + 2 * dOffs + EPS_SMALL)
return false ;
// Vettore movimento nel solo piano XY
Vector3d vtMoveXY( vtMove.x, vtMove.y, 0) ;
vtMove = V_NULL ;
if ( vtMoveXY.IsSmall())
return true ;
// Box della regione di interesse
BBox3d b3Region( dXmin, dYmin, 0, dXmax, dYmax, 0) ;
// Flag per calcolo box
const int BBF_MY_FLAG = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_DIM ;
// Risolvo eventuali riferimenti a oggetti selezionati, escludo oggetti non completamente nella regione e
// calcolo il box del cluster risultante
INTVECTOR vTrueIds ;
vTrueIds.reserve( vIds.size()) ;
BBox3d b3Cluster ;
for ( auto nId : vIds) {
int nTrueId = (( nId != GDB_ID_SEL) ? nId : pGeomDB->GetFirstSelectedObj()) ;
while ( nTrueId != GDB_ID_NULL) {
BBox3d b3Part ;
if ( pGeomDB->GetGlobalBBox( nTrueId, b3Part, BBF_MY_FLAG) &&
b3Region.EnclosesXY( b3Part)) {
// inserisco l'identificativo nel vettore dei validi
vTrueIds.push_back( nTrueId) ;
// aggiorno il box del cluster
b3Cluster.Add( b3Part) ;
}
// passo al successivo
nTrueId = (( nId != GDB_ID_SEL) ? GDB_ID_NULL : pGeomDB->GetNextSelectedObj()) ;
}
}
// Se non sono rimasti oggetti, esco con successo
if ( vTrueIds.empty())
return true ;
// Verifico se pezzi sotto la radice o pezzi in altro gruppo
int nGroupId = pGeomDB->GetParentId( vTrueIds[0]) ;
bool bInRoot = ( nGroupId == GDB_ID_ROOT) ;
// Determino i box di tutti gli altri pezzi compresi nella regione di interesse
BOXVECTOR vBox ;
int nId2 = ( bInRoot ? ExeGetFirstPart( true) : ExeGetFirstGroupInGroup( nGroupId)) ;
while ( nId2 != GDB_ID_NULL) {
if ( find( vTrueIds.begin(), vTrueIds.end(), nId2) == vTrueIds.end()) {
BBox3d b3Part2 ;
if ( pGeomDB->GetGlobalBBox( nId2, b3Part2, BBF_MY_FLAG) &&
b3Region.OverlapsXY( b3Part2))
vBox.emplace_back( b3Part2) ;
}
nId2 = ( bInRoot ? ExeGetNextPart( nId2, true) : ExeGetNextGroup( nId2)) ;
}
// Ordino questi box in senso contrario al movimento
if ( abs( vtMoveXY.x) >= abs( vtMoveXY.y)) {
if ( vtMoveXY.x > 0)
// movimento prevalente in X+ -> ordine secondo X decrescente
sort( vBox.begin(), vBox.end(), []( const BBox3d& a, const BBox3d& b)
{ return a.GetMin().x > b.GetMin().x ; }) ;
else
// movimento prevalente in X- -> ordine secondo X crescente
sort( vBox.begin(), vBox.end(), []( const BBox3d& a, const BBox3d& b)
{ return a.GetMin().x < b.GetMin().x ; }) ;
}
else {
if ( vtMoveXY.y > 0)
// movimento prevalente in Y+ -> ordine secondo Y decrescente
sort( vBox.begin(), vBox.end(), []( const BBox3d& a, const BBox3d& b)
{ return a.GetMin().y > b.GetMin().y ; }) ;
else
// movimento prevalente in Y- -> ordine secondo Y crescente
sort( vBox.begin(), vBox.end(), []( const BBox3d& a, const BBox3d& b)
{ return a.GetMin().y < b.GetMin().y ; }) ;
}
// Verifico movimento del box del cluster rispetto alla regione
VerifyBoxMoveInBox( b3Region, b3Cluster, vtMoveXY) ;
// Verifico movimento dei pezzi del cluster rispetto agli altri pezzi
for ( auto nTrueId : vTrueIds) {
// recupero box del pezzo, lo espando della minima distanza e verifico il mosso
BBox3d b3Part ;
pGeomDB->GetGlobalBBox( nTrueId, b3Part, BBF_MY_FLAG) ;
b3Part.Expand( dOffs, dOffs, 0) ;
// lo confronto con il box degli altri pezzi e se necessario riduco il movimento
for ( const auto& Box : vBox) {
VerifyBoxMoveOutBox( Box, b3Part, vtMoveXY) ;
}
}
// Se movimento risultante nullo, non faccio alcunché
if ( vtMoveXY.IsSmall())
return true ;
// Eseguo movimento dei pezzi del cluster
for ( auto nTrueId : vTrueIds)
pGeomDB->TranslateGlob( nTrueId, vtMoveXY) ;
ExeSetModified() ;
vtMove = vtMoveXY ;
return true ;
}