Files
Riccardo Elitropi 1545bc07cd EgtGeomKernel 3.1c5 :
- Aggiunto controllo dimensioni Zmap per versioni a 32Bit.
2026-03-24 15:58:51 +01:00

2806 lines
109 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2015-2016
//----------------------------------------------------------------------------
// File : VolZmap.cpp Data : 22.01.15 Versione : 1.6a4
// Contenuto : Implementazione della classe Volume Zmap (tre griglie)
//
//
//
// Modifiche : 22.01.15 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "VolZmap.h"
#include "GeoObjFactory.h"
#include "GdbGeo.h"
#include "NgeWriter.h"
#include "NgeReader.h"
#include "GeoConst.h"
#include "/EgtDev/Include/EGkDistPointLine.h"
#include "/EgtDev/Include/EGkIntersLinePlane.h"
#include "/EgtDev/Include/EGkUiUnits.h"
#include "/EgtDev/Include/EGkIntervals.h"
#include "/EgtDev/Include/EGkStringUtils3d.h"
#include "/EgtDev/Include/EgtNumUtils.h"
#include "/EgtDev/Include/EGkIntersLineSurfTm.h"
#include <thread>
#include <future>
#define DEBUG_REMOVE_FINS 0
#if DEBUG_REMOVE_FINS
#include "/EgtDev/Include/EGkGeoObjSave.h"
#include "/EgtDev/Include/EGkGeoPoint3d.h"
#include "/EgtDev/Include/EGkGeoVector3d.h"
std::vector<IGeoObj*> VT ;
std::vector<Color> VC ;
#endif
using namespace std ;
#if !defined(_WIN64)
int VolZmap::m_nDexelNbr = 0 ;
#endif
//----------------------------------------------------------------------------
GEOOBJ_REGISTER( VOL_ZMAP, NGE_V_ZMP, VolZmap) ;
//----------------------------------------------------------------------------
VolZmap::VolZmap(void)
: m_nStatus( TO_VERIFY), m_nTempProp{0,0}, m_dTempParam{0.0,0.0}, m_bShowEdges( false),
m_dStep( 10.0), m_nMapNum( 0), m_nShape( GENERIC), m_nVoxNumPerBlock( N_VOXBLOCK),
m_nDexVoxRatio( 1), m_nNumBlock( 0), m_nConnectedCompoCount( 0), m_nCurrTool( -1),
m_dToolLinTol( LIN_TOL_STD), m_dToolAngTolDeg( ANG_TOL_APPROX_DEG)
{
for ( int i = 0 ; i < N_MAPS ; ++ i) {
m_nNx[i] = 0 ;
m_nNy[i] = 0 ;
m_nDim[i] = 0 ;
m_dMinZ[i] = 0 ;
m_dMaxZ[i] = 0 ;
m_nFracLin[i] = 0 ;
}
m_vTool.resize( 1) ;
}
//----------------------------------------------------------------------------
VolZmap::~VolZmap( void)
{
// Se versione 32-bit aggiorno il numero di Dexel complessivi rimuovendo il numero dei correnti
#if !defined(_WIN64)
int nDexelNbr = 0 ;
for ( int i = 0 ; i < ssize( m_nDim) ; ++ i)
nDexelNbr += m_nDim[i] ;
m_nDexelNbr = max( 0, m_nDexelNbr - nDexelNbr) ;
#endif
}
//----------------------------------------------------------------------------
bool
VolZmap::Clear( void)
{
m_nStatus = TO_VERIFY ;
m_nTempProp[0] = 0 ;
m_nTempProp[1] = 0 ;
m_dTempParam[0] = 0.0 ;
m_dTempParam[1] = 0.0 ;
m_bShowEdges = false ;
m_dStep = 10.0 ;
m_nMapNum = 0 ;
m_nShape = GENERIC ;
m_nVoxNumPerBlock = N_VOXBLOCK ;
m_nDexVoxRatio = 1 ;
m_nNumBlock = 0 ;
m_nConnectedCompoCount = 0 ;
m_MapFrame.Reset() ;
// Se versione 32-bit aggiorno il numero di Dexel complessivi rimuovendo il numero dei correnti
#if !defined(_WIN64)
int nDexelNbr = 0 ;
for ( int i = 0 ; i < ssize( m_nDim) ; ++ i)
nDexelNbr += m_nDim[i] ;
m_nDexelNbr = max( 0, m_nDexelNbr - nDexelNbr) ;
#endif
for ( int i = 0 ; i < N_MAPS ; ++ i) {
m_nNx[i] = 0 ;
m_nNy[i] = 0 ;
m_nDim[i] = 0 ;
m_dMinZ[i] = 0 ;
m_dMaxZ[i] = 0 ;
m_Values[i].clear() ;
}
m_vTool.resize( 1) ;
m_nCurrTool = 0 ;
m_dToolLinTol = LIN_TOL_STD ;
m_dToolAngTolDeg = ANG_TOL_APPROX_DEG ;
// imposto ri-creazione della grafica
m_OGrMgr.Clear() ;
return true ;
}
//----------------------------------------------------------------------------
VolZmap*
VolZmap::Clone( void) const
{
// alloco oggetto
VolZmap* pVzm = new( nothrow) VolZmap ;
if ( pVzm != nullptr) {
if ( ! pVzm->CopyFrom( *this)) {
delete pVzm ;
return nullptr ;
}
}
return pVzm ;
}
//----------------------------------------------------------------------------
bool
VolZmap::CopyFrom( const IGeoObj* pGObjSrc)
{
const VolZmap* pVzm = GetBasicVolZmap( pGObjSrc) ;
if ( pVzm == nullptr)
return false ;
return CopyFrom( *pVzm) ;
}
//----------------------------------------------------------------------------
bool
VolZmap::CopyFrom( const VolZmap& vzmSrc)
{
if ( &vzmSrc == this)
return true ;
m_nMapNum = vzmSrc.m_nMapNum ;
m_nShape = vzmSrc.m_nShape ;
m_nNumBlock = vzmSrc.m_nNumBlock ;
m_nVoxNumPerBlock = vzmSrc.m_nVoxNumPerBlock ;
m_nFracLin[0] = vzmSrc.m_nFracLin[0] ;
m_nFracLin[1] = vzmSrc.m_nFracLin[1] ;
m_nFracLin[2] = vzmSrc.m_nFracLin[2] ;
m_nDexVoxRatio = vzmSrc.m_nDexVoxRatio ;
m_nConnectedCompoCount = vzmSrc.m_nConnectedCompoCount ;
m_MapFrame = vzmSrc.m_MapFrame ;
for ( int i = 0 ; i < int ( m_nMapNum) ; ++ i) {
m_nNx[i] = vzmSrc.m_nNx[i] ;
m_nNy[i] = vzmSrc.m_nNy[i] ;
m_nDim[i] = vzmSrc.m_nDim[i] ;
m_dMinZ[i] = vzmSrc.m_dMinZ[i] ;
m_dMaxZ[i] = vzmSrc.m_dMaxZ[i] ;
m_Values[i] = vzmSrc.m_Values[i] ;
}
m_dStep = vzmSrc.m_dStep ;
m_nStatus = vzmSrc.m_nStatus ;
m_nTempProp[0] = vzmSrc.m_nTempProp[0] ;
m_nTempProp[1] = vzmSrc.m_nTempProp[1] ;
m_dTempParam[0] = vzmSrc.m_dTempParam[0] ;
m_dTempParam[1] = vzmSrc.m_dTempParam[1] ;
m_bShowEdges = vzmSrc.m_bShowEdges ;
// dimensiono membri legati ai blocchi
m_BlockToUpdate = vzmSrc.m_BlockToUpdate ;
m_BlockUpdatingCounter = vzmSrc.m_BlockUpdatingCounter ;
m_InterBlockVox = vzmSrc.m_InterBlockVox ;
m_InterBlockOriginalSharpTria = vzmSrc.m_InterBlockOriginalSharpTria ;
m_InterBlockSharpTria = vzmSrc.m_InterBlockSharpTria ;
m_BlockSharpTria = vzmSrc.m_BlockSharpTria ;
m_BlockSmoothTria = vzmSrc.m_BlockSmoothTria ;
m_BlockBigTria = vzmSrc.m_BlockBigTria ;
m_SingleMapTria = vzmSrc.m_SingleMapTria ;
m_SliceXY = vzmSrc.m_SliceXY ;
m_SliceXZ = vzmSrc.m_SliceXZ ;
m_SliceYZ = vzmSrc.m_SliceYZ ;
// imposto ricalcolo grafica
ResetGraphics() ;
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::ResetGraphics( void)
{
m_OGrMgr.Clear() ;
for ( int nCount = 0 ; nCount < m_nNumBlock ; ++ nCount)
m_BlockToUpdate[nCount] = true ;
return true ;
}
//----------------------------------------------------------------------------
GeoObjType
VolZmap::GetType( void) const
{
return static_cast<GeoObjType>( GEOOBJ_GETTYPE( VolZmap)) ;
}
//----------------------------------------------------------------------------
const string&
VolZmap::GetTitle( void) const
{
static const string sTitle = "VolZm" ;
return sTitle ;
}
//----------------------------------------------------------------------------
bool
VolZmap::Dump( string& sOut, bool bMM, const char* szNewLine) const
{
// tipo
sOut += "Type=" + string( m_nMapNum == 1 ? "dexel" : "tridexel") + szNewLine ;
// visualizzazione spigoli
sOut += "ShowEdges=" + ToString( GetShowEdges()) + szNewLine ;
// dexel per voxel (DexToVoxRatio)
sOut += "DexVoxRat=" + ToString( m_nDexVoxRatio) + szNewLine ;
// forma
switch ( m_nShape) {
default : sOut += "Shape=generic" ; break ;
case BOX : sOut += "Shape=box" ; break ;
case EXTRUSION : sOut += "Shape=extrusion" ; break ;
}
sOut += szNewLine ;
// passo
sOut += "Step=" + ToString( GetInUiUnits( m_dStep, bMM), 6) + szNewLine ;
// dimensioni
if ( m_nMapNum == 1)
sOut += "Dim=" + ToString( m_nDim[0]) +
"(" + ToString( m_nNx[0]) + "x" + ToString( m_nNy[0]) + ")" + szNewLine ;
else {
for ( int i = 0 ; i < m_nMapNum ; ++ i)
sOut += "Dim" + ToString( i+1) + "=" + ToString( m_nDim[i]) +
"(" + ToString( m_nNx[i]) + "x" + ToString( m_nNy[i]) + ")" + szNewLine ;
}
// numero di blocchi
sOut += "Blocks=" + ToString( m_nNumBlock) + " (" + ToString( m_nFracLin[0]) + "x" +
ToString( m_nFracLin[1]) + "x" + ToString( m_nFracLin[2]) + ")" + szNewLine ;
return true ;
}
//----------------------------------------------------------------------------
int
VolZmap::GetNgeId( void) const
{
return GEOOBJ_GETNGEID( VolZmap) ;
}
//----------------------------------------------------------------------------
bool
VolZmap::Save( NgeWriter& ngeOut) const
{
// numero di mappe
if ( ! ngeOut.WriteInt( m_nMapNum, ",", false))
return false ;
// numero di blocchi
if ( ! ngeOut.WriteInt( m_nNumBlock, ",", false))
return false ;
// numero di voxel per blocco
if ( ! ngeOut.WriteInt( m_nVoxNumPerBlock, ",", false))
return false ;
// numero di blocchi per ogni asse
for ( int i = 0 ; i < 3 ; ++ i) {
if ( ! ngeOut.WriteInt( m_nFracLin[i], ",", false))
return false ;
}
// DexVoxRatio
if ( ! ngeOut.WriteInt( m_nDexVoxRatio, ",", false))
return false ;
// numero di componenti connesse
if ( ! ngeOut.WriteInt( m_nConnectedCompoCount, ",", false))
return false ;
// passo di campionamento (distanza tra spilloni)
if ( ! ngeOut.WriteDouble( m_dStep, ";", true))
return false ;
// forma
if ( ! ngeOut.WriteInt( m_nShape, ";", true))
return false ;
// sistema di riferimento
if ( ! ngeOut.WriteFrame( m_MapFrame, ";", true))
return false ;
// per ogni mappa : numero di passi in X e Y e quote Z estremali
for ( int i = 0 ; i < m_nMapNum ; ++ i) {
if ( ! ngeOut.WriteInt( m_nNx[i], ",", false))
return false ;
if ( ! ngeOut.WriteInt( m_nNy[i], ",", false))
return false ;
if ( ! ngeOut.WriteDouble( m_dMinZ[i], ",", false))
return false ;
if ( ! ngeOut.WriteDouble( m_dMaxZ[i], ";", true))
return false ;
}
// ciclo sulle mappe
for ( int i = 0 ; i < m_nMapNum ; ++ i) {
// ciclo sui dexel
for ( int j = 0 ; j < m_nDim[i] ; ++ j) {
// numero di estremi
int nDim = int( m_Values[i][j].size()) ;
if ( ! ngeOut.WriteInt( nDim, ":", false))
return false ;
// se dexel nullo
if ( nDim == 0) {
// scrivo un valore dummy
if ( ! ngeOut.WriteDouble( 0, ";", true))
return false ;
}
// altrimenti
else {
for ( int k = 0 ; k < nDim ; ++ k) {
if ( ! ngeOut.WriteDouble( m_Values[i][j][k].dMin, ",", false))
return false ;
if ( ! ngeOut.WriteInt( m_Values[i][j][k].nToolMin, ";", false))
return false ;
if ( ! ngeOut.WriteVector( m_Values[i][j][k].vtMinN, ";", false))
return false ;
if ( ! ngeOut.WriteDouble( m_Values[i][j][k].dMax, ",", false))
return false ;
if ( ! ngeOut.WriteInt( m_Values[i][j][k].nToolMax, ";", false))
return false ;
if ( ! ngeOut.WriteVector( m_Values[i][j][k].vtMaxN, ";", false))
return false ;
if ( ! ngeOut.WriteInt( m_Values[i][j][k].nCompo, ";", true))
return false ;
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::PreSave( GdbGeo& Wrapper) const
{
// salvo il flag di visualizzazione spigoli vivi anche in shading (default false)
if ( m_bShowEdges)
Wrapper.SetInfo( GDB_SI_SHOWEDGES, true) ;
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::PostSave( GdbGeo& Wrapper) const
{
// elimino eventuali info aggiunte nella PreSave
Wrapper.RemoveInfo( GDB_SI_SHOWEDGES) ;
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::Load( NgeReader& ngeIn)
{
Clear() ;
// numero di mappe
if ( ! ngeIn.ReadInt( m_nMapNum, ",", false))
return false ;
// numero di blocchi
if ( ! ngeIn.ReadInt( m_nNumBlock, ",", false))
return false ;
// numero di voxel per blocco
if ( ! ngeIn.ReadInt( m_nVoxNumPerBlock, ",", false))
return false ;
// numero di blocchi per ogni asse
for ( int i = 0 ; i < 3 ; ++ i) {
if ( ! ngeIn.ReadInt( m_nFracLin[i], ",", false))
return false ;
}
// da versione 1018 : aggiunto DexVoxRatio
if ( ngeIn.GetFileVersion() >= NGE_VER_1018) {
if ( ! ngeIn.ReadInt( m_nDexVoxRatio, ",", false))
return false ;
}
// numero di componenti connesse
if ( ! ngeIn.ReadInt( m_nConnectedCompoCount, ",", false))
return false ;
// passo di campionamento (distanza tra spilloni)
if ( ! ngeIn.ReadDouble( m_dStep, ";", true))
return false ;
// da versione 1014 : aggiunto flag Shape
if ( ngeIn.GetFileVersion() >= NGE_VER_1014) {
if ( ! ngeIn.ReadInt( m_nShape, ";", true))
return false ;
}
// sistema di riferimento
if ( ! ngeIn.ReadFrame( m_MapFrame, ";", true))
return false ;
// per ogni mappa : numero di passi in X e Y e quote Z estremali
for ( int i = 0 ; i < m_nMapNum ; ++ i) {
if ( ! ngeIn.ReadInt( m_nNx[i], ",", false))
return false ;
if ( ! ngeIn.ReadInt( m_nNy[i], ",", false))
return false ;
m_nDim[i] = m_nNx[i] * m_nNy[i] ;
if ( ! ngeIn.ReadDouble( m_dMinZ[i], ",", false))
return false ;
if ( ! ngeIn.ReadDouble( m_dMaxZ[i], ";", true))
return false ;
}
// ciclo sulle mappe
for ( int i = 0 ; i < m_nMapNum ; ++ i) {
// dimensiono i vettori
m_Values[i].resize( m_nDim[i]) ;
// ciclo sui dexel
for ( int j = 0 ; j < m_nDim[i] ; ++ j) {
// leggo il numero di estremi nel dexel
int nDim ;
if ( ! ngeIn.ReadInt( nDim, ":", false))
return false ;
// se dexel nullo
if ( nDim == 0) {
// leggo un valore dummy
double dDummy ;
if ( ! ngeIn.ReadDouble( dDummy, ";", true))
return false ;
}
// altrimenti
else {
// dimensiono l'array
m_Values[i][j].resize( nDim) ;
// leggo i valori
for ( int k = 0 ; k < nDim ; ++ k) {
if ( ! ngeIn.ReadDouble( m_Values[i][j][k].dMin, ",", false))
return false ;
if ( ! ngeIn.ReadInt( m_Values[i][j][k].nToolMin, ";", false))
return false ;
if ( ! ngeIn.ReadVector( m_Values[i][j][k].vtMinN, ";", false))
return false ;
if ( ! ngeIn.ReadDouble( m_Values[i][j][k].dMax, ",", false))
return false ;
if ( ! ngeIn.ReadInt( m_Values[i][j][k].nToolMax, ";", false))
return false ;
if ( ! ngeIn.ReadVector( m_Values[i][j][k].vtMaxN, ";", false))
return false ;
if ( ! ngeIn.ReadInt( m_Values[i][j][k].nCompo, ";", true))
return false ;
}
}
}
}
// imposto aggiornamento obbligatorio su tutti i blocchi
m_BlockToUpdate.resize( m_nNumBlock, true) ;
m_BlockUpdatingCounter.resize( m_nNumBlock + ( m_nMapNum == 1 ? 0 : 1), 0) ;
// per triangoli di feature di frontiera tra blocchi
m_InterBlockVox.resize( m_nNumBlock) ;
m_InterBlockOriginalSharpTria.resize( m_nNumBlock) ;
m_InterBlockSharpTria.resize( m_nNumBlock) ;
m_BlockSharpTria.resize( m_nNumBlock) ;
m_BlockSmoothTria.resize( m_nNumBlock) ;
m_BlockBigTria.resize( m_nNumBlock) ;
m_SingleMapTria.resize( m_nNumBlock) ;
m_SliceXY.resize( m_nNumBlock) ;
m_SliceXZ.resize( m_nNumBlock) ;
m_SliceYZ.resize( m_nNumBlock) ;
m_nStatus = OK ;
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::PostLoad( GdbGeo& Wrapper)
{
// recupero eventuale flag di visualizzazione spigoli vivi anche in shading
bool bVal ;
if ( Wrapper.GetInfo( GDB_SI_SHOWEDGES, bVal)) {
m_bShowEdges = bVal ;
Wrapper.RemoveInfo( GDB_SI_SHOWEDGES) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::GetLocalBBox( BBox3d& b3Loc, int nFlag) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// reset box
b3Loc.Reset() ;
// se richiesto approssimato
if ( ( nFlag & BBF_EXACT) == 0) {
b3Loc.Add( ORIG) ;
b3Loc.Add( Point3d( m_nNx[0] * m_dStep, m_nNy[0] * m_dStep, m_dMaxZ[0])) ;
b3Loc.ToGlob( m_MapFrame) ;
return true ;
}
// calcolo preciso
// ciclo sui dexel (punti in basso con ciclo aggiunto per punti in alto di ultima riga)
double dY = 0 ;
for ( int j = 0 ; j <= m_nNy[0] ; ++ j) {
int jc = ( ( j != m_nNy[0]) ? j : m_nNy[0] - 1) ;
double dX = 0 ;
// punto a sinistra di ogni dexel (aggiungo un ciclo per fare punto a destra di ultimo)
for ( int i = 0 ; i <= m_nNx[0] ; ++ i) {
int ic = ( ( i != m_nNx[0]) ? i : m_nNx[0] - 1) ;
int nPos = ic + jc * m_nNx[0] ;
if ( ! m_Values[0][nPos].empty()) {
Point3d ptP = m_MapFrame.Orig() + dX * m_MapFrame.VersX() + dY * m_MapFrame.VersY() ;
b3Loc.Add( ptP + m_Values[0][nPos][0].dMin * m_MapFrame.VersZ()) ;
b3Loc.Add( ptP + m_Values[0][nPos][m_Values[0][nPos].size()-1].dMax * m_MapFrame.VersZ()) ;
}
// passo al punto successivo
dX += m_dStep ;
if ( m_nMapNum == N_MAPS)
dX = min( dX, m_dMaxZ[1]) ;
}
// passo alla riga successiva
dY += m_dStep ;
if ( m_nMapNum == N_MAPS)
dY = min( dY, m_dMaxZ[2]) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::GetBBox( const Frame3d& frRef, BBox3d& b3Ref, int nFlag) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// reset box
b3Ref.Reset() ;
// trasformo il riferimento locale tramite quello passato
Frame3d frUse = m_MapFrame ;
frUse.ToGlob( frRef) ;
// se richiesto approssimato
if ( ( nFlag & BBF_EXACT) == 0) {
b3Ref.Add( ORIG) ;
b3Ref.Add( Point3d( m_nNx[0] * m_dStep, m_nNy[0] * m_dStep, m_dMaxZ[0])) ;
b3Ref.ToGlob( frUse) ;
return true ;
}
// calcolo preciso
// ciclo sui dexel (punti in basso con ciclo aggiunto per punti in alto di ultima riga)
double dY = 0 ;
for ( int j = 0 ; j <= m_nNy[0] ; ++ j) {
int jc = ( ( j != m_nNy[0]) ? j : m_nNy[0] - 1) ;
double dX = 0 ;
// punto a sinistra di ogni dexel (aggiungo un ciclo per fare punto a destra di ultimo)
for ( int i = 0 ; i <= m_nNx[0] ; ++ i) {
int ic = ( ( i != m_nNx[0]) ? i : m_nNx[0] - 1) ;
int nPos = ic + jc * m_nNx[0] ;
if ( nPos >= 0 && ! m_Values[0][nPos].empty()) {
Point3d ptP = frUse.Orig() + dX * frUse.VersX() + dY * frUse.VersY() ;
b3Ref.Add( ptP + m_Values[0][nPos][0].dMin * frUse.VersZ()) ;
b3Ref.Add( ptP + m_Values[0][nPos][m_Values[0][nPos].size()-1].dMax * frUse.VersZ()) ;
}
// passo al punto successivo
dX += m_dStep ;
if ( m_nMapNum == N_MAPS)
dX = min( dX, m_dMaxZ[1]) ;
}
// passo alla riga successiva
dY += m_dStep ;
if ( m_nMapNum == N_MAPS)
dY = min( dY, m_dMaxZ[2]) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::GetPartLocalBBox( int nPart, BBox3d& b3Loc, int nFlag) const
{
// Verifico lo stato.
if ( m_nStatus != OK)
return false ;
// Se una sola mappa o il numero di componenti è indefinito, vi è un errore.
if ( m_nMapNum == 1 || m_nConnectedCompoCount == - 1)
return false ;
// Se la componente richiesta non esiste, vi è un errore.
if ( nPart < 0 || nPart > m_nConnectedCompoCount - 1)
return false ;
// Calcolo Bounding-box
for ( int nMap = 0 ; nMap < 3 ; ++ nMap) {
for ( int nDex = 0 ; nDex < m_nDim[nMap] ; ++ nDex) {
for ( int nInt = 0 ; nInt < int( m_Values[nMap][nDex].size()) ; ++ nInt) {
if ( m_Values[nMap][nDex][nInt].nCompo == nPart + 1) {
// Indici del dexel
int nI = nDex % m_nNx[nMap] ;
int nJ = nDex / m_nNx[nMap] ;
// Posizione del dexel
double dX = ( nI + 0.5) * m_dStep ;
double dY = ( nJ + 0.5) * m_dStep ;
// Definisco i punti nel sistema locale
Point3d ptP, ptPSt, ptPEn ;
if ( nMap == 0) {
ptP = m_MapFrame.Orig() + dX * m_MapFrame.VersX() + dY * m_MapFrame.VersY() ;
ptPSt = ptP + m_Values[nMap][nDex][nInt].dMin * m_MapFrame.VersZ() ;
ptPEn = ptP + m_Values[nMap][nDex][nInt].dMax * m_MapFrame.VersZ() ;
}
else if ( nMap == 1) {
ptP = m_MapFrame.Orig() + dX * m_MapFrame.VersY() + dY * m_MapFrame.VersZ() ;
ptPSt = ptP + m_Values[nMap][nDex][nInt].dMin * m_MapFrame.VersX() ;
ptPEn = ptP + m_Values[nMap][nDex][nInt].dMax * m_MapFrame.VersX() ;
}
else {
ptP = m_MapFrame.Orig() + dX * m_MapFrame.VersZ() + dY * m_MapFrame.VersX() ;
ptPSt = ptP + m_Values[nMap][nDex][nInt].dMin * m_MapFrame.VersY() ;
ptPEn = ptP + m_Values[nMap][nDex][nInt].dMax * m_MapFrame.VersY() ;
}
// Aggiungo i punti al bounding-box
b3Loc.Add( ptPSt) ;
b3Loc.Add( ptPEn) ;
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::GetPartBBox( int nPart, const Frame3d& frRef, BBox3d& b3Ref, int nFlag) const
{
// Verifico lo stato.
if ( m_nStatus != OK)
return false ;
// Se una sola mappa o il numero di componenti è indefinito, vi è un errore.
if ( m_nMapNum == 1 || m_nConnectedCompoCount == - 1)
return false ;
// Se la componente richiesta non esiste, vi è un errore.
if ( nPart < 0 || nPart > m_nConnectedCompoCount - 1)
return false ;
// Calcolo Bounding-box
Point3d ptMapFrameOrig = m_MapFrame.Orig() ;
Vector3d vtMapFrameVersX = m_MapFrame.VersX() ;
Vector3d vtMapFrameVersY = m_MapFrame.VersY() ;
Vector3d vtMapFrameVersZ = m_MapFrame.VersZ() ;
ptMapFrameOrig.ToGlob( frRef) ;
vtMapFrameVersX.ToGlob( frRef) ;
vtMapFrameVersY.ToGlob( frRef) ;
vtMapFrameVersZ.ToGlob( frRef) ;
for ( int nMap = 0 ; nMap < 3 ; ++ nMap) {
for ( int nDex = 0 ; nDex < m_nDim[nMap] ; ++ nDex) {
for ( int nInt = 0 ; nInt < int( m_Values[nMap][nDex].size()) ; ++ nInt) {
if ( m_Values[nMap][nDex][nInt].nCompo == nPart + 1) {
// Indici del dexel
int nI = nDex % m_nNx[nMap] ;
int nJ = nDex / m_nNx[nMap] ;
// Posizione del dexel
double dX = ( nI + 0.5) * m_dStep ;
double dY = ( nJ + 0.5) * m_dStep ;
// Definisco i punti nel sistema locale
Point3d ptP, ptPSt, ptPEn ;
if ( nMap == 0) {
ptP = ptMapFrameOrig + dX * vtMapFrameVersX + dY * vtMapFrameVersY ;
ptPSt = ptP + m_Values[nMap][nDex][nInt].dMin * vtMapFrameVersZ ;
ptPEn = ptP + m_Values[nMap][nDex][nInt].dMax * vtMapFrameVersZ ;
}
else if ( nMap == 1) {
ptP = ptMapFrameOrig + dX * vtMapFrameVersY + dY * vtMapFrameVersZ ;
ptPSt = ptP + m_Values[nMap][nDex][nInt].dMin * vtMapFrameVersX ;
ptPEn = ptP + m_Values[nMap][nDex][nInt].dMax * vtMapFrameVersX ;
}
else {
ptP = ptMapFrameOrig + dX * vtMapFrameVersZ + dY * vtMapFrameVersX ;
ptPSt = ptP + m_Values[nMap][nDex][nInt].dMin * vtMapFrameVersY ;
ptPEn = ptP + m_Values[nMap][nDex][nInt].dMax * vtMapFrameVersY ;
}
// Aggiungo i punti al bounding-box
b3Ref.Add( ptPSt) ;
b3Ref.Add( ptPEn) ;
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::Translate( const Vector3d& vtMove)
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// imposto ricalcolo della grafica
ResetGraphics() ;
// traslo il riferimento
m_MapFrame.Translate( vtMove) ;
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, double dSinAng)
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità dell'asse di rotazione
if ( vtAx.IsSmall())
return false ;
// imposto ricalcolo della grafica
ResetGraphics() ;
// ruoto il riferimento
m_MapFrame.Rotate( ptAx, vtAx, dCosAng, dSinAng) ;
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double dCoeffZ)
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico non sia nulla
if ( abs( dCoeffX) < EPS_ZERO && abs( dCoeffY) < EPS_ZERO && abs( dCoeffZ) < EPS_ZERO)
return false ;
return false ;
}
//----------------------------------------------------------------------------
bool
VolZmap::Mirror( const Point3d& ptOn, const Vector3d& vtNorm)
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità del piano di specchiatura
if ( vtNorm.IsSmall())
return false ;
return false ;
}
//----------------------------------------------------------------------------
bool
VolZmap::Shear( const Point3d& ptOn, const Vector3d& vtNorm, const Vector3d& vtDir, double dCoeff)
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità dei parametri
if ( vtNorm.IsSmall() || vtDir.IsSmall())
return false ;
return false ;
}
//----------------------------------------------------------------------------
bool
VolZmap::ToGlob( const Frame3d& frRef)
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// se frame identità, non devo fare alcunché
if ( IsGlobFrame( frRef))
return true ;
// imposto ricalcolo della grafica
ResetGraphics() ;
// trasformo il riferimento
m_MapFrame.ToGlob( frRef) ;
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::ToLoc( const Frame3d& frRef)
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// se frame identità, non devo fare alcunché
if ( IsGlobFrame( frRef))
return true ;
// imposto ricalcolo della grafica
ResetGraphics() ;
// trasformo il riferimento
m_MapFrame.ToLoc( frRef) ;
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::LocToLoc( const Frame3d& frOri, const Frame3d& frDest)
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità dei frame
if ( frOri.GetType() == Frame3d::ERR || frDest.GetType() == Frame3d::ERR)
return false ;
// se i due riferimenti coincidono, non devo fare alcunché
if ( AreSameFrame( frOri, frDest))
return true ;
// imposto ricalcolo della grafica
ResetGraphics() ;
// trasformo il riferimento
m_MapFrame.LocToLoc( frOri, frDest) ;
return true ;
}
//----------------------------------------------------------------------------
int
VolZmap::GetPartCount( void) const
{
// Se mono-dexel la connessione è incalcolabile.
if ( m_nMapNum == 1)
return - 1 ;
// Se il numero delle componenti è indefinito
// lo ricalcolo e restituisco il risultato.
if ( m_nConnectedCompoCount == - 1) {
const_cast<VolZmap*>(this)->CheckMapConnection() ;
return m_nConnectedCompoCount ;
}
// Altrimenti restituisco direttamente il numero di componenti.
else
return m_nConnectedCompoCount ;
}
//----------------------------------------------------------------------------
bool
VolZmap::CheckMapConnection( void)
{
// Imposto il numero di componenti connesse a 0
m_nConnectedCompoCount = 0 ;
// Imposto a 0 tutti il valore del numero della componente
// connessa di ciascun tratto di ciascun dexel.
for ( int tMap = 0 ; tMap < m_nMapNum ; ++ tMap) {
for ( int tDex = 0 ; tDex < m_nDim[tMap] ; ++ tDex) {
for ( int tInt = 0 ; tInt < int( m_Values[tMap][tDex].size()) ; ++ tInt) {
m_Values[tMap][tDex][tInt].nCompo = 0 ;
}
}
}
// Numero massimo di thread
int nThreadMax = max( 1, int( thread::hardware_concurrency()) - 1) ;
// Ciclo sui dexel lungo Z
for ( int tI = 0 ; tI < m_nNx[0] ; ++ tI) {
for ( int tJ = 0 ; tJ < m_nNy[0] ; ++ tJ) {
// Numero del dexel lungo Z
int tDexZ = tJ * m_nNx[0] + tI ;
// Numero di intervalli nel dexel
int tStopIntZ = int( m_Values[0][tDexZ].size()) ;
// Ciclo sugli intervalli del dexel
for ( int tIntZ = 0 ; tIntZ < tStopIntZ ; ++ tIntZ) {
if ( m_Values[0][tDexZ][tIntZ].nCompo == 0) {
++ m_nConnectedCompoCount ;
m_Values[0][tDexZ][tIntZ].nCompo = m_nConnectedCompoCount ;
// Espando in tutta la componente
// Segmento corrente
IntervalIndexes NewInt ;
NewInt.tMap = 0 ;
NewInt.tDex = tJ * m_nNx[0] + tI ;
NewInt.tInt = tIntZ ;
// Vettore di stack di segmenti
IntContainerVec IntervalsToProcessStackVec ;
IntervalsToProcessStackVec.resize( nThreadMax) ;
// Mi espando dal primo intervallo mettendo gli intervalli che intersecano nei vari thread
FirstExpansionFromZ( nThreadMax, NewInt, IntervalsToProcessStackVec) ;
// Lancio in parallelo più ricerche
int nActiveThread = 0 ;
vector<future<bool>> vRes ;
vRes.resize( nThreadMax) ;
for ( int i = 0 ; i < nThreadMax ; ++ i) {
if ( ! IntervalsToProcessStackVec[i].empty()) {
++ nActiveThread ;
vRes[i] = async( launch::async, &VolZmap::ProcessIntervals, this, ref( IntervalsToProcessStackVec[i])) ;
}
}
// Attendo che tutti i porcessi terminino
int nTerminated = 0 ;
while ( nTerminated < nActiveThread) {
for ( int i = 0 ; i < nThreadMax ; ++ i) {
if ( vRes[i].valid() && vRes[i].wait_for( chrono::nanoseconds{ 1}) == future_status::ready) {
vRes[i].get() ;
++ nTerminated ;
}
}
}
}
// Se l'intervallo non attraversa un nodo o ha già
// un indice assegnato salto questa iterazione.
else
continue ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::ExpandFromXInterval( IntContainer& IntCont)
{
// Copio i dati dell'intervallo corrente
IntervalIndexes CurrInterval = IntCont.top() ;
IntCont.pop() ;
int tDex = CurrInterval.tDex ;
int tGrIndex1 = CurrInterval.tDex % m_nNx[1] ;
int tGrIndex2 = CurrInterval.tDex / m_nNx[1] ;
int tInt = CurrInterval.tInt ;
// Quote estreme del segmento lungo X
double dMinX = m_Values[1][tDex][tInt].dMin ;
double dMaxX = m_Values[1][tDex][tInt].dMax ;
double dMinDX = max( floor( ( dMinX - 2 * EPS_SMALL) / m_dStep - 0.5), 0.) ;
double dMaxDX = max( floor( ( dMaxX + 2 * EPS_SMALL) / m_dStep - 0.5), 0.) ;
// Indici estremi dei dei dexel ortogonali
// che possono intersecare il segmento di partenza
int tStartI = min( int( dMinDX), ( m_nNx[0] - 1)) ;
int tStopI = min( int( dMaxDX), ( m_nNx[0] - 1)) ;
// Posizione YZ del dexel
double dY = ( tGrIndex1 + 0.5) * m_dStep ;
double dZ = ( tGrIndex2 + 0.5) * m_dStep ;
// Ciclo sugli indici dei dexel che potrebbero
// intersecare il segmento di partenza
for ( int tI = tStartI ; tI <= tStopI ; ++ tI) {
// Analizzo i dexel della griglia 0.
int tStopZ = int( m_Values[0][tGrIndex1 * m_nNx[0] + tI].size()) ;
for ( int tIntZ = 0 ; tIntZ < tStopZ ; ++ tIntZ) {
// Estremi del dexel lunog Z
double dZmin = m_Values[0][tGrIndex1 * m_nNx[0] + tI][tIntZ].dMin ;
double dZmax = m_Values[0][tGrIndex1 * m_nNx[0] + tI][tIntZ].dMax ;
// Se i segmenti si incrociano e il nuovo trovato non
// ha già un indice assegnato, assegno l'indice e
// aggiungo l'intervallo trovato allo stack.
if ( dZmin - 2 * EPS_SMALL < dZ &&
dZmax + 2 * EPS_SMALL > dZ &&
m_Values[0][tGrIndex1 * m_nNx[0] + tI][tIntZ].nCompo == 0) {
m_Values[0][tGrIndex1 * m_nNx[0] + tI][tIntZ].nCompo = m_Values[1][tDex][tInt].nCompo ;
IntervalIndexes NewInterval ;
NewInterval.tMap = 0 ;
NewInterval.tDex = tGrIndex1 * m_nNx[0] + tI ;
NewInterval.tInt = tIntZ ;
IntCont.push( NewInterval) ;
}
}
// Analizzo i dexel della griglia 2
int tStopY = int( m_Values[2][tI * m_nNx[2] + tGrIndex2].size()) ;
for ( int tIntY = 0 ; tIntY < tStopY ; ++ tIntY) {
// Estremi del segmento del dexel lungo Y
double dYmin = m_Values[2][tI * m_nNx[2] + tGrIndex2][tIntY].dMin ;
double dYmax = m_Values[2][tI * m_nNx[2] + tGrIndex2][tIntY].dMax ;
// Se i segmenti si incrociano e il nuovo trovato non
// ha già un indice assegnato, assegno l'indice e
// aggiungo l'intervallo trovato allo stack.
if ( dYmin - 2 * EPS_SMALL < dY &&
dYmax + 2 * EPS_SMALL > dY &&
m_Values[2][tI * m_nNx[2] + tGrIndex2][tIntY].nCompo == 0) {
m_Values[2][tI * m_nNx[2] + tGrIndex2][tIntY].nCompo = m_Values[1][tDex][tInt].nCompo ;
IntervalIndexes NewInterval ;
NewInterval.tMap = 2 ;
NewInterval.tDex = tI * m_nNx[2] + tGrIndex2 ;
NewInterval.tInt = tIntY ;
IntCont.push( NewInterval) ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::ExpandFromYInterval( IntContainer& IntCont)
{
// Copio i dati dell'intervallo corrente
IntervalIndexes CurrInterval = IntCont.top() ;
IntCont.pop() ;
int tDex = CurrInterval.tDex ;
int tGrIndex1 = CurrInterval.tDex % m_nNx[2] ;
int tGrIndex2 = CurrInterval.tDex / m_nNx[2] ;
int tInt = CurrInterval.tInt ;
// Quote estreme del segmento lungo Y
double dMinY = m_Values[2][tDex][tInt].dMin ;
double dMaxY = m_Values[2][tDex][tInt].dMax ;
double dMinDY = max( floor( ( dMinY - 2 * EPS_SMALL) / m_dStep - 0.5), 0.) ;
double dMaxDY = max( floor( ( dMaxY + 2 * EPS_SMALL) / m_dStep - 0.5), 0.) ;
// Indici estremi dei dei dexel ortogonali
// che possono intersecare il segmento di partenza
int tStartJ = min( int( dMinDY), ( m_nNy[0] - 1)) ;
int tStopJ = min( int( dMaxDY), ( m_nNy[0] - 1)) ;
// Posizione XZ del dexel
double dX = ( tGrIndex2 + 0.5) * m_dStep ;
double dZ = ( tGrIndex1 + 0.5) * m_dStep ;
// Ciclo sugli indici dei dexel che potrebbero
// intersecare il segmento di partenza
for ( int tJ = tStartJ ; tJ <= tStopJ ; ++ tJ) {
// Analizzo i dexel della griglia 0.
int tStopZ = int( m_Values[0][tJ * m_nNx[0] + tGrIndex2].size()) ;
for ( int tIntZ = 0 ; tIntZ < tStopZ ; ++ tIntZ) {
// Estremi del dexel lunog Z
double dZmin = m_Values[0][tJ * m_nNx[0] + tGrIndex2][tIntZ].dMin ;
double dZmax = m_Values[0][tJ * m_nNx[0] + tGrIndex2][tIntZ].dMax ;
// Se i segmenti si incrociano e il nuovo trovato non
// ha già un indice assegnato, assegno l'indice e
// aggiungo l'intervallo trovato allo stack.
if ( dZmin - 2 * EPS_SMALL < dZ &&
dZmax + 2 * EPS_SMALL > dZ &&
m_Values[0][tJ * m_nNx[0] + tGrIndex2][tIntZ].nCompo == 0) {
m_Values[0][tJ * m_nNx[0] + tGrIndex2][tIntZ].nCompo = m_Values[2][tDex][tInt].nCompo ;
IntervalIndexes NewInterval ;
NewInterval.tMap = 0 ;
NewInterval.tDex = tJ * m_nNx[0] + tGrIndex2 ;
NewInterval.tInt = tIntZ ;
IntCont.push( NewInterval) ;
}
}
// Analizzo i dexel della griglia 1
int tStopX = int( m_Values[1][tGrIndex1 * m_nNx[1] + tJ].size()) ;
for ( int tIntX = 0 ; tIntX < tStopX ; ++ tIntX) {
// Estremi del segmento del dexel lungo X
double dXmin = m_Values[1][tGrIndex1 * m_nNx[1] + tJ][tIntX].dMin ;
double dXmax = m_Values[1][tGrIndex1 * m_nNx[1] + tJ][tIntX].dMax ;
// Se i segmenti si incrociano e il nuovo trovato non
// ha già un indice assegnato, assegno l'indice e
// aggiungo l'intervallo trovato allo stack.
if ( dXmin - 2 * EPS_SMALL < dX &&
dXmax + 2 * EPS_SMALL > dX &&
m_Values[1][tGrIndex1 * m_nNx[1] + tJ][tIntX].nCompo == 0) {
m_Values[1][tGrIndex1 * m_nNx[1] + tJ][tIntX].nCompo = m_Values[2][tDex][tInt].nCompo ;
IntervalIndexes NewInterval ;
NewInterval.tMap = 1 ;
NewInterval.tDex = tGrIndex1 * m_nNx[1] + tJ ;
NewInterval.tInt = tIntX ;
IntCont.push( NewInterval) ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::ExpandFromZInterval( IntContainer& IntCont)
{
// Copio i dati dell'intervallo corrente
IntervalIndexes CurrInterval = IntCont.top() ;
IntCont.pop() ;
int tDex = CurrInterval.tDex ;
int tGrIndex1 = CurrInterval.tDex % m_nNx[0] ;
int tGrIndex2 = CurrInterval.tDex / m_nNx[0] ;
int tInt = CurrInterval.tInt ;
// Quote estreme del segmento lungo Z
double dMinZ = m_Values[0][tDex][tInt].dMin ;
double dMaxZ = m_Values[0][tDex][tInt].dMax ;
double dMinDZ = max( floor( ( dMinZ - 2 * EPS_SMALL) / m_dStep - 0.5), 0.) ;
double dMaxDZ = max( floor( ( dMaxZ + 2 * EPS_SMALL) / m_dStep - 0.5), 0.) ;
// Indici estremi dei dexel ortogonali
// che possono intersecare il segmento di partenza
int tStartK = min( int( dMinDZ), ( m_nNy[1] - 1)) ;
int tStopK = min( int( dMaxDZ), ( m_nNy[1] - 1)) ;
// Posizione XY del dexel
double dX = ( tGrIndex1 + 0.5) * m_dStep ;
double dY = ( tGrIndex2 + 0.5) * m_dStep ;
// Ciclo sugli indici dei dexel che potrebbero
// intersecare il segmento di partenza
for ( int tK = tStartK ; tK <= tStopK ; ++ tK) {
// Analizzo i dexel della griglia 1.
int tStopX = int( m_Values[1][tK * m_nNx[1] + tGrIndex2].size()) ;
for ( int tIntX = 0 ; tIntX < tStopX ; ++ tIntX) {
// Estremi del segmento del dexel lungo X
double dXmin = m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].dMin ;
double dXmax = m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].dMax ;
// Se i segmenti si incrociano e il nuovo trovato non
// ha già un indice assegnato, assegno l'indice e
// aggiungo l'intervallo trovato allo stack.
if ( dXmin - 2 * EPS_SMALL < dX &&
dXmax + 2 * EPS_SMALL > dX &&
m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].nCompo == 0) {
m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].nCompo = m_Values[0][tDex][tInt].nCompo ;
IntervalIndexes NewInterval ;
NewInterval.tMap = 1 ;
NewInterval.tDex = tK * m_nNx[1] + tGrIndex2 ;
NewInterval.tInt = tIntX ;
IntCont.push( NewInterval) ;
}
}
// Analizzo i dexel della griglia 2
int tStopY = int( m_Values[2][tGrIndex1 * m_nNx[2] + tK].size()) ;
for ( int tIntY = 0 ; tIntY < tStopY ; ++ tIntY) {
// Estremi del segmento del dexel lungo Y
double dYmin = m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].dMin ;
double dYmax = m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].dMax ;
// Se i segmenti si incrociano e il nuovo trovato non
// ha già un indice assegnato, assegno l'indice e
// aggiungo l'intervallo trovato allo stack.
if ( dYmin - 2 * EPS_SMALL < dY &&
dYmax + 2 * EPS_SMALL > dY &&
m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].nCompo == 0) {
m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].nCompo = m_Values[0][tDex][tInt].nCompo ;
IntervalIndexes NewInterval ;
NewInterval.tMap = 2 ;
NewInterval.tDex = tGrIndex1 * m_nNx[2] + tK ;
NewInterval.tInt = tIntY ;
IntCont.push( NewInterval) ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::FirstExpansionFromZ( int nNumThread, IntervalIndexes IntSt, IntContainerVec& IntervalsToProcessStackVec)
{
int tDex = IntSt.tDex ;
int tGrIndex1 = IntSt.tDex % m_nNx[0] ;
int tGrIndex2 = IntSt.tDex / m_nNx[0] ;
int tInt = IntSt.tInt ;
// Quote estreme del segmento lungo Z
double dMinZ = m_Values[0][tDex][tInt].dMin ;
double dMaxZ = m_Values[0][tDex][tInt].dMax ;
double dMinDZ = max( floor( ( dMinZ - 2 * EPS_SMALL) / m_dStep - 0.5), 0.) ;
double dMaxDZ = max( floor( ( dMaxZ + 2 * EPS_SMALL) / m_dStep - 0.5), 0.) ;
// Indici estremi dei dexel ortogonali
// che possono intersecare il segmento di partenza
int tStartK = min( int( dMinDZ), ( m_nNy[1] - 1)) ;
int tStopK = min( int( dMaxDZ), ( m_nNy[1] - 1)) ;
// Posizione XY del dexel
double dX = ( tGrIndex1 + 0.5) * m_dStep ;
double dY = ( tGrIndex2 + 0.5) * m_dStep ;
// Ciclo sugli indici dei dexel che potrebbero
// intersecare il segmento di partenza
int nCurStack = 0 ;
for ( int tK = tStartK ; tK <= tStopK ; ++ tK) {
// Analizzo i dexel della griglia 1.
int tStopX = int( m_Values[1][tK * m_nNx[1] + tGrIndex2].size()) ;
for ( int tIntX = 0 ; tIntX < tStopX ; ++ tIntX) {
// Estremi del segmento del dexel lungo X
double dXmin = m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].dMin ;
double dXmax = m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].dMax ;
// Se i segmenti si incrociano e il nuovo trovato non
// ha già un indice assegnato, assegno l'indice e
// aggiungo l'intervallo trovato allo stack.
if ( dXmin - 2 * EPS_SMALL < dX &&
dXmax + 2 * EPS_SMALL > dX &&
m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].nCompo == 0) {
m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].nCompo = m_Values[0][tDex][tInt].nCompo ;
IntervalIndexes NewInterval ;
NewInterval.tMap = 1 ;
NewInterval.tDex = tK * m_nNx[1] + tGrIndex2 ;
NewInterval.tInt = tIntX ;
IntervalsToProcessStackVec[nCurStack].push( NewInterval) ;
nCurStack = ( ++ nCurStack) % int( IntervalsToProcessStackVec.size()) ;
}
}
// Analizzo i dexel della griglia 2
int tStopY = int( m_Values[2][tGrIndex1 * m_nNx[2] + tK].size()) ;
for ( int tIntY = 0 ; tIntY < tStopY ; ++ tIntY) {
// Estremi del segmento del dexel lungo Y
double dYmin = m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].dMin ;
double dYmax = m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].dMax ;
// Se i segmenti si incrociano e il nuovo trovato non
// ha già un indice assegnato, assegno l'indice e
// aggiungo l'intervallo trovato allo stack.
if ( dYmin - 2 * EPS_SMALL < dY &&
dYmax + 2 * EPS_SMALL > dY &&
m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].nCompo == 0) {
m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].nCompo = m_Values[0][tDex][tInt].nCompo ;
IntervalIndexes NewInterval ;
NewInterval.tMap = 2 ;
NewInterval.tDex = tGrIndex1 * m_nNx[2] + tK ;
NewInterval.tInt = tIntY ;
IntervalsToProcessStackVec[nCurStack].push( NewInterval) ;
nCurStack = ( ++ nCurStack) % int( IntervalsToProcessStackVec.size()) ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::ProcessIntervals( IntContainer& IntervalsToProcess)
{
// Processo gli intervalli trovati
while ( ! IntervalsToProcess.empty()) {
switch ( IntervalsToProcess.top().tMap) {
case 0:
ExpandFromZInterval( IntervalsToProcess) ;
break ;
case 1:
ExpandFromXInterval( IntervalsToProcess) ;
break ;
case 2:
ExpandFromYInterval( IntervalsToProcess) ;
break ;
}
}
return true ;
}
//----------------------------------------------------------------------------
VolZmap*
VolZmap::ClonePart( int nPart) const
{
// verifico lo stato
if ( m_nStatus != OK)
return nullptr ;
// Se è definita una sola griglia non sono definibili le parti, errore
if ( m_nMapNum == 1)
return nullptr ;
// Se è richiesta una componente fuori intervallo, errore
if ( nPart < 0 || nPart >= m_nConnectedCompoCount)
return nullptr ;
// Se il numero di componenti è indefinito, lo ricalcolo.
if ( m_nConnectedCompoCount == - 1)
const_cast<VolZmap*>(this)->CheckMapConnection() ;
// Se non vi sono componenti, errore
if ( m_nConnectedCompoCount == 0)
return nullptr ;
// Creo nuovo oggetto Zmap
PtrOwner<VolZmap> pVolume( CreateBasicVolZmap()) ;
if ( IsNull( pVolume))
return nullptr ;
// Setto per il nuovo Zmap le seguenti variabili
pVolume->m_nConnectedCompoCount = 1 ;
pVolume->m_dStep = m_dStep ;
pVolume->m_nMapNum = m_nMapNum ;
// Minimi e massimi indici i,j della componente per le tre griglie
int nMinIndI[N_MAPS] ;
int nMaxIndI[N_MAPS] ;
int nMinIndJ[N_MAPS] ;
int nMaxIndJ[N_MAPS] ;
// Coordinate dell'origine del sistema di riferimento
// del nuovo Zmap
double dNewOx, dNewOy, dNewOz ;
// Ciclo sulle mappe
for ( int nMap = 0 ; nMap < int( m_nMapNum) ; ++ nMap) {
nMinIndI[nMap] = m_nNx[nMap] ;
nMinIndJ[nMap] = m_nNy[nMap] ;
nMaxIndI[nMap] = 0 ;
nMaxIndJ[nMap] = 0 ;
pVolume->m_dMinZ[nMap] = m_dMaxZ[nMap] ;
pVolume->m_dMaxZ[nMap] = m_dMinZ[nMap] ;
// Della componente connessa in questione calcolo indici i e j massimi e minimi.
// Inoltre cerco la minima e massima Z.
for ( int nIndI = 0 ; nIndI < int( m_nNx[nMap]) ; ++ nIndI) {
for ( int nIndJ = 0 ; nIndJ < int( m_nNy[nMap]) ; ++ nIndJ) {
int nDex = nIndJ * m_nNx[nMap] + nIndI ;
for ( int nInt = 0 ; nInt < int( m_Values[nMap][nDex].size()) ; ++ nInt) {
if ( m_Values[nMap][nDex][nInt].nCompo == nPart + 1) {
if ( nIndI < nMinIndI[nMap])
nMinIndI[nMap] = nIndI ;
if ( nIndJ < nMinIndJ[nMap])
nMinIndJ[nMap] = nIndJ ;
if ( nIndI > nMaxIndI[nMap])
nMaxIndI[nMap] = nIndI ;
if ( nIndJ > nMaxIndJ[nMap])
nMaxIndJ[nMap] = nIndJ ;
if ( m_Values[nMap][nDex][nInt].dMin < pVolume->m_dMinZ[nMap])
pVolume->m_dMinZ[nMap] = m_Values[nMap][nDex][nInt].dMin ;
if ( m_Values[nMap][nDex][nInt].dMax > pVolume->m_dMaxZ[nMap])
pVolume->m_dMaxZ[nMap] = m_Values[nMap][nDex][nInt].dMax ;
}
}
}
}
}
for ( int nMap = 0 ; nMap < int( m_nMapNum) ; ++ nMap) {
if ( nMinIndI[nMap] > 0)
-- nMinIndI[nMap] ;
if ( nMaxIndI[nMap] < int( m_nNx[nMap]) - 1)
++ nMaxIndI[nMap] ;
if ( nMinIndJ[nMap] > 0)
-- nMinIndJ[nMap] ;
if ( nMaxIndJ[nMap] < int( m_nNy[nMap]) - 1)
++ nMaxIndJ[nMap] ;
pVolume->m_nNx[nMap] = max( 0, nMaxIndI[nMap] - nMinIndI[nMap] + 1) ;
pVolume->m_nNy[nMap] = max( 0, nMaxIndJ[nMap] - nMinIndJ[nMap] + 1) ;
pVolume->m_nDim[nMap] = pVolume->m_nNx[nMap] * pVolume->m_nNy[nMap] ;
pVolume->m_Values[nMap].resize( pVolume->m_nDim[nMap]) ;
}
// Se almeno una griglia è nulla, non ha senso Zmap
if ( pVolume->m_nDim[0] == 0 ||
pVolume->m_nDim[1] == 0 ||
pVolume->m_nDim[2] == 0)
return nullptr ;
// Copio gli intervalli nelle griglie del nuovo oggetto:
// Griglia 0
for ( int nIndJ = 0 ; nIndJ < int( pVolume->m_nNy[0]) ; ++ nIndJ) {
for ( int nIndI = 0 ; nIndI < int( pVolume->m_nNx[0]) ; ++ nIndI) {
int nNewDex = nIndJ * pVolume->m_nNx[0] + nIndI ;
int nOldDex = ( nIndJ + nMinIndJ[0]) * m_nNx[0] + nIndI + nMinIndI[0] ;
for ( int nInt = 0 ; nInt < int( m_Values[0][nOldDex].size()) ; ++ nInt) {
if ( m_Values[0][nOldDex][nInt].nCompo == nPart + 1) {
pVolume->m_Values[0][nNewDex].emplace_back( m_Values[0][nOldDex][nInt]) ;
pVolume->m_Values[0][nNewDex].back().nCompo = 1 ;
}
}
}
}
// Griglia 1
for ( int nIndJ = 0 ; nIndJ < int( pVolume->m_nNy[1]) ; ++ nIndJ) {
for ( int nIndI = 0 ; nIndI < int( pVolume->m_nNx[1]) ; ++ nIndI) {
int nNewDex = nIndJ * pVolume->m_nNx[1] + nIndI ;
int nOldDex = ( nIndJ + nMinIndJ[1]) * m_nNx[1] + nIndI + nMinIndI[1] ;
for ( int nInt = 0 ; nInt < int( m_Values[1][nOldDex].size()) ; ++ nInt) {
if ( m_Values[1][nOldDex][nInt].nCompo == nPart + 1) {
pVolume->m_Values[1][nNewDex].emplace_back( m_Values[1][nOldDex][nInt]) ;
pVolume->m_Values[1][nNewDex].back().nCompo = 1 ;
}
}
}
}
// Griglia 2
for ( int nIndJ = 0 ; nIndJ < int( pVolume->m_nNy[2]) ; ++ nIndJ) {
for ( int nIndI = 0 ; nIndI < int( pVolume->m_nNx[2]) ; ++ nIndI) {
int nNewDex = nIndJ * pVolume->m_nNx[2] + nIndI ;
int nOldDex = ( nIndJ + nMinIndJ[2]) * m_nNx[2] + nIndI + nMinIndI[2] ;
for ( int nInt = 0 ; nInt < int( m_Values[2][nOldDex].size()) ; ++ nInt) {
if ( m_Values[2][nOldDex][nInt].nCompo == nPart + 1) {
pVolume->m_Values[2][nNewDex].emplace_back( m_Values[2][nOldDex][nInt]) ;
pVolume->m_Values[2][nNewDex].back().nCompo = 1 ;
}
}
}
}
// Coordinate x,y dell'origine del sistema di riferimento
dNewOx = nMinIndI[0] * m_dStep ;
dNewOy = nMinIndJ[0] * m_dStep ;
dNewOz = nMinIndJ[1] * m_dStep ;
// Porto i dexel nel nuovo sistema di riferimento e le quote estreme Z. Non c'è bisogno di trasformare le normali,
// infatti i sistemi di riferimento in gioco differiscono al più per una traslazione.
for ( int nMap = 0 ; nMap < int( m_nMapNum) ; ++ nMap) {
// Quote estreme Z
switch ( nMap) {
case 0 :
pVolume->m_dMinZ[nMap] -= dNewOz ;
pVolume->m_dMaxZ[nMap] -= dNewOz ;
break ;
case 1 :
pVolume->m_dMinZ[nMap] -= dNewOx ;
pVolume->m_dMaxZ[nMap] -= dNewOx ;
break ;
case 2 :
pVolume->m_dMinZ[nMap] -= dNewOy ;
pVolume->m_dMaxZ[nMap] -= dNewOy ;
break ;
}
// Dexel
for ( int nDex = 0 ; nDex < int( pVolume->m_nDim[nMap]) ; ++ nDex) {
for ( int nInt = 0 ; nInt < int( pVolume->m_Values[nMap][nDex].size()) ; ++ nInt) {
switch ( nMap) {
case 0 :
pVolume->m_Values[nMap][nDex][nInt].dMin -= dNewOz ;
pVolume->m_Values[nMap][nDex][nInt].dMax -= dNewOz ;
break ;
case 1 :
pVolume->m_Values[nMap][nDex][nInt].dMin -= dNewOx ;
pVolume->m_Values[nMap][nDex][nInt].dMax -= dNewOx ;
break ;
case 2 :
pVolume->m_Values[nMap][nDex][nInt].dMin -= dNewOy ;
pVolume->m_Values[nMap][nDex][nInt].dMax -= dNewOy ;
break ;
}
}
}
}
// Definisco il numero di blocchi lungo x,y e z
if ( ! pVolume->CalcBlockNum())
return nullptr ;
// Sistema di riferimento intrinseco del nuovo solido
Point3d ptNewO = m_MapFrame.Orig() + Vector3d( dNewOx, dNewOy, dNewOz) ;
pVolume->m_MapFrame.Set( ptNewO, X_AX, Y_AX, Z_AX) ;
// Determino la forma
pVolume->m_nShape = ( pVolume->IsBox() ? BOX : GENERIC) ;
// Setto lo stato del nuovo Solido
pVolume->m_nStatus = m_nStatus ;
// Restituisco il nuovo solido
return Release( pVolume) ;
}
//----------------------------------------------------------------------------
bool
VolZmap::RemovePart( int nPart)
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// Se è definita una sola griglia non sono definibili le parti, errore
if ( m_nMapNum == 1)
return false ;
// Se il numero di componenti è indefinito, lo ricalcolo
if ( m_nConnectedCompoCount == - 1)
CheckMapConnection() ;
// Se non vi sono componenti, abbiamo finito
if ( m_nConnectedCompoCount == 0)
return true ;
// Elimino i segmenti con indice nPart + 1 e aggiorno quelli con indice superiore
// Ciclo sulle mappe.
for ( int nMap = 0 ; nMap < m_nMapNum ; ++ nMap) {
// Ciclo sui dexel della mappa.
for ( int nDex = 0 ; nDex < int( m_Values[nMap].size()) ; ++ nDex) {
// Ciclo sugli intervalli del dexel.
for ( int nInt = 0 ; nInt < int( m_Values[nMap][nDex].size()) ; ++ nInt) {
// Se l'intervallo appartiene alla componente da eliminare, lo cancello.
if ( m_Values[nMap][nDex][nInt].nCompo == nPart + 1) {
SetToModifyDexelBlocks( nMap, nDex, nInt) ;
m_Values[nMap][nDex].erase( m_Values[nMap][nDex].begin() + nInt) ;
-- nInt ;
}
else if ( m_Values[nMap][nDex][nInt].nCompo > nPart + 1)
m_Values[nMap][nDex][nInt].nCompo -= 1 ;
}
}
}
// Decremento il numero di componenti.
m_nConnectedCompoCount -= 1 ;
// Imposto ricalcolo grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
int
VolZmap::GetPartMinDistFromPoint( const Point3d& ptP) const
{
// Verifico lo stato e che siano definibili le componenti connesse
if ( m_nStatus != OK || m_nMapNum == 1)
return - 1 ;
// Se il numero di componenti è indefinito, lo ricalcolo
if ( m_nConnectedCompoCount == -1)
const_cast<VolZmap*>( this)->CheckMapConnection() ;
// Se non vi sono componenti, abbiamo finito
if ( m_nConnectedCompoCount == 0)
return - 1 ;
// Porto il punto nel riferimento intrinseco
Point3d ptPL = ptP ;
ptPL.ToLoc( m_MapFrame) ;
// Trovo la componente connessa di minima distanza dal punto
double dMinDist = DBL_MAX ;
int nMinDistPart = - 1 ;
for ( int nMap = 0 ; nMap < m_nMapNum ; ++ nMap) {
for ( int nDex = 0 ; nDex < m_nDim[nMap] ; ++ nDex) {
double dX = ( ( nDex % m_nNx[nMap]) + 0.5) * m_dStep ;
double dY = ( ( nDex / m_nNx[nMap]) + 0.5) * m_dStep ;
int nIntervalNum = int( m_Values[nMap][nDex].size()) ;
for ( int nInt = 0 ; nInt < nIntervalNum ; ++ nInt) {
Point3d ptSt( dX, dY, m_Values[nMap][nDex][nInt].dMin) ;
Point3d ptEn( dX, dY, m_Values[nMap][nDex][nInt].dMax) ;
// Riporto le coordinate cicliche delle normali nell'ordine di partenza (da griglia a sistema intrinseco)
if ( nMap == 1) {
swap( ptSt.x, ptSt.z) ;
swap( ptSt.y, ptSt.z) ;
swap( ptEn.x, ptEn.z) ;
swap( ptEn.y, ptEn.z) ;
}
else if ( nMap == 2) {
swap( ptSt.y, ptSt.z) ;
swap( ptSt.x, ptSt.z) ;
swap( ptEn.y, ptEn.z) ;
swap( ptEn.x, ptEn.z) ;
}
// Calcolo la distanza del punto dal segmento corrente. Se è minore della minima distanza aggiorno quest'ultima
// e la corrispondente componente connessa di minima distanza con la distanza e la componente connessa correnti.
double dDist ;
DistPointLine DistCalc( ptPL, ptSt, ptEn) ;
if ( DistCalc.GetDist( dDist) && dDist < dMinDist) {
dMinDist = dDist ;
nMinDistPart = m_Values[nMap][nDex][nInt].nCompo ;
}
}
}
}
return ( nMinDistPart - 1) ;
}
//----------------------------------------------------------------------------
bool
VolZmap::AddSurfTm( const ISurfTriMesh* pStm)
{
// controllo sulla superficie
double dVol ;
if ( pStm == nullptr || ! pStm->IsValid() || ! pStm->IsClosed() ||
! pStm->GetVolume( dVol) || dVol < 0)
return false ;
// controllo se il Box3d della superficie si interseca con il Box3d dello Zmap corrente
BBox3d BBox_stm, BBox_curr ;
if ( ! pStm->GetLocalBBox( BBox_stm) || ! GetLocalBBox( BBox_curr))
return false ;
BBox3d BBox_inters ;
if ( BBox_stm.FindIntersection( BBox_curr, BBox_inters) && BBox_inters.IsEmpty())
return true ; // se non ci sono intersezioni, la superficie non influenza lo Zmap
Vector3d vtLen = BBox_curr.GetMax() - BBox_curr.GetMin() ; // dimensione massima dello spillone
// ciclo sulle griglie
bool bCompleted = true ;
for ( int nG = 0 ; nG < m_nMapNum ; ++ nG) {
// definisco dei sistemi di riferimento ausiliari
Frame3d frMapFrame ;
if ( nG == 0)
frMapFrame = m_MapFrame ;
else if ( nG == 1)
frMapFrame.Set( m_MapFrame.Orig(), Y_AX, Z_AX, X_AX) ;
else if ( nG == 2)
frMapFrame.Set( m_MapFrame.Orig(), Z_AX, X_AX, Y_AX) ;
// oggetto per calcolo massivo intersezioni
IntersParLinesSurfTm intPLSTM( frMapFrame, *pStm) ;
// numero massimo di thread
int nThreadMax = max( 1, int( thread::hardware_concurrency()) - 1) ;
vector<future<bool>> vRes ;
vRes.resize( nThreadMax) ;
// se dimensione griglia in X maggiore di dimensione Y
if ( m_nNx[nG] > m_nNy[nG]) {
int nDexNum = m_nNx[nG] / nThreadMax ;
int nRemainder = m_nNx[nG] % nThreadMax ;
int nInfI = 0 ;
int nSupI = 0 ;
// aggiungo le parti interessate alla mappa
for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
nInfI = nSupI ;
nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
vRes[nThread] = async( launch::async, &VolZmap::AddMapPart, this, nG,
nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( m_MapFrame.Orig()),
ref( *pStm), ref( intPLSTM)) ;
}
}
// se dimensione griglia in Y maggiore di dimensione X
else {
int nDexNum = m_nNy[nG] / nThreadMax ;
int nRemainder = m_nNy[nG] % nThreadMax ;
int nInfJ = 0 ;
int nSupJ = 0 ;
// aggiungo le parti interessate alla mappa
for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
nInfJ = nSupJ ;
nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
vRes[nThread] = async( launch::async, &VolZmap::AddMapPart, this, nG,
0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( m_MapFrame.Orig()),
ref( *pStm), ref( intPLSTM)) ;
}
}
// ciclo per attendere che tutti gli async abbiano terminato.
int nTerminated = 0 ;
while ( nTerminated < nThreadMax) {
for ( int nL = 0 ; nL < nThreadMax ; ++ nL) {
// async terminato
if ( vRes[nL].valid() && vRes[nL].wait_for( chrono::microseconds{ 1}) == future_status::ready) {
++ nTerminated ;
bCompleted = bCompleted && vRes[nL].get() ;
}
}
}
if ( ! bCompleted)
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::SubtractSurfTm( const ISurfTriMesh* pStm)
{
// controllo sulla superficie
double dVol ;
if ( pStm == nullptr || ! pStm->IsValid() || ! pStm->IsClosed() ||
! pStm->GetVolume( dVol) || dVol < 0)
return false ;
// controllo se il Box3d della superficie si interseca con il Box3d dello Zmap corrente
BBox3d BBox_stm, BBox_curr ;
if ( ! pStm->GetLocalBBox( BBox_stm) || ! GetLocalBBox( BBox_curr))
return false ;
BBox3d BBox_inters ;
if ( BBox_stm.FindIntersection( BBox_curr, BBox_inters) && BBox_inters.IsEmpty())
return true ; // se non ci sono intersezioni, la superficie non influenza lo Zmap
Vector3d vtLen = BBox_curr.GetMax() - BBox_curr.GetMin() ; // dimensione massima dello spillone
// ciclo sulle griglie
bool bCompleted = true ;
for ( int nG = 0 ; nG < m_nMapNum ; ++ nG) {
// definisco dei sistemi di riferimento ausiliari
Frame3d frMapFrame ;
if ( nG == 0)
frMapFrame = m_MapFrame ;
else if ( nG == 1)
frMapFrame.Set( m_MapFrame.Orig(), Y_AX, Z_AX, X_AX) ;
else if ( nG == 2)
frMapFrame.Set( m_MapFrame.Orig(), Z_AX, X_AX, Y_AX) ;
// oggetto per calcolo massivo intersezioni
IntersParLinesSurfTm intPLSTM( frMapFrame, *pStm) ;
// numero massimo di thread
int nThreadMax = max( 1, int( thread::hardware_concurrency()) - 1) ;
vector<future<bool>> vRes ;
vRes.resize( nThreadMax) ;
// se dimensione griglia in X maggiore di dimensione Y
if ( m_nNx[nG] > m_nNy[nG]) {
int nDexNum = m_nNx[nG] / nThreadMax ;
int nRemainder = m_nNx[nG] % nThreadMax ;
int nInfI = 0 ;
int nSupI = 0 ;
// aggiungo le parti interessate alla mappa
for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
nInfI = nSupI ;
nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
vRes[nThread] = async( launch::async, &VolZmap::SubtractMapPart, this, nG,
nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( m_MapFrame.Orig()),
ref( *pStm), ref( intPLSTM)) ;
}
}
// se dimensione griglia in Y maggiore di dimensione X
else {
int nDexNum = m_nNy[nG] / nThreadMax ;
int nRemainder = m_nNy[nG] % nThreadMax ;
int nInfJ = 0 ;
int nSupJ = 0 ;
// aggiungo le parti interessate alla mappa
for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
nInfJ = nSupJ ;
nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
vRes[nThread] = async( launch::async, &VolZmap::SubtractMapPart, this, nG,
0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( m_MapFrame.Orig()),
ref( *pStm), ref( intPLSTM)) ;
}
}
// ciclo per attendere che tutti gli async abbiano terminato.
int nTerminated = 0 ;
while ( nTerminated < nThreadMax) {
for ( int nL = 0 ; nL < nThreadMax ; ++ nL) {
// async terminato
if ( vRes[nL].valid() && vRes[nL].wait_for( chrono::microseconds{ 1}) == future_status::ready) {
++ nTerminated ;
bCompleted = bCompleted && vRes[nL].get() ;
}
}
}
if ( ! bCompleted)
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::MakeUniform( double dToler, bool bIsExtensionFirst, int nToolNum)
{
// Controllo validità dello Zmap
if ( ! IsValid())
return false ;
// Creo lo ZMap per i riferimenti degli intervalli sulle griglie
PtrOwner<VolZmap> pZMapCopy( CloneBasicVolZmap( this)) ;
if ( IsNull( pZMapCopy) || ! pZMapCopy->IsValid())
return false ;
// Creo uno ZMap per gli intervalli da aggiungere o da rimuovere
PtrOwner<VolZmap> pZMapExtra( CreateBasicVolZmap()) ;
if ( IsNull( pZMapExtra) ||
! pZMapExtra->CreateEmpty( m_MapFrame.Orig(), m_dMaxZ[1] - m_dMinZ[1], m_dMaxZ[2] - m_dMinZ[2], m_dMaxZ[0] - m_dMinZ[0],
m_dStep, IsTriDexel()))
return false ;
// Dovendo effettuare estensioni, allargo gli ingobri nelle direzioni principali
m_dMinZ[0] -= dToler ;
m_dMinZ[1] -= dToler ;
m_dMinZ[2] -= dToler ;
m_dMaxZ[0] += dToler ;
m_dMaxZ[1] += dToler ;
m_dMaxZ[2] += dToler ;
// NB. Tutti i parametri sono sempre presi dalla Copia dello ZMap corrente
// Ciclo sulle griglie
for ( int nGrid = 0 ; nGrid < pZMapCopy->m_nMapNum ; ++ nGrid) {
// Ciclo sul numero di dexel presenti nella Copia
for ( int nDex = 0 ; nDex < ssize( pZMapCopy->m_Values[nGrid]) ; ++ nDex) {
// Se il dexel corrente non ha sotto-intervalli passo al successivo
if ( pZMapCopy->m_Values[nGrid][nDex].empty())
continue ;
// Indici del dexel
int nI = nDex % m_nNx[nGrid] ;
int nJ = nDex / m_nNx[nGrid] ;
// Recupero il numero di intervalli presenti nel Dexel corrente
int nIntervals = ssize( pZMapCopy->m_Values[nGrid][nDex]) ;
// Scorro gli intervalli presenti
for ( int nInfo = 0 ; nInfo < ssize( pZMapCopy->m_Values[nGrid][nDex]) ; ++ nInfo) {
// Recupero l'intervallo corrente
Data& Interval = pZMapCopy->m_Values[nGrid][nDex][nInfo] ;
// --- Se richiesta prima estensione
if ( bIsExtensionFirst) {
// *** Estremo inferiore -> Intervallo : [ dMin - dToler, dMin + dToler ]
// Aggiungo l'intervallo nello Zmap corrente ( lascio invariato lo ZMapCopy)
AddIntervals( nGrid, nI, nJ, Interval.dMin - dToler, Interval.dMin + dToler,
Interval.vtMinN, Interval.vtMinN, nToolNum, true) ;
// Se si sono uniti degli intervalli, potrei dover aggiungere degli spilloni nelle altre due direzioni
if ( IsTriDexel() && nIntervals != ssize( m_Values[nGrid][nDex])) {
// Aggiorno gli intervalli correnti ( dato che il corrente si è unito al precedente)
// ( lascio invariato lo ZMapCopy)
nIntervals = ssize( m_Values[nGrid][nDex]) ;
pZMapExtra->UniformIntervalsInVoxel( nGrid, nI, nJ,
pZMapCopy->m_Values[nGrid][nDex][nInfo-1].dMax, Interval.dMin,
dToler, true, nToolNum, V_INVALID, V_INVALID) ;
}
// *** Estremo superiore -> Intervallo : [ dMax - dToler, dMax + dToler ]
// Aggiungo l'intervallo nello Zmap corrente ( lascio invariato lo ZMapCopy)
AddIntervals( nGrid, nI, nJ, Interval.dMax - dToler, Interval.dMax + dToler,
Interval.vtMaxN, Interval.vtMaxN, nToolNum, true) ;
// Se si sono uniti degli intervalli, potrei dover aggiungere degli spilloni nelle altre due direzioni
if ( IsTriDexel() && nIntervals != ssize( m_Values[nGrid][nDex])) {
// Aggiorno gli intervalli correnti ( dato che il corrente si è unito al successivo)
// ( lascio invariato lo ZMapCopy)
nIntervals = ssize( m_Values[nGrid][nDex]) ;
pZMapExtra->UniformIntervalsInVoxel( nGrid, nI, nJ,
Interval.dMax, pZMapCopy->m_Values[nGrid][nDex][nInfo+1].dMin,
dToler, true, nToolNum, V_INVALID, V_INVALID) ;
}
}
// --- Se richiesta prima restrizione
else {
// Se la lunghezza dell'intervallo non è almeno il doppio della tolleranza
double dLen = Interval.dMax - Interval.dMin ;
if ( dLen < 2. * ( dToler + EPS_SMALL)) {
// L'intervallo sparisce completamente
SubtractIntervals( nGrid, nI, nJ, Interval.dMin - EPS_SMALL, Interval.dMax + EPS_SMALL,
Interval.vtMinN, Interval.vtMaxN, nToolNum, true) ;
// Rimuovo le parti di spillone nelle altre dimensioni
if ( IsTriDexel()) {
-- nIntervals ;
pZMapExtra->UniformIntervalsInVoxel( nGrid, nI, nJ,
Interval.dMin, Interval.dMax,
dToler, true, Tool::UNDEF, V_INVALID, V_INVALID) ;
}
}
// Se sufficientemente lungo, allora
else {
// *** Estremo inferiore -> Intervallo : [ dMin, dMin + dToler ]
// Sottraggo l'intervallo nello Zmap corrente ( lascio invariato lo ZMapCopy)
SubtractIntervals( nGrid, nI, nJ, Interval.dMin - EPS_SMALL, Interval.dMin + dToler,
Interval.vtMinN, Interval.vtMinN, nToolNum, true) ;
// *** Estremo superiore -> Intervallo : [ dMax - dToler, dMax ]
// Sottraggo l'intervallo nello Zmap corrente ( lascio invariato lo ZMapCopy)
SubtractIntervals( nGrid, nI, nJ, Interval.dMax - dToler, Interval.dMax + EPS_SMALL,
Interval.vtMaxN, Interval.vtMaxN, nToolNum, true) ;
}
}
}
}
}
// Ciclo sulle griglie ( uso lo Zmap Corrente, lascio invariato pZMapCopy)
for ( int nGrid = 0 ; nGrid < m_nMapNum ; ++ nGrid) {
// Ciclo sul numero di dexel presenti
for ( int nDex = 0 ; nDex < ssize( m_Values[nGrid]) ; ++ nDex) {
// Se l'intervallo è vuoto, non faccio nulla
if ( m_Values[nGrid][nDex].empty())
continue ;
// Per ogni intervallo ricavato fino ad ora, restringo della tolleranza
for ( int nInfo = 0 ; nInfo < ssize( m_Values[nGrid][nDex]) ; ++ nInfo) {
// --- Se richiesta prima estensione
if ( bIsExtensionFirst) {
m_Values[nGrid][nDex][nInfo].dMin += dToler ;
m_Values[nGrid][nDex][nInfo].dMax -= dToler ;
}
// --- Se richiesta prima restrizione
else {
m_Values[nGrid][nDex][nInfo].dMin -= dToler ;
m_Values[nGrid][nDex][nInfo].dMax += dToler ;
}
// Definisco il colore
for ( int nOrigInfo = 0 ; nOrigInfo < ssize( pZMapCopy->m_Values[nGrid][nDex]) ; ++ nOrigInfo) {
if ( pZMapCopy->m_Values[nGrid][nDex][nOrigInfo].dMin - m_Values[nGrid][nDex][nInfo].dMin < EPS_SMALL)
m_Values[nGrid][nDex][nInfo].nToolMin = pZMapCopy->m_Values[nGrid][nDex][nOrigInfo].nToolMin ;
if ( pZMapCopy->m_Values[nGrid][nDex][nOrigInfo].dMax - m_Values[nGrid][nDex][nInfo].dMax < EPS_SMALL)
m_Values[nGrid][nDex][nInfo].nToolMax = pZMapCopy->m_Values[nGrid][nDex][nOrigInfo].nToolMax ;
}
}
}
}
// Gestisco le parti Extra ricavate
// Ciclo sulle griglie ( uso lo ZmapExtra, lascio invariato pZMapCopy)
for ( int nGrid = 0 ; nGrid < pZMapExtra->m_nMapNum ; ++ nGrid) {
// Ciclo sul numero di dexel presenti
for ( int nDex = 0 ; nDex < ssize( pZMapExtra->m_Values[nGrid]) ; ++ nDex) {
// Se l'intervallo è vuoto, non faccio nulla
if ( pZMapExtra->m_Values[nGrid][nDex].empty())
continue ;
// Indici del dexel
int nI = nDex % m_nNx[nGrid] ;
int nJ = nDex / m_nNx[nGrid] ;
// Per ogni intervallo ricavato fino ad ora...
for ( int nInfo = 0 ; nInfo < ssize( pZMapExtra->m_Values[nGrid][nDex]) ; ++ nInfo) {
double dMin = pZMapExtra->m_Values[nGrid][nDex][nInfo].dMin ;
double dMax = pZMapExtra->m_Values[nGrid][nDex][nInfo].dMax ;
Vector3d vtNMin = pZMapExtra->m_Values[nGrid][nDex][nInfo].vtMinN ;
Vector3d vtNMax = pZMapExtra->m_Values[nGrid][nDex][nInfo].vtMaxN ;
// --- Se richiesta prima estensione
if ( bIsExtensionFirst) {
// Aggiungo i contributi
AddIntervals( nGrid, nI, nJ, dMin, dMax, vtNMin, vtNMax, nToolNum, true) ;
}
// --- Se richiesta prima restrizione
else {
// Sottraggo i contributi
SubtractIntervals( nGrid, nI, nJ, dMin, dMax, vtNMin, vtNMax, nToolNum, true) ;
}
}
}
}
// Restringo gli ingombri espensi in precedenza
m_dMinZ[0] += dToler ;
m_dMinZ[1] += dToler ;
m_dMinZ[2] += dToler ;
m_dMaxZ[0] -= dToler ;
m_dMaxZ[1] -= dToler ;
m_dMaxZ[2] -= dToler ;
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::RemoveFins( const Vector3d& vtDir, double dThick)
{
// Verifico la Validità dello ZMap
if ( ! IsValid())
return false ;
// Per sicurezza normalizzo la direzione
Vector3d vtMyDir = vtDir ;
if ( ! vtMyDir.Normalize())
return false ;
double dMyThick = max( 10. * EPS_SMALL, dThick) ;
// Creo lo ZMap per i riferimenti degli intervalli sulle griglie
PtrOwner<VolZmap> pZMapCopy( CloneBasicVolZmap( this)) ;
if ( IsNull( pZMapCopy) || ! pZMapCopy->IsValid())
return false ;
// Creo uno ZMap per gli intervalli da aggiungere e successivamente da rimuovere
VolZmap ZMapExtra ;
if ( ! ZMapExtra.CreateEmpty( m_MapFrame.Orig(), m_dMaxZ[1] - m_dMinZ[1], m_dMaxZ[2] - m_dMinZ[2], m_dMaxZ[0] - m_dMinZ[0],
m_dStep, IsTriDexel()))
return false ;
const double FIN_ANG_DEG_TOL = 55. ; // Approssimazione per eccesso dell'angolo massimo possibile tra una direzione generica
// e un versore della terna globale ( arccos( 1 / sqrt( 3) ~ 54.375)
const double COS_FIN_ANG_DEG_TOL = cos( FIN_ANG_DEG_TOL * DEGTORAD) ;
const int NUM_TOOL = 1000 ; // Identificativo Utensile per riconoscere le parti rimosse
// NB. Tutti i parametri sono sempre presi dalla Copia dello ZMap corrente
// Ciclo sulle griglie
DBLVECTOR vdThicks ;
if ( IsTriDexel())
vdThicks = { dThick, dThick, dThick} ;
else
vdThicks = { dThick} ;
for ( int nGrid = 0 ; nGrid < pZMapCopy->m_nMapNum ; ++ nGrid) {
// Verifico se l'angolo tra la direzione degli spilloni della griglia corrente è sotto alla tolleranza rispetto alla direzione
double dCosDir = ( nGrid == 0 ? vtMyDir.z :
( nGrid == 1 ? vtMyDir.x :
vtMyDir.y)) ;
if ( abs( dCosDir) < COS_FIN_ANG_DEG_TOL + EPS_ANG_SMALL)
continue ;
// Aggiorno l'effettivo valore dello spessore da considerare
double dCurrThick = dMyThick / abs( dCosDir) ; // (sicuramente esiste, essendo 55deg il limite)
vdThicks[nGrid] = dCurrThick ;
// Ciclo sul numero di dexel presenti nella Copia
for ( int nDex = 0 ; nDex < ssize( pZMapCopy->m_Values[nGrid]) ; ++ nDex) {
// Se il dexel corrente non ha sotto-intervalli passo al successivo
if ( pZMapCopy->m_Values[nGrid][nDex].empty())
continue ;
// Indici del dexel
int nI = nDex % m_nNx[nGrid] ;
int nJ = nDex / m_nNx[nGrid] ;
// Scorro gli intervalli presenti
for ( int nInfo = 0 ; nInfo < ssize( pZMapCopy->m_Values[nGrid][nDex]) ; ++ nInfo) {
// Recupero l'intervallo corrente
Data& Interval = pZMapCopy->m_Values[nGrid][nDex][nInfo] ;
// Se entrambi gli estremi dell'intervallo non sono stati toccati dall'utensile, allora passo al successivo
bool bAnalyze = ( ( Interval.nToolMin == 1 && Interval.nToolMax == 1) ||
( Interval.dMax > m_dMaxZ[nGrid] - EPS_SMALL || Interval.dMin < m_dMinZ[nGrid] + EPS_SMALL)) ;
if ( ! bAnalyze)
continue ;
// Se la lunghezza dell'intervallo è superiore allo spessore richiesto, non faccio nulla
double dLen = Interval.dMax - Interval.dMin ;
if ( dLen > dCurrThick + EPS_ZERO)
continue ;
// Se ZMap composto da una sola griglia, elimino il contributo lungo la direzione corrente
if ( ! IsTriDexel()) {
SubtractIntervals( nGrid, nI, nJ, Interval.dMin - EPS_SMALL, Interval.dMax + EPS_SMALL,
- Interval.vtMinN, - Interval.vtMaxN, NUM_TOOL, true) ;
}
// Se Tridexel, aggiungo il contributo del cubetto corrente allo ZMap Extra
else
ZMapExtra.AddStripInterval( nGrid, nI, nJ, Interval.dMin - EPS_SMALL, Interval.dMax + EPS_SMALL, NUM_TOOL) ;
}
}
}
// Se non ho aggiunto alcun elemento allo ZMap Extra, non devo fare nulla
if ( ! ZMapExtra.IsValid())
return true ;
#if DEBUG_REMOVE_FINS
SaveGeoObj( ZMapExtra.Clone(), "C:\\Temp\\VolZMapSubt0.nge") ;
#endif
// Ciclo sulle griglie dello ZMap Extra
for ( int nGrid = 0 ; nGrid < ZMapExtra.m_nMapNum ; ++ nGrid) {
// Ciclo sul numero di dexel presenti
for ( int nDex = 0 ; nDex < ssize( ZMapExtra.m_Values[nGrid]) ; ++ nDex) {
// Se l'intervallo è vuoto, non faccio nulla
if ( ZMapExtra.m_Values[nGrid][nDex].empty())
continue ;
// Indici del dexel
int nI = nDex % m_nNx[nGrid] ;
int nJ = nDex / m_nNx[nGrid] ;
// Scorro i gli Intervalli dello Spillone corrente
for ( int nInfo = 0 ; nInfo < ssize( ZMapExtra.m_Values[nGrid][nDex]) ; ++ nInfo) {
double dMin = ZMapExtra.m_Values[nGrid][nDex][nInfo].dMin ;
double dMax = ZMapExtra.m_Values[nGrid][nDex][nInfo].dMax ;
Vector3d vtNMin = ZMapExtra.m_Values[nGrid][nDex][nInfo].vtMinN ;
Vector3d vtNMax = ZMapExtra.m_Values[nGrid][nDex][nInfo].vtMaxN ;
// sottraggo tali contributi
SubtractIntervals( nGrid, nI, nJ, dMin, dMax, - vtNMin, - vtNMax, NUM_TOOL, true) ;
}
}
}
if ( ! IsValid())
return true ;
#if DEBUG_REMOVE_FINS
SaveGeoObj( this->Clone(), "C:\\Temp\\VolZMapSubt1.nge") ;
#endif
// Sistemo le Normali sullo ZMap ricavato
for ( int nGrid = 0 ; nGrid < m_nMapNum ; ++ nGrid) {
// Ciclo sul numero di dexel presenti
for ( int nDex = 0 ; nDex < ssize( m_Values[nGrid]) ; ++ nDex) {
// Se l'Intervallo è vuoto non faccio nulla
if ( m_Values[nGrid][nDex].empty())
continue ;
// Indici del dexel
int nI = nDex % m_nNx[nGrid] ;
int nJ = nDex / m_nNx[nGrid] ;
// Scorro gli intervalli dello spillone corrente
for ( int nInfo = 0 ; nInfo < ssize( m_Values[nGrid][nDex]) ; ++ nInfo) {
// Se intervallo con estremo minimo derivante dalla sottrazione con ZMapExtra, medio le normali
int nToolMin = m_Values[nGrid][nDex][nInfo].nToolMin ;
if ( nToolMin == NUM_TOOL) {
// Recupero il valore minimo, se sul bordo dello ZMap corrente non faccio nulla
double dMin = m_Values[nGrid][nDex][nInfo].dMin ;
if ( dMin > m_dMinZ[nGrid] + EPS_SMALL) {
Vector3d vtMinN = V_NULL ;
double dZMin = INFINITO ;
if ( ! pZMapCopy->ComputePointAndNormalForRemovingFins( nGrid, nI, nJ, dMin, vtMyDir, dThick, true, 1, vtMinN, dZMin)) {
vtMinN = - ( nGrid == 0 ? m_MapFrame.VersZ() : nGrid == 1 ? m_MapFrame.VersX() : m_MapFrame.VersY()) ;
dZMin = dMin ;
}
m_Values[nGrid][nDex][nInfo].vtMinN = vtMinN ;
m_Values[nGrid][nDex][nInfo].dMin = dZMin ;
}
}
// Se intervallo con estremo massimo derivante dalla sottrazione con ZMapExtra, medio le normali
int nToolMax = m_Values[nGrid][nDex][nInfo].nToolMax ;
if ( nToolMax == NUM_TOOL) {
// Recupero il valore massimo, se sul bordo dello ZMap corrente non faccio nulla
double dMax = m_Values[nGrid][nDex][nInfo].dMax ;
if ( dMax < m_dMaxZ[nGrid] - EPS_SMALL) {
Vector3d vtMaxN = V_NULL ;
double dZMax = INFINITO ;
if ( ! pZMapCopy->ComputePointAndNormalForRemovingFins( nGrid, nI, nJ, dMax, vtMyDir, dThick, false, 1, vtMaxN, dZMax)) {
vtMaxN = ( nGrid == 0 ? m_MapFrame.VersZ() : nGrid == 1 ? m_MapFrame.VersX() : m_MapFrame.VersY()) ;
dZMax = dMax ;
}
m_Values[nGrid][nDex][nInfo].vtMaxN = vtMaxN ;
m_Values[nGrid][nDex][nInfo].dMax = dZMax ;
}
}
}
}
}
// Riassegno il Tool dell'utensile alle nuove parti
for ( int nGrid = 0 ; nGrid < m_nMapNum ; ++ nGrid) {
// Ciclo sul numero di dexel presenti
for ( int nDex = 0 ; nDex < ssize( m_Values[nGrid]) ; ++ nDex) {
// Se l'Intervallo è vuoto non faccio nulla
if ( m_Values[nGrid][nDex].empty())
continue ;
// Scorro gli intervalli dello spillone corrente
for ( int nInfo = 0 ; nInfo < ssize( m_Values[nGrid][nDex]) ; ++ nInfo) {
if ( m_Values[nGrid][nDex][nInfo].nToolMin == NUM_TOOL)
m_Values[nGrid][nDex][nInfo].nToolMin = 1 ;
if ( m_Values[nGrid][nDex][nInfo].nToolMax == NUM_TOOL)
m_Values[nGrid][nDex][nInfo].nToolMax = 1 ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::SetToModifyDexelBlocks( int nGrid, int nDex, int nInt)
{
// Controllo sulla validità della griglia
if ( nGrid < 0 || nGrid > 2)
return false ;
// Controllo sulla validità del dexel
if ( nDex <= - 1 || nDex >= int( m_Values[nGrid].size()))
return false ;
// Controllo sulla validità dell'intervallo
if ( nInt <= - 1 || nInt >= int( m_Values[nGrid][nDex].size()))
return false ;
// Determino quali blocchi sono stati modificati
int nLayerBlock = m_nFracLin[0] * m_nFracLin[1] ;
// Indici del dexel
int nI = nDex % m_nNx[nGrid] ;
int nJ = nDex / m_nNx[nGrid] ;
// Quote estreme del dexel
double dMin = m_Values[nGrid][nDex][nInt].dMin ;
double dMax = m_Values[nGrid][nDex][nInt].dMax ;
if ( nGrid == 0) {
int nXStop = 1 ;
int nYStop = 1 ;
int nXBlock[2] ;
int nYBlock[2] ;
// Passo dal dexel al voxel
nI /= m_nDexVoxRatio ;
nJ /= m_nDexVoxRatio ;
nXBlock[0] = min( nI / m_nVoxNumPerBlock, m_nFracLin[0] - 1) ;
nYBlock[0] = min( nJ / m_nVoxNumPerBlock, m_nFracLin[1] - 1) ;
if ( nI % N_VOXBLOCK == 0 && nXBlock[0] > 0) {
nXBlock[1] = nXBlock[0] - 1 ;
++ nXStop ;
}
if ( nJ % N_VOXBLOCK == 0 && nYBlock[0] > 0) {
nYBlock[1] = nYBlock[0] - 1 ;
++ nYStop ;
}
// Numero di voxel lungo Z
int nVoxNumZ = int( m_nNy[1] / m_nDexVoxRatio + ( m_nNy[1] % m_nDexVoxRatio == 0 ? 1 : 2)) ;
int nMinK = Clamp( int( floor( ( ( dMin - 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) - EPS_SMALL))), 0, nVoxNumZ - 2) ;
int nMaxK = Clamp( int( floor( ( ( dMax + 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) + EPS_SMALL))), 0, nVoxNumZ - 2) ;
int nMinZBlock = ( m_nMapNum == 1 ? 0 : Clamp( nMinK / int( m_nVoxNumPerBlock), 0, int( m_nFracLin[2] - 1))) ;
int nMaxZBlock = min( int( m_nFracLin[2] - 1), nMaxK / int( m_nVoxNumPerBlock)) ;
for ( int tI = 0 ; tI < nXStop ; ++ tI) {
for ( int tJ = 0 ; tJ < nYStop ; ++ tJ) {
for ( int k = nMinZBlock ; k <= nMaxZBlock ; ++ k) {
int nBlockNum = k * nLayerBlock + nYBlock[tJ] * m_nFracLin[0] + nXBlock[tI] ;
m_BlockToUpdate[nBlockNum] = true ;
}
}
}
}
else if ( nGrid == 1) {
int nYStop = 1 ;
int nZStop = 1 ;
int nYBlock[2] ;
int nZBlock[2] ;
// Passo dal dexel al voxel
nI /= m_nDexVoxRatio ;
nJ /= m_nDexVoxRatio ;
nYBlock[0] = min( nI / m_nVoxNumPerBlock, m_nFracLin[1] - 1) ;
nZBlock[0] = min( nJ / m_nVoxNumPerBlock, m_nFracLin[2] - 1) ;
if ( nI % N_VOXBLOCK == 0 && nYBlock[0] > 0) {
nYBlock[1] = nYBlock[0] - 1 ;
++ nYStop ;
}
if ( nJ % N_VOXBLOCK == 0 && nZBlock[0] > 0) {
nZBlock[1] = nZBlock[0] - 1 ;
++ nZStop ;
}
// Numero di voxel lungo X
int nVoxNumX = int( m_nNx[0] / m_nDexVoxRatio + ( m_nNx[0] % m_nDexVoxRatio == 0 ? 1 : 2)) ;
int nMinI = Clamp( int( floor( ( ( dMin - 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) - EPS_SMALL))), 0, nVoxNumX - 2) ;
int nMaxI = Clamp( int( floor( ( ( dMax + 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) + EPS_SMALL))), 0, nVoxNumX - 2) ;
int nMinXBlock = Clamp( nMinI / int( m_nVoxNumPerBlock), 0, int( m_nFracLin[0] - 1)) ;
int nMaxXBlock = min( int( m_nFracLin[0] - 1), nMaxI / int( m_nVoxNumPerBlock)) ;
for ( int tI = 0 ; tI < nYStop ; ++ tI) {
for ( int tJ = 0 ; tJ < nZStop ; ++ tJ) {
for ( int k = nMinXBlock ; k <= nMaxXBlock ; ++ k) {
int nBlockNum = nZBlock[tJ] * nLayerBlock + nYBlock[tI] * m_nFracLin[0] + k ;
m_BlockToUpdate[nBlockNum] = true ;
}
}
}
}
else if ( nGrid == 2) {
int nXStop = 1 ;
int nZStop = 1 ;
int nXBlock[2] ;
int nZBlock[2] ;
// Passo dal dexel al voxel
nI /= m_nDexVoxRatio ;
nJ /= m_nDexVoxRatio ;
nXBlock[0] = min( nJ / m_nVoxNumPerBlock, m_nFracLin[0] - 1) ;
nZBlock[0] = min( nI / m_nVoxNumPerBlock, m_nFracLin[2] - 1) ;
if ( nJ % N_VOXBLOCK == 0 && nXBlock[0] > 0) {
nXBlock[1] = nXBlock[0] - 1 ;
++ nXStop ;
}
if ( nI % N_VOXBLOCK == 0 && nZBlock[0] > 0) {
nZBlock[1] = nZBlock[0] - 1 ;
++ nZStop ;
}
// Numero di voxel lungo Y
int nVoxNumY = int( m_nNy[0] / m_nDexVoxRatio + ( m_nNy[0] % m_nDexVoxRatio == 0 ? 1 : 2)) ;
int nMinJ = Clamp( int( floor( ( ( dMin - 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) - EPS_SMALL))), 0, nVoxNumY - 2) ;
int nMaxJ = Clamp( int( floor( ( ( dMax + 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) + EPS_SMALL))), 0, nVoxNumY - 2) ;
int nMinYBlock = Clamp( nMinJ / int( m_nVoxNumPerBlock), 0, int( m_nFracLin[1] - 1)) ;
int nMaxYBlock = min( int( m_nFracLin[1] - 1), nMaxJ / int( m_nVoxNumPerBlock)) ;
for ( int tI = 0 ; tI < nZStop ; ++ tI) {
for ( int tJ = 0 ; tJ < nXStop ; ++ tJ) {
for ( int k = nMinYBlock ; k <= nMaxYBlock ; ++ k) {
int nBlockNum = nZBlock[tI] * nLayerBlock + k * m_nFracLin[0] + nXBlock[tJ] ;
m_BlockToUpdate[nBlockNum] = true ;
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::IsMapPartABox( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, double& dMinZ, double& dMaxZ)
{
dMinZ = m_dMaxZ[nMap] ;
dMaxZ = m_dMinZ[nMap] ;
for ( int i = nInfI ; i < nSupI ; ++ i) {
for ( int j = nInfJ ; j < nSupJ ; ++ j) {
int n = j * m_nNx[nMap] + i ;
int nSize = int( m_Values[nMap][n].size()) ;
if ( nSize > 1)
return false ;
else if ( nSize > 0) {
if ( dMinZ > dMaxZ) {
dMinZ = m_Values[nMap][n][0].dMin ;
dMaxZ = m_Values[nMap][n][0].dMax ;
}
else {
if ( abs( m_Values[nMap][n][0].dMin - dMinZ) > EPS_SMALL ||
abs( m_Values[nMap][n][0].dMax - dMaxZ) > EPS_SMALL)
return false ;
}
}
}
}
return ( dMaxZ >= dMinZ) ;
}
//----------------------------------------------------------------------------
bool
VolZmap::IsBox( void)
{
// Se non tridexel, non posso stabilire con il metodo seguente se è un box
// Verifico solo che gli spilloni di una mappa o sono nulli o hanno gli stessi estremi
if ( m_nMapNum == 1)
return false ;
// Numero massimo di thread per il calcolo parallelo.
int nThreadMax = max( 1, int( thread::hardware_concurrency()) - 1) ;
// Disponibile un solo thread
if ( nThreadMax == 1) {
for ( int nMap = 0 ; nMap < m_nMapNum ; ++ nMap) {
double dMinZ, dMaxZ ;
if ( ! IsMapPartABox( nMap, 0, m_nNx[nMap], 0, m_nNy[nMap], dMinZ, dMaxZ)) {
m_bIsBox = false ;
return false ;
}
}
m_bIsBox = true ;
return true ;
}
// Caso di più thread
m_bIsBox = true ;
for ( int nMap = 0 ; nMap < m_nMapNum ; ++ nMap) {
vector< future<bool>> vRes ;
vRes.resize( nThreadMax) ;
std::vector<double> vMinZ, vMaxZ ;
vMinZ.resize( nThreadMax) ;
vMaxZ.resize( nThreadMax) ;
if ( m_nNx[nMap] > m_nNy[nMap]) {
int nDexNum = m_nNx[nMap] / nThreadMax ;
int nRemainder = m_nNx[nMap] % nThreadMax ;
int nInfI = 0 ;
int nSupI = 0 ;
for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
nInfI = nSupI ;
nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
vRes[nThread] = async( launch::async, &VolZmap::IsMapPartABox, this, nMap,
nInfI, nSupI, 0, m_nNy[nMap], ref( vMinZ[nThread]), ref( vMaxZ[nThread])) ;
}
}
else {
int nDexNum = m_nNy[nMap] / nThreadMax ;
int nRemainder = m_nNy[nMap] % nThreadMax ;
int nInfJ = 0 ;
int nSupJ = 0 ;
for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
nInfJ = nSupJ ;
nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
vRes[nThread] = async( launch::async, &VolZmap::IsMapPartABox, this, nMap,
0, m_nNx[nMap], nInfJ, nSupJ, ref(vMinZ[nThread]), ref(vMaxZ[nThread])) ;
}
}
// Ciclo per attendere che tutti gli async abbiano terminato.
int nTerminated = 0 ;
while ( nTerminated < nThreadMax) {
for ( int nL = 0 ; nL < nThreadMax ; ++ nL) {
// Async terminato
if ( vRes[nL].valid() && vRes[nL].wait_for(chrono::microseconds{ 1 }) == future_status::ready) {
++ nTerminated ;
if ( ! vRes[nL].get()) {
m_bIsBox = false ;
}
}
}
}
// Se uno dei thread trova che la sua porzione non è un box, non lo può essere il solido intero.
if ( ! m_bIsBox)
return false ;
// Controllo che gli estremi Z siano uguali.
for ( int nT = 1 ; nT < nThreadMax ; ++ nT) {
if ( abs( vMinZ[nT] - vMinZ[0]) > EPS_SMALL ||
abs( vMaxZ[nT] - vMaxZ[0]) > EPS_SMALL) {
m_bIsBox = false ;
return false ;
}
}
}
return m_bIsBox ;
}
//----------------------------------------------------------------------------
bool
VolZmap::Cut( const Plane3d& plPlane)
{
// Porto il piano nel riferimento intrinseco
Plane3d plMyPlane = plPlane ;
plMyPlane.ToLoc( m_MapFrame) ;
// Interseco lo Zmap col piano, ciclando sulle griglie
bool bModified = false ;
for ( int nMap = 0 ; nMap < int( m_nMapNum) ; ++ nMap) {
// Porto il piano nel riferimento di griglia
if ( nMap == 1) {
Frame3d frGrid ; frGrid.Set( ORIG, Y_AX, Z_AX, X_AX) ;
plMyPlane.ToLoc( frGrid) ;
}
else if (nMap == 2) {
Frame3d frGrid ; frGrid.Set( ORIG, Y_AX, Z_AX, X_AX) ;
plMyPlane.ToLoc( frGrid) ;
}
// Ciclo sui dexel della mappa
for ( int nD = 0 ; nD < int( m_Values[nMap].size()) ; ++ nD) {
// Se spillone già vuoto, passo al successivo
if ( m_Values[nMap][nD].empty())
continue ;
// Indici di spillone
int nI = nD % m_nNx[nMap] ;
int nJ = nD / m_nNx[nMap] ;
// Recupero estremi spillone
double dMin = m_Values[nMap][nD][0].dMin ;
double dMax = m_Values[nMap][nD][m_Values[nMap][nD].size() - 1].dMax ;
Point3d ptSt( ( nI + 0.5) * m_dStep, ( nJ + 0.5) * m_dStep, dMin) ;
Point3d ptEn( ( nI + 0.5) * m_dStep, ( nJ + 0.5) * m_dStep, dMax) ;
// Distanze degli estremi del segmento dal piano
double dStDist = DistPointPlane( ptSt, plMyPlane) ;
double dEnDist = DistPointPlane( ptEn, plMyPlane) ;
// Se entrambi sotto il piano
if ( dStDist < EPS_SMALL && dEnDist < EPS_SMALL)
// Non devo fare alcunché
;
// se altrimenti entrambi gli estremi sono oltre il piano
else if ( dStDist > -EPS_SMALL && dEnDist > -EPS_SMALL) {
// Si elimina tutto
SubtractIntervals( nMap, nI, nJ, dMin, dMax, V_NULL, V_NULL, 1) ;
}
// se altrimenti è da tenere il punto iniziale
else if ( dStDist < 0) {
// Si elimina la parte tra intersezione e punto finale
double dInt = dMin + ( dMax - dMin) * abs( dStDist) / ( abs( dStDist) + abs( dEnDist)) ;
SubtractIntervals( nMap, nI, nJ, dInt, dMax, plMyPlane.GetVersN(), V_NULL, 1) ;
}
// se altrimenti è da tenere il punto finale
else if (dEnDist < 0) {
// Si elimina la parte tra punto iniziale e intersezione
double dInt = dMin + ( dMax - dMin) * abs( dStDist) / ( abs( dStDist) + abs( dEnDist)) ;
SubtractIntervals( nMap, nI, nJ, dMin, dInt, V_NULL, plMyPlane.GetVersN(), 1) ;
}
}
}
if ( bModified == true) {
// Imposto forma generica
m_nShape = GENERIC ;
// Imposto ricalcolo grafica
m_OGrMgr.Reset() ;
// Imposto numero di componenti connesse da ricalcolare
m_nConnectedCompoCount = - 1 ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::Compact( void)
{
// Determino i nuovi estremi sugli indici e sulle quote Z e copio i dexel i cui indici sono compresi fra gli estremi
int nMinI[N_MAPS] ;
int nMinJ[N_MAPS] ;
int nMaxI[N_MAPS] ;
int nMaxJ[N_MAPS] ;
int nNx[N_MAPS] ;
int nNy[N_MAPS] ;
int nDim[N_MAPS] ;
double dMinZ[N_MAPS] ;
double dMaxZ[N_MAPS] ;
vector<vector<Data>> Values[N_MAPS] ;
bool bNotEmptyGrid = true ;
for ( int nMap = 0 ; nMap < int( m_nMapNum) ; ++ nMap) {
nMinI[nMap] = m_nNx[nMap] - 1 ;
nMinJ[nMap] = m_nNy[nMap] - 1 ;
nMaxI[nMap] = 0 ;
nMaxJ[nMap] = 0 ;
dMinZ[nMap] = m_dMaxZ[nMap] ;
dMaxZ[nMap] = m_dMinZ[nMap] ;
// Determino estremi degli indici e delle quote Z
for ( int nD = 0 ; nD < int( m_Values[nMap].size()) ; ++ nD) {
int nDexDim = int( m_Values[nMap][nD].size()) ;
if ( nDexDim > 0) {
int nI = nD % m_nNx[nMap] ;
int nJ = nD / m_nNx[nMap] ;
if ( nI < nMinI[nMap])
nMinI[nMap] = nI ;
if ( nJ < nMinJ[nMap])
nMinJ[nMap] = nJ ;
if ( nI > nMaxI[nMap])
nMaxI[nMap] = nI ;
if ( nJ > nMaxJ[nMap])
nMaxJ[nMap] = nJ ;
if ( m_Values[nMap][nD][0].dMin < dMinZ[nMap])
dMinZ[nMap] = m_Values[nMap][nD][0].dMin ;
if ( m_Values[nMap][nD][nDexDim - 1].dMax > dMaxZ[nMap])
dMaxZ[nMap] = m_Values[nMap][nD][nDexDim - 1].dMax ;
}
}
if ( nMinI[nMap] > nMaxI[nMap] || nMinJ[nMap] > nMaxJ[nMap]) {
bNotEmptyGrid = false ;
break ;
}
// Se necessario espando la griglia
if ( nMinI[nMap] > 0)
-- nMinI[nMap] ;
if ( nMinJ[nMap] > 0)
-- nMinJ[nMap] ;
if ( nMaxI[nMap] < int( m_nNx[nMap]) - 1)
++ nMaxI[nMap] ;
if ( nMaxJ[nMap] < int( m_nNy[nMap]) - 1)
++ nMaxJ[nMap] ;
nNx[nMap] = nMaxI[nMap] - nMinI[nMap] + 1 ;
nNy[nMap] = nMaxJ[nMap] - nMinJ[nMap] + 1 ;
nDim[nMap] = nNx[nMap] * nNy[nMap] ;
// Copio i dexel i cui indici sono compresi fra gli estremi
for ( int nD = 0 ; nD < int( m_Values[nMap].size()) ; ++ nD) {
int nI = nD % m_nNx[nMap] ;
int nJ = nD / m_nNx[nMap] ;
if ( nI >= nMinI[nMap] && nI <= nMaxI[nMap] && nJ >= nMinJ[nMap] && nJ <= nMaxJ[nMap]) {
Values[nMap].emplace_back( m_Values[nMap][nD]) ;
}
}
}
// Se non vi è materiale
if ( ! bNotEmptyGrid) {
m_nStatus = TO_VERIFY ;
m_nNumBlock = 0 ;
m_nConnectedCompoCount = 0 ;
m_nShape = GENERIC ;
for ( int i = 0 ; i < N_MAPS ; ++ i) {
m_nNx[i] = 0 ;
m_nNy[i] = 0 ;
m_nDim[i] = 0 ;
m_dMinZ[i] = 0 ;
m_dMaxZ[i] = 0 ;
m_nFracLin[i] = 0 ;
}
return true ;
}
// Coordinate x,y dell'origine del sistema di riferimento
double dNewOx = nMinI[0] * m_dStep ;
double dNewOy = nMinJ[0] * m_dStep ;
double dNewOz = nMinJ[1] * m_dStep ;
// Porto i dexel nel nuovo sistema di riferimento e le quote estreme Z. Non c'è bisogno di trasformare le normali,
// infatti i sistemi di riferimento in gioco differiscono al più per una traslazione.
for ( int nMap = 0 ; nMap < int( m_nMapNum) ; ++ nMap) {
// Quote estreme Z
switch ( nMap) {
case 0 :
dMinZ[nMap] -= dNewOz ;
dMaxZ[nMap] -= dNewOz ;
break ;
case 1 :
dMinZ[nMap] -= dNewOx ;
dMaxZ[nMap] -= dNewOx ;
break ;
case 2 :
dMinZ[nMap] -= dNewOy ;
dMaxZ[nMap] -= dNewOy ;
break ;
}
// Dexel
for ( int nD = 0 ; nD < int( nDim[nMap]) ; ++ nD) {
for ( int nS = 0 ; nS < int( Values[nMap][nD].size()) ; ++ nS) {
switch ( nMap) {
case 0 :
Values[nMap][nD][nS].dMin -= dNewOz ;
Values[nMap][nD][nS].dMax -= dNewOz ;
break ;
case 1 :
Values[nMap][nD][nS].dMin -= dNewOx ;
Values[nMap][nD][nS].dMax -= dNewOx ;
break ;
case 2 :
Values[nMap][nD][nS].dMin -= dNewOy ;
Values[nMap][nD][nS].dMax -= dNewOy ;
break ;
}
}
}
}
// Ricopio i dexel con gli indici compresi fra gli estremi
for ( int nMap = 0 ; nMap < int( m_nMapNum) ; ++ nMap) {
m_nNx[nMap] = nNx[nMap] ;
m_nNy[nMap] = nNy[nMap] ;
m_nDim[nMap] = nDim[nMap] ;
m_Values[nMap].resize( 0) ;
for ( int nD = 0 ; nD < int( Values[nMap].size()) ; ++ nD) {
m_Values[nMap].emplace_back( Values[nMap][nD]) ;
}
}
// Definisco il numero di blocchi lungo x,y e z
if ( ! CalcBlockNum())
return false ;
// Sistema di riferimento intrinseco del nuovo solido
Point3d ptNewO = m_MapFrame.Orig() + Vector3d( dNewOx, dNewOy, dNewOz) ;
m_MapFrame.Set( ptNewO, X_AX, Y_AX, Z_AX) ;
// Imposto ricalcolo grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::ChangeResolution( int nDexVoxRatio)
{
if ( nDexVoxRatio < 1 || nDexVoxRatio > 5)
return false ;
if ( nDexVoxRatio != m_nDexVoxRatio) {
int nOldDexVoxRatio = m_nDexVoxRatio ;
m_nDexVoxRatio = nDexVoxRatio ;
if ( CalcBlockNum()) {
ResetGraphics() ;
m_OGrMgr.Clear() ;
return true ;
}
m_nDexVoxRatio = nOldDexVoxRatio ;
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::CalcBlockNum( void)
{
// Calcolo il numero di voxel lungo X e Y
int nVoxNumX = m_nNx[0] / m_nDexVoxRatio + ( m_nNx[0] % m_nDexVoxRatio == 0 ? 1 : 2) ;
int nVoxNumY = m_nNy[0] / m_nDexVoxRatio + ( m_nNy[0] % m_nDexVoxRatio == 0 ? 1 : 2) ;
if ( nVoxNumX == 0 || nVoxNumY == 0)
return false ;
// Definisco il numero di blocchi lungo X e Y
m_nFracLin[0] = max( 1, nVoxNumX / m_nVoxNumPerBlock + ( nVoxNumX % m_nVoxNumPerBlock > m_nVoxNumPerBlock / 4 ? 1 : 0)) ;
m_nFracLin[1] = max( 1, nVoxNumY / m_nVoxNumPerBlock + ( nVoxNumY % m_nVoxNumPerBlock > m_nVoxNumPerBlock / 4 ? 1 : 0)) ;
if ( m_nMapNum == 1) {
m_nFracLin[2] = 1 ;
m_nNumBlock = m_nFracLin[0] * m_nFracLin[1] * m_nFracLin[2] ;
m_BlockToUpdate.clear() ;
m_BlockToUpdate.resize( m_nNumBlock, true) ;
m_BlockUpdatingCounter.clear() ;
m_BlockUpdatingCounter.resize( m_nNumBlock, 0) ;
m_SingleMapTria.resize( m_nNumBlock) ;
return true ;
}
// Calcolo il numero di voxel lungo Z
int nVoxNumZ = m_nNy[1] / m_nDexVoxRatio + ( m_nNy[1] % m_nDexVoxRatio == 0 ? 1 : 2) ;
// Definisco il numero di blocchi lungo Z
m_nFracLin[2] = max( 1, nVoxNumZ / m_nVoxNumPerBlock + ( nVoxNumZ % m_nVoxNumPerBlock > m_nVoxNumPerBlock / 4 ? 1 : 0)) ;
// Dimensiono e setto il vettore dei blocchi a da ricalcolare e il vettore di contatori di aggiornamenti della grafica
m_nNumBlock = m_nFracLin[0] * m_nFracLin[1] * m_nFracLin[2] ;
m_BlockToUpdate.clear() ;
m_BlockToUpdate.resize( m_nNumBlock, true) ;
m_BlockUpdatingCounter.clear() ;
m_BlockUpdatingCounter.resize( m_nNumBlock + 1, 0) ;
// Dimensiono raccolta di voxel, triangoli di feature tra blocchi e di segnalatori di materiale fra voxel
m_InterBlockVox.resize( m_nNumBlock) ;
m_InterBlockOriginalSharpTria.resize( m_nNumBlock) ;
m_InterBlockSharpTria.resize( m_nNumBlock) ;
m_BlockSharpTria.resize( m_nNumBlock) ;
m_BlockSmoothTria.resize( m_nNumBlock) ;
m_BlockBigTria.resize( m_nNumBlock) ;
m_SingleMapTria.resize( m_nNumBlock) ;
m_SliceXY.resize( m_nNumBlock) ;
m_SliceXZ.resize( m_nNumBlock) ;
m_SliceYZ.resize( m_nNumBlock) ;
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::SetToolTolerances( double dLinTol, double dAngTolDeg)
{
m_dToolLinTol = max( dLinTol, LIN_TOL_MIN) ;
m_dToolAngTolDeg = max( dAngTolDeg, ANG_TOL_MIN_DEG) ;
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::SetStdTool( const string& sToolName, double dH, double dR, double dCornR, double dCutterH, int nFlag, bool bFirst)
{
if ( bFirst) {
m_vTool.resize( 1) ;
m_vTool[0].Clear( true) ;
}
else
m_vTool.emplace_back( true) ;
m_nCurrTool = int( m_vTool.size()) - 1 ;
if ( m_nCurrTool < 0)
return false ;
m_vTool[m_nCurrTool].SetTolerances( m_dToolLinTol, m_dToolAngTolDeg) ;
return m_vTool[m_nCurrTool].SetStdTool( sToolName, dH, dR, dCornR, dCutterH, nFlag) ;
}
//----------------------------------------------------------------------------
bool
VolZmap::SetAdvTool( const string& sToolName,
double dH, double dR, double dTipH, double dTipR, double dCornR, double dCutterH, int nFlag, bool bFirst)
{
if ( bFirst) {
m_vTool.resize( 1) ;
m_vTool[0].Clear( true) ;
}
else
m_vTool.emplace_back( true) ;
m_nCurrTool = int( m_vTool.size()) - 1 ;
if ( m_nCurrTool < 0)
return false ;
m_vTool[m_nCurrTool].SetTolerances( m_dToolLinTol, m_dToolAngTolDeg) ;
return m_vTool[m_nCurrTool].SetAdvTool( sToolName, dH, dR, dTipH, dTipR, dCornR, dCutterH, nFlag) ;
}
//----------------------------------------------------------------------------
bool
VolZmap::SetSawTool( const string& sToolName,
double dH, double dR, double dThick, double dStemR, double dCornR, int nFlag, bool bFirst)
{
if ( bFirst) {
m_vTool.resize( 1) ;
m_vTool[0].Clear( true) ;
}
else
m_vTool.emplace_back( true) ;
m_nCurrTool = int( m_vTool.size()) - 1 ;
if ( m_nCurrTool < 0)
return false ;
m_vTool[m_nCurrTool].SetTolerances( m_dToolLinTol, m_dToolAngTolDeg) ;
return m_vTool[m_nCurrTool].SetSawTool( sToolName, dH, dR, dThick, dStemR, dCornR, nFlag) ;
}
//----------------------------------------------------------------------------
bool
VolZmap::SetGenTool( const string& sToolName, const ICurveComposite* pToolOutline, int nFlag, bool bFirst)
{
if ( bFirst) {
m_vTool.resize( 1) ;
m_vTool[0].Clear( true) ;
}
else
m_vTool.emplace_back( true) ;
m_nCurrTool = int( m_vTool.size()) - 1 ;
if ( m_nCurrTool < 0)
return false ;
m_vTool[m_nCurrTool].SetTolerances( m_dToolLinTol, m_dToolAngTolDeg) ;
return m_vTool[m_nCurrTool].SetGenTool( sToolName, pToolOutline, nFlag) ;
}
//----------------------------------------------------------------------------
bool
VolZmap::SetMortiserTool( const string& sToolName, double dH, double dW, double dTh, double dRc, int nFlag, bool bFirst)
{
if ( bFirst) {
m_vTool.resize( 1) ;
m_vTool[0].Clear( true) ;
}
else
m_vTool.emplace_back( true) ;
m_nCurrTool = int( m_vTool.size()) - 1 ;
if ( m_nCurrTool < 0)
return false ;
m_vTool[m_nCurrTool].SetTolerances( m_dToolLinTol, m_dToolAngTolDeg) ;
return m_vTool[m_nCurrTool].SetMortiserTool( sToolName, dH, dW, dTh, dRc, nFlag) ;
}
//----------------------------------------------------------------------------
bool
VolZmap::SetChiselTool( const string& sToolName, double dH, double dW, double dTh, int nFlag, bool bFirst)
{
if ( bFirst) {
m_vTool.resize( 1) ;
m_vTool[0].Clear( true) ;
}
else
m_vTool.emplace_back( true) ;
m_nCurrTool = int( m_vTool.size()) - 1 ;
if ( m_nCurrTool < 0)
return false ;
m_vTool[m_nCurrTool].SetTolerances( m_dToolLinTol, m_dToolAngTolDeg) ;
return m_vTool[m_nCurrTool].SetChiselTool( sToolName, dH, dW, dTh, nFlag) ;
}
//----------------------------------------------------------------------------
bool
VolZmap::SetAdditiveTool( const std::string& sToolName,
double dH, double dR, double dRc, int nFlag, bool bFirst)
{
if ( bFirst) {
m_vTool.resize( 1) ;
m_vTool[0].Clear( true) ;
}
else
m_vTool.emplace_back( true) ;
m_nCurrTool = int( m_vTool.size()) - 1 ;
if ( m_nCurrTool < 0)
return false ;
m_vTool[m_nCurrTool].SetTolerances( m_dToolLinTol, m_dToolAngTolDeg) ;
return m_vTool[m_nCurrTool].SetAdditiveTool( sToolName, dH, dR, dRc, nFlag) ;
}
//----------------------------------------------------------------------------
int
VolZmap::GetToolCount( void) const
{
return m_vTool.size() ;
}
//----------------------------------------------------------------------------
bool
VolZmap::SetCurrTool( int nCurrTool)
{
if ( nCurrTool < 0 || nCurrTool >= int( m_vTool.size()))
return false ;
m_nCurrTool = nCurrTool ;
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::ResetTools( void)
{
m_vTool.resize( 1) ;
m_nCurrTool = 0 ;
return m_vTool[0].Clear() ;
}
//----------------------------------------------------------------------------
const ICurveComposite&
VolZmap::GetToolOutline( bool bApprox) const
{
if ( m_nCurrTool < 0 || m_nCurrTool >= int( m_vTool.size())) {
static CurveComposite StatCrvCo ;
return StatCrvCo ;
}
const Tool& CurrTool = m_vTool[m_nCurrTool] ;
return ( bApprox ? CurrTool.GetApproxOutline() : CurrTool.GetOutline()) ;
}