2ca704432a
- aggiunto text dimensioni a FlatParts.
957 lines
37 KiB
C++
957 lines
37 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2015-2015
|
|
//----------------------------------------------------------------------------
|
|
// File : EXE_Nesting.cpp Data : 20.09.14 Versione : 1.6e1
|
|
// Contenuto : Funzioni Nesting per EXE.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 20.09.14 DS Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
#include "stdafx.h"
|
|
#include "EXE.h"
|
|
#include "EXE_Macro.h"
|
|
#include "/EgtDev/Include/EXeExecutor.h"
|
|
#include "/EgtDev/Include/EXeConst.h"
|
|
#include "/EgtDev/Include/EGkCurveComposite.h"
|
|
#include "/EgtDev/Include/EGkIntersCurves.h"
|
|
#include "/EgtDev/Include/EGkSfrCreate.h"
|
|
#include "/EgtDev/Include/EGkExtText.h"
|
|
#include "/EgtDev/Include/EGkGdbIterator.h"
|
|
#include "/EgtDev/Include/EGkIntervals.h"
|
|
#include "/EgtDev/Include/EgtPointerOwner.h"
|
|
#include <functional>
|
|
|
|
using namespace std ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
ApproxCurveIfNeeded( IGdbIterator* pEnt)
|
|
{
|
|
const double LIN_TOL_STD = 0.25 ;
|
|
const double ANG_TOL_STD_DEG = 15 ;
|
|
const double LIN_FEA_STD = 20 ;
|
|
// deve essere una curva
|
|
int nGeoType = pEnt->GetGeoType() ;
|
|
if ( (nGeoType & GEO_CURVE) == 0)
|
|
return false ;
|
|
// verifico se da approssimare
|
|
if ( nGeoType == CRV_LINE || nGeoType == CRV_ARC)
|
|
return true ;
|
|
else if ( nGeoType == CRV_COMPO) {
|
|
ICurveComposite* pCrvCo = GetCurveComposite( pEnt->GetGeoObj()) ;
|
|
double dLen ;
|
|
pCrvCo->GetLength( dLen) ;
|
|
int nCrvs = pCrvCo->GetCurveCount() ;
|
|
if ( nCrvs <= 5 && dLen > nCrvs * LIN_FEA_STD)
|
|
return true ;
|
|
}
|
|
// esecuzione dell'approssimazione
|
|
ICurve* pCrv = GetCurve( pEnt->GetGeoObj()) ;
|
|
PtrOwner<ICurveComposite> pCC( CreateCurveComposite()) ;
|
|
PolyArc PA ;
|
|
bool bOk = pCrv->ApproxWithArcsEx( LIN_TOL_STD, ANG_TOL_STD_DEG, LIN_FEA_STD, PA) && pCC->FromPolyArc( PA) ;
|
|
bOk = bOk && pEnt->GetGDB()->ReplaceGeoObj( pEnt->GetId(), Release( pCC)) ;
|
|
return bOk ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
FilterAndApprox( void)
|
|
{
|
|
IGeomDB* pGeomDB = GetCurrGeomDB() ;
|
|
VERIFY_GEOMDB( pGeomDB, false)
|
|
// preparo gli iteratori
|
|
PtrOwner<IGdbIterator> pPar( CreateGdbIterator( pGeomDB)) ;
|
|
PtrOwner<IGdbIterator> pLay( CreateGdbIterator( pGeomDB)) ;
|
|
PtrOwner<IGdbIterator> pEnt( CreateGdbIterator( pGeomDB)) ;
|
|
if ( IsNull( pPar) || IsNull( pLay) || IsNull( pEnt))
|
|
return false ;
|
|
// ciclo su tutti gli oggetti del DB geometrico
|
|
bool bPok = pPar->GoToFirstInGroup( GDB_ID_ROOT) ;
|
|
while ( bPok) {
|
|
// sotto la radice sono ammessi solo gruppi di livello User -> Pezzi
|
|
int nLev ;
|
|
if ( pPar->GetGdbType() != GDB_TY_GROUP ||
|
|
! pPar->GetCalcLevel( nLev) || nLev != GDB_LV_USER) {
|
|
bPok = pPar->EraseAndGoToNext() ;
|
|
continue ;
|
|
}
|
|
// ciclo su tutti gli oggetti del pezzo
|
|
bool bLok = pLay->GoToFirstInGroup( *Get( pPar)) ;
|
|
while ( bLok) {
|
|
// sotto ogni pezzo sono ammessi solo gruppi di livello User -> Layer
|
|
int nLev ;
|
|
if ( pLay->GetGdbType() != GDB_TY_GROUP ||
|
|
! pLay->GetCalcLevel( nLev) || nLev != GDB_LV_USER) {
|
|
bLok = pLay->EraseAndGoToNext() ;
|
|
continue ;
|
|
}
|
|
// ciclo su tutti gli oggetti del layer
|
|
bool bEok = pEnt->GoToFirstInGroup( *Get( pLay)) ;
|
|
while ( bEok) {
|
|
// sotto ogni layer sono ammesse solo curve di livello User
|
|
int nLev ;
|
|
if ( ( pEnt->GetGeoType() & GEO_CURVE) == 0 ||
|
|
! pEnt->GetCalcLevel( nLev) || nLev != GDB_LV_USER) {
|
|
bEok = pEnt->EraseAndGoToNext() ;
|
|
continue ;
|
|
}
|
|
// eventuale approx della curva se Bezier o Composita con molti piccoli segmenti
|
|
ApproxCurveIfNeeded( Get( pEnt)) ;
|
|
// passo alla successiva entità
|
|
bEok = pEnt->GoToNext() ;
|
|
}
|
|
// passo al successivo layer
|
|
bLok = pLay->GoToNext() ;
|
|
}
|
|
// passo al successivo pezzo
|
|
bPok = pPar->GoToNext() ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
ChainCurves( int& nLay)
|
|
{
|
|
// seleziono tutte le curve
|
|
bool bOk = ExeSelectAll( false) ;
|
|
// creo un nuovo pezzo con layer in cui mettere tutti i concatenati
|
|
int nPart = ExeCreateGroup( GDB_ID_ROOT, Frame3d(), RTY_GLOB) ;
|
|
nLay = ExeCreateGroup( nPart, Frame3d(), RTY_GLOB) ;
|
|
bOk = bOk && nLay != GDB_ID_NULL ;
|
|
// concateno tutte le curve
|
|
INTVECTOR vIds ;
|
|
vIds.push_back( GDB_ID_SEL) ;
|
|
int nCount ;
|
|
int nFirstId = ( bOk ? ExeCreateCurveCompoByChain( nLay, vIds, ORIG, true, RTY_GLOB, &nCount) : GDB_ID_NULL) ;
|
|
bOk = bOk && nFirstId != GDB_ID_NULL ;
|
|
// cancello i gruppi rimasti vuoti
|
|
ExeEraseEmptyParts() ;
|
|
return bOk ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CreateFlatPartsByRegions( int nLay)
|
|
{
|
|
IGeomDB* pGeomDB = GetCurrGeomDB() ;
|
|
VERIFY_GEOMDB( pGeomDB, false)
|
|
// recupero il padre del layer
|
|
int nParentId = pGeomDB->GetParentId( nLay) ;
|
|
// preparo gli iteratori
|
|
PtrOwner<IGdbIterator> pEnt( CreateGdbIterator( pGeomDB)) ;
|
|
if ( IsNull( pEnt))
|
|
return false ;
|
|
// separo le curve aperte da quelle chiuse e salvo vettore aree di queste ultime
|
|
INTVECTOR vOpenIds ;
|
|
INTVECTOR vClosedIds ;
|
|
typedef std::pair<int,double> INDAREA ; // coppia indice, area
|
|
typedef std::vector<INDAREA> INDAREAVECTOR ; // vettore di coppie indice, area
|
|
INDAREAVECTOR vArea ;
|
|
bool bEok = pEnt->GoToFirstInGroup( nLay) ;
|
|
while ( bEok) {
|
|
ICurve* pCrv = GetCurve( pEnt->GetGeoObj()) ;
|
|
if ( pCrv == nullptr) {
|
|
bEok = pEnt->EraseAndGoToNext() ;
|
|
}
|
|
else if ( ! pCrv->IsClosed()) {
|
|
vOpenIds.push_back( pEnt->GetId()) ;
|
|
bEok = pEnt->GoToNext() ;
|
|
}
|
|
else {
|
|
vClosedIds.push_back( pEnt->GetId()) ;
|
|
double dArea ;
|
|
pCrv->GetAreaXY( dArea) ;
|
|
if ( fabs( dArea) > 1) {
|
|
if ( dArea < 0) {
|
|
pCrv->Invert() ;
|
|
dArea = - dArea ;
|
|
}
|
|
vArea.emplace_back( pEnt->GetId(), dArea) ;
|
|
}
|
|
else
|
|
vOpenIds.push_back( pEnt->GetId()) ;
|
|
bEok = pEnt->GoToNext() ;
|
|
}
|
|
}
|
|
// ordino le aree in senso decrescente
|
|
sort( vArea.begin(), vArea.end(),
|
|
[]( const INDAREA& a, const INDAREA&b) { return fabs( a.second) > fabs( b.second) ; }) ;
|
|
// creo i pezzi a partire dalle curve chiuse più grandi e dalle curve che vi sono contenute
|
|
for ( int i = 0 ; i < int( vArea.size()) ; ++ i) {
|
|
if ( vArea[i].first == GDB_ID_NULL)
|
|
continue ;
|
|
// creo pezzo con questa geometria
|
|
int nPartId = pGeomDB->InsertGroup( GDB_ID_NULL, nParentId, GDB_BEFORE, Frame3d()) ;
|
|
// creo layer nel pezzo
|
|
int nLayId = pGeomDB->AddGroup( GDB_ID_NULL, nPartId, Frame3d()) ;
|
|
// sposto il contorno nel pezzo
|
|
pGeomDB->RelocateGlob( vArea[i].first, nLayId) ;
|
|
// cerco altri contorni chiusi che siano contenuti completamente o parzialmente
|
|
ICurve* pCrv = GetCurve( pGeomDB->GetGeoObj( vArea[i].first)) ;
|
|
for ( int j = i + 1 ; j < int( vArea.size()) ; ++ j) {
|
|
if ( vArea[j].first == GDB_ID_NULL)
|
|
continue ;
|
|
ICurve* pCrv2 = GetCurve( pGeomDB->GetGeoObj( vArea[j].first)) ;
|
|
// intersezione e classificazione
|
|
CRVCVECTOR ccClass ;
|
|
IntersCurveCurve intCC( *pCrv2, *pCrv) ;
|
|
if ( ! intCC.GetCurveClassification( 0, ccClass))
|
|
continue ;
|
|
// se completamente interna
|
|
if ( ccClass.size() == 1 && ccClass[0].nClass == CRVC_IN) {
|
|
pGeomDB->RelocateGlob( vArea[j].first, nLayId) ;
|
|
vArea[j].first = GDB_ID_NULL ;
|
|
}
|
|
// se più di un tratto
|
|
else if ( ccClass.size() > 1) {
|
|
// verifico se parzialmente interna
|
|
bool bIn = false ;
|
|
bool bOther = false ;
|
|
for ( int k = 0 ; k < int( ccClass.size()) ; ++ k) {
|
|
if ( ccClass[k].nClass == CRVC_IN)
|
|
bIn = true ;
|
|
else
|
|
bOther = true ;
|
|
}
|
|
// se parzialmente interna, la sposto negli aperti
|
|
if ( bIn && bOther) {
|
|
vOpenIds.push_back( vArea[j].first) ;
|
|
vArea[j].first = GDB_ID_NULL ;
|
|
}
|
|
}
|
|
}
|
|
// verifico i contorni aperti che siano contenuti completamente o parzialmente
|
|
for ( int j = i + 1 ; j < int( vOpenIds.size()) ; ++ j) {
|
|
if ( vOpenIds[j] == GDB_ID_NULL)
|
|
continue ;
|
|
ICurve* pCrv2 = GetCurve( pGeomDB->GetGeoObj( vOpenIds[j])) ;
|
|
Intervals inCrv ;
|
|
double dParS, dParE ;
|
|
pCrv2->GetDomain( dParS, dParE) ;
|
|
inCrv.Set( dParS, dParE) ;
|
|
// intersezione e classificazione
|
|
CRVCVECTOR ccClass ;
|
|
IntersCurveCurve intCC( *pCrv2, *pCrv) ;
|
|
if ( ! intCC.GetCurveClassification( 0, ccClass))
|
|
continue ;
|
|
// conservo solo le parti interne
|
|
for ( int k = 0 ; k < int( ccClass.size()) ; ++ k) {
|
|
if ( ccClass[k].nClass != CRVC_IN)
|
|
inCrv.Subtract( ccClass[k].dParS, ccClass[k].dParE) ;
|
|
}
|
|
// tratti di curva rimasti
|
|
int nNum = inCrv.GetCount() ;
|
|
// se rimangono uno o più tratti
|
|
if ( nNum >= 1) {
|
|
double dParS, dParE ;
|
|
bool bInt = inCrv.GetFirst( dParS, dParE) ;
|
|
while ( bInt) {
|
|
// copio la curva e la modifico
|
|
int nCopyId = pGeomDB->Copy( vOpenIds[j], GDB_ID_NULL, nLayId) ;
|
|
// modifico l'originale
|
|
ICurve* pOriCrv = GetCurve( pGeomDB->GetGeoObj( nCopyId)) ;
|
|
pOriCrv->TrimStartEndAtParam( dParS, dParE) ;
|
|
// passo al successivo intervallo
|
|
bInt = inCrv.GetNext( dParS, dParE) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// elimino la geometria originale rimasta
|
|
pGeomDB->Erase( nParentId) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
CreateFlatPartsByLayers( void)
|
|
{
|
|
IGeomDB* pGeomDB = GetCurrGeomDB() ;
|
|
VERIFY_GEOMDB( pGeomDB, false)
|
|
// preparo gli iteratori
|
|
PtrOwner<IGdbIterator> pPar( CreateGdbIterator( pGeomDB)) ;
|
|
PtrOwner<IGdbIterator> pLay( CreateGdbIterator( pGeomDB)) ;
|
|
if ( IsNull( pPar) || IsNull( pLay))
|
|
return false ;
|
|
// ciclo su tutti i gruppi della radice (pezzi)
|
|
bool bPok = pPar->GoToFirstGroupInGroup( GDB_ID_ROOT) ;
|
|
int nFirstId = pPar->GetId() ;
|
|
while ( bPok) {
|
|
// ciclo su tutti i sottogruppi (layer)
|
|
bool bLok = pLay->GoToFirstGroupInGroup( *Get( pPar)) ;
|
|
while ( bLok) {
|
|
// creo pezzo con questa geometria
|
|
int nPartId = pGeomDB->InsertGroup( GDB_ID_NULL, nFirstId, GDB_BEFORE, Frame3d()) ;
|
|
// passo al pezzo l'eventuale nome del layer
|
|
string sName ;
|
|
if ( pLay->GetName( sName)) {
|
|
pGeomDB->SetName( nPartId, sName) ;
|
|
pLay->RemoveName() ;
|
|
}
|
|
// sposto il layer sotto questo pezzo
|
|
if ( ! pGeomDB->RelocateGlob( pLay->GetId(), nPartId))
|
|
return false ;
|
|
// altro layer del gruppo originale
|
|
bLok = pLay->GoToFirstGroupInGroup( *Get( pPar)) ;
|
|
}
|
|
// passo al successivo
|
|
bPok = pPar->GoToNextGroup() ;
|
|
}
|
|
// cancello i gruppi svuotati
|
|
bPok = pPar->GoTo( nFirstId) ;
|
|
while ( bPok)
|
|
bPok = pPar->EraseAndGoToNext() ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
VerifyAndAdjustFlatParts( void)
|
|
{
|
|
IGeomDB* pGeomDB = GetCurrGeomDB() ;
|
|
VERIFY_GEOMDB( pGeomDB, false)
|
|
// preparo gli iteratori
|
|
PtrOwner<IGdbIterator> pPar( CreateGdbIterator( pGeomDB)) ;
|
|
PtrOwner<IGdbIterator> pEnt( CreateGdbIterator( pGeomDB)) ;
|
|
if ( IsNull( pPar) || IsNull( pEnt))
|
|
return false ;
|
|
// ciclo sui pezzi
|
|
bool bPok = pPar->GoToFirstGroupInGroup( GDB_ID_ROOT) ;
|
|
while ( bPok) {
|
|
// seleziono tutte le curve del pezzo
|
|
bool bOk = ExeSelectPartObjs( pPar->GetId()) ;
|
|
// creo un nuovo layer in cui mettere tutti i concatenati
|
|
int nRegId = ExeCreateGroup( pPar->GetId(), Frame3d(), RTY_GLOB) ;
|
|
bOk = bOk && nRegId != GDB_ID_NULL ;
|
|
bOk = bOk && pGeomDB->SetName( nRegId, "Region") ;
|
|
// concateno tutte le curve
|
|
INTVECTOR vIds ;
|
|
vIds.push_back( GDB_ID_SEL) ;
|
|
int nCount ;
|
|
int nFirstId = ( bOk ? ExeCreateCurveCompoByChain( nRegId, vIds, ORIG, false, RTY_GLOB, &nCount) : GDB_ID_NULL) ;
|
|
bOk = bOk && nFirstId != GDB_ID_NULL ;
|
|
// deseleziono tutto
|
|
pGeomDB->ClearSelection() ;
|
|
// elimino le curve aperte del nuovo layer e uso le chiuse per creare la regione
|
|
INTVECTOR vOpenIds ;
|
|
STRVECTOR vClosedIds ;
|
|
SurfFlatRegionByContours SfrCntr( false, false) ;
|
|
bool bEok = pEnt->GoToFirstInGroup( nRegId) ;
|
|
while ( bEok) {
|
|
ICurve* pCrv = GetCurve( pEnt->GetGeoObj()) ;
|
|
if ( pCrv == nullptr) {
|
|
bEok = pEnt->EraseAndGoToNext() ;
|
|
}
|
|
else if ( ! pCrv->IsClosed()) {
|
|
// salvo Id di origine nell'elenco curve aperte da controllare
|
|
INTVECTOR vTmpIds ;
|
|
if ( pGeomDB->GetInfo( pEnt->GetId(), "ORIG", vTmpIds))
|
|
vOpenIds.insert( vOpenIds.end(), vTmpIds.begin(), vTmpIds.end()) ;
|
|
bEok = pEnt->EraseAndGoToNext() ;
|
|
}
|
|
else {
|
|
// salvo Id entità corrente e preparo passaggio a prossima
|
|
int nEntId = pEnt->GetId() ;
|
|
bEok = pEnt->GoToNext() ;
|
|
// salvo stringa con elenco Id di origine
|
|
string sInfo ;
|
|
if ( pGeomDB->GetInfo( nEntId, "ORIG", sInfo)) {
|
|
vClosedIds.emplace_back( sInfo) ;
|
|
pCrv->SetTempProp( int( vClosedIds.size())) ;
|
|
}
|
|
// estraggo curva da entità che viene cancellata
|
|
SfrCntr.AddCurve( pCrv) ;
|
|
pGeomDB->RemoveGeoObjAndErase( nEntId) ;
|
|
}
|
|
}
|
|
// creo la regione
|
|
ISurfFlatRegion* pSfr = SfrCntr.GetSurf() ;
|
|
bOk = bOk && ( pSfr != nullptr) ;
|
|
// inserisco eventuali curve chiuse non usate nell'elenco delle aperte
|
|
if ( ! SfrCntr.AllCurvesUsed()) {
|
|
// recupero indice da proprietà temporanea di curve non usate
|
|
INTVECTOR vUnId ;
|
|
SfrCntr.GetUnusedCurveTempProps( vUnId) ;
|
|
// recupero Id originali associati
|
|
for ( auto nUnId : vUnId) {
|
|
if ( nUnId > 0 && nUnId <= int( vClosedIds.size())) {
|
|
INTVECTOR vTmpIds ;
|
|
if ( FromString( vClosedIds[nUnId - 1], vTmpIds))
|
|
vOpenIds.insert( vOpenIds.end(), vTmpIds.begin(), vTmpIds.end()) ;
|
|
}
|
|
}
|
|
}
|
|
// inserisco la superficie nel DB
|
|
int nNewId = ( bOk ? pGeomDB->AddGeoObj( GDB_ID_NULL, nRegId, pSfr) : GDB_ID_NULL) ;
|
|
bOk = bOk && nNewId != GDB_ID_NULL ;
|
|
// assegno il colore
|
|
Color cCol = AQUA ;
|
|
cCol.SetAlpha( 0.3) ;
|
|
bOk = bOk && pGeomDB->SetMaterial( nNewId, cCol) ;
|
|
// scrittura delle dimensioni nel layer della regione
|
|
if ( bOk) {
|
|
BBox3d b3Reg ;
|
|
pGeomDB->GetGlobalBBox( nNewId, b3Reg) ;
|
|
Point3d ptMin, ptMax ;
|
|
b3Reg.GetMinMax( ptMin, ptMax) ;
|
|
double dDimX = ptMax.x - ptMin.x ;
|
|
double dDimY = ptMax.y - ptMin.y ;
|
|
string sOut = ToString( ExeToUiUnits( dDimX), 2) + "x" + ToString( ExeToUiUnits( dDimY), 2) ;
|
|
Point3d ptCen = Media( ptMin, ptMax, 0.5) ;
|
|
Vector3d vtDir = ( dDimX >= dDimY ? X_AX : Y_AX) ;
|
|
double dDimT = min( 0.05 * max( dDimX, dDimY), 0.5 * min( dDimX, dDimY)) ;
|
|
PtrOwner<IExtText> pText( CreateExtText()) ;
|
|
if ( ! IsNull( pText) &&
|
|
pText->Set( ptCen, Z_AX, vtDir, sOut, "", 100, false, dDimT, 1, 0, ETXT_IPMC)) {
|
|
int nTextId = pGeomDB->AddGeoObj( GDB_ID_NULL, nRegId, Release( pText)) ;
|
|
pGeomDB->SetMaterial( nTextId, BLACK) ;
|
|
}
|
|
}
|
|
// taglio le curve aperte con la regione
|
|
for ( int i = 0 ; bOk && i < int( vOpenIds.size()) ; ++i) {
|
|
ICurve* pCrv = GetCurve( pGeomDB->GetGeoObj( vOpenIds[i])) ;
|
|
// calcolo la classificazione della curva rispetto alla regione
|
|
CRVCVECTOR ccClass ;
|
|
if ( ! pSfr->GetCurveClassification( *pCrv, ccClass))
|
|
continue ;
|
|
// conservo solo gli intervalli di curva interni
|
|
Intervals inOk ;
|
|
for ( auto& ccOne : ccClass) {
|
|
if ( ccOne.nClass == CRVC_IN)
|
|
inOk.Add( ccOne.dParE, ccOne.dParS) ;
|
|
}
|
|
// recupero un intervallo di id contigui per tutte le parti
|
|
int nFirstId = pGeomDB->GetNewId() ;
|
|
pGeomDB->ChangeId( vOpenIds[i], nFirstId) ;
|
|
int nCurrId = nFirstId ;
|
|
// eseguo la divisione
|
|
nCount = 0 ;
|
|
double dParS, dParE ;
|
|
bool bFound = inOk.GetFirst( dParS, dParE) ;
|
|
while ( bFound) {
|
|
// copio la curva
|
|
int nCopyId = pGeomDB->Copy( nCurrId, GDB_ID_NULL, nCurrId, GDB_AFTER) ;
|
|
ICurve* pCopyCrv = GetCurve( pGeomDB->GetGeoObj( nCopyId)) ;
|
|
if ( pCopyCrv == nullptr)
|
|
break ;
|
|
++ nCount ;
|
|
// modifico l'originale
|
|
bOk = bOk && pCrv->TrimStartEndAtParam( dParS, dParE) ;
|
|
// la copia diventa il nuovo corrente
|
|
nCurrId = nCopyId ;
|
|
pCrv = pCopyCrv ;
|
|
// passo alla successiva divisione
|
|
bFound = inOk.GetNext( dParS, dParE) ;
|
|
}
|
|
// cancello l'ultima copia (se non c'erano intervalli validi è l'originale)
|
|
if ( nCurrId != GDB_ID_NULL)
|
|
pGeomDB->Erase( nCurrId) ;
|
|
}
|
|
// se errore sul pezzo, lo elimino
|
|
if ( ! bOk)
|
|
bPok = pPar->EraseAndGoToNextGroup() ;
|
|
// passo al pezzo successivo
|
|
else
|
|
bPok = pPar->GoToNextGroup() ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
ExeCreateFlatParts( int nType)
|
|
{
|
|
// disabilito registrazione comandi
|
|
bool bOldCmdLog = SetCmdLog( false) ;
|
|
// filtro e approssimo le curve
|
|
bool bOk = FilterAndApprox() ;
|
|
// creazione basata sulle regioni
|
|
if ( nType == FPC_REGION) {
|
|
int nLay ;
|
|
// concateno
|
|
bOk = bOk && ChainCurves( nLay) ;
|
|
// costruisco i pezzi
|
|
bOk = bOk && CreateFlatPartsByRegions( nLay) ;
|
|
}
|
|
// creazione basata sui layer
|
|
else if ( nType == FPC_LAYER) {
|
|
// creazione dei pezzi
|
|
bOk = bOk && CreateFlatPartsByLayers() ;
|
|
}
|
|
// creazione basata sui pezzi NGE
|
|
// sono già a posto
|
|
// verifica e aggiustamento dei pezzi
|
|
bOk = bOk && VerifyAndAdjustFlatParts() ;
|
|
// ripristino stato registrazione comandi
|
|
bOldCmdLog = SetCmdLog( bOldCmdLog) ;
|
|
return bOk ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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)
|
|
{
|
|
BBox3d b3Moved = b3Test ;
|
|
b3Moved.Translate( vtMove) ;
|
|
dExtraMove = 0 ;
|
|
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
|
|
ExePackPart( 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 fabs( a - b) < EPS_SMALL ;}), vY.end()) ;
|
|
// Testo le Y in ordine opportuno
|
|
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 ;
|
|
break ;
|
|
}
|
|
}
|
|
// 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
|
|
ExePackCluster( 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 fabs( a - b) < EPS_SMALL ;}), vY.end()) ;
|
|
// Testo le Y in ordine opportuno
|
|
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 ;
|
|
break ;
|
|
}
|
|
}
|
|
// 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
|
|
ExeMoveCluster( 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 ( fabs( vtMoveXY.x) >= fabs( 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 ;
|
|
} |