//---------------------------------------------------------------------------- // 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 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()) ; } // 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()) ; } // 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 ; }