Files
EgtGeomKernel/VolZmapCalculus.cpp
T
Dario Sassi 67cd4ef923 EgtGeomKernel :
- correzione a creazione arco con Set2PNB quando deltaN < epsilon
- dump di CurveComposite limitato a 1000 entità
- correzione in Zmap a calcolo spillone con movimento ortogonale di sfera.
2018-05-23 13:28:32 +00:00

1716 lines
63 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 "CurveLine.h"
#include "VolZmap.h"
#include "GeoConst.h"
#include "IntersLineSurfTm.h"
#include "/EgtDev/Include/EgtNumUtils.h"
#include "/EgtDev/Include/EGkIntersLineTria.h"
#include "/EgtDev/Include/EGkIntersLinePlane.h"
#include "/EgtDev/Include/EGkIntersLineSphere.h"
#include "/EgtDev/Include/EGkChainCurves.h"
using namespace std ;
//----------------------------------------------------------------------------
// Punti e vettore devono esse espressi nel medesimo sistema di riferimento.
// Il box è allineato con gli assi di tale sistema di riferimento.
// Viene restituito true in caso di intersezione, false altrimenti.
bool
VolZmap::IntersLineBox( const Point3d& ptP, const Vector3d& vtV, const Point3d& ptMin, const Point3d& ptMax) const
{
// Il box è allineato agli assi
double dU1, dU2 ;
return IntersLineBox( ptP, vtV, ptMin, ptMax, dU1, dU2) ;
}
//----------------------------------------------------------------------------
// Punti e vettore devono esse espressi nel medesimo sistema di riferimento.
// Il box è allineato con gli assi di tale sistema di riferimento.
// In dU1, dU2 vengono restituiti i parametri a cui si trovano le intersezioni.
// Viene restituito true in caso di intersezione, false altrimenti.
bool
VolZmap::IntersLineBox( const Point3d& ptP, const Vector3d& vtV,
const Point3d& ptMin, const Point3d& ptMax, double& dU1, double& dU2) const
{
// Il box è allineato agli assi
dU1 = - INFINITO ;
dU2 = INFINITO ;
// confronto con piani YZ (perpendicolari ad asse X)
if ( vtV.x > EPS_ZERO) {
dU1 = max( dU1, ( ptMin.x - ptP.x) / vtV.x) ;
dU2 = min( dU2, ( ptMax.x - ptP.x) / vtV.x) ;
}
else if ( vtV.x < - EPS_ZERO) {
dU1 = max( dU1, ( ptMax.x - ptP.x) / vtV.x) ;
dU2 = min( dU2, ( ptMin.x - ptP.x) / vtV.x) ;
}
else if ( ptP.x < ptMin.x - EPS_SMALL || ptP.x > ptMax.x + EPS_SMALL)
return false ;
// confronto con piani ZX (perpendicolari ad asse Y)
if ( vtV.y > EPS_ZERO) {
dU1 = max( dU1, ( ptMin.y - ptP.y) / vtV.y) ;
dU2 = min( dU2, ( ptMax.y - ptP.y) / vtV.y) ;
}
else if ( vtV.y < - EPS_ZERO) {
dU1 = max( dU1, ( ptMax.y - ptP.y) / vtV.y) ;
dU2 = min( dU2, ( ptMin.y - ptP.y) / vtV.y) ;
}
else if ( ptP.y < ptMin.y - EPS_SMALL || ptP.y > ptMax.y + EPS_SMALL)
return false ;
// confronto con piani XY (perpendicolari ad asse Z)
if ( vtV.z > EPS_ZERO) {
dU1 = max( dU1, ( ptMin.z - ptP.z) / vtV.z) ;
dU2 = min( dU2, ( ptMax.z - ptP.z) / vtV.z) ;
}
else if ( vtV.z < - EPS_ZERO) {
dU1 = max( dU1, ( ptMax.z - ptP.z) / vtV.z) ;
dU2 = min( dU2, ( ptMin.z - ptP.z) / vtV.z) ;
}
else if ( ptP.z < ptMin.z - EPS_SMALL || ptP.z > ptMax.z + EPS_SMALL)
return false ;
return ( dU2 >= dU1) ;
}
//----------------------------------------------------------------------------
// La retta è rappresentata da un punto e dal versore espressi nel riferimento dello Zmap.
// Se non vi è intersezione, viene restituito falso
bool
VolZmap::IntersLineZMapLattice( const Point3d& ptP, const Vector3d& vtV, double& dU1, double& dU2) const
{
// Punti estremi della diagonale del box del reticolo
Point3d ptMin( - 0.5 * m_dStep, - 0.5 * m_dStep, - 0.5 * m_dStep) ;
Point3d ptMax( ( m_nNx[0] + 0.5) * m_dStep, ( m_nNy[0] + 0.5) * m_dStep, ( m_nNy[1] + 0.5) * m_dStep) ;
return IntersLineBox( ptP, vtV, ptMin, ptMax, dU1, dU2) ;
}
//----------------------------------------------------------------------------
// Trova le intersezioni di una retta, definita tramite un suo punto e il vettore della direzione,
// e il bounding box dello Zmap. Punto e vettore devono essere espressi nel sistema di riferimento
// intrinseco dello Zmap. Se vi è intersezione viene restitutito true, false altrimenti.
// Se vi è intersezione in dU1 e dU2 vengono restituiti i parametri a cui avvengono le intersezioni.
bool
VolZmap::IntersLineZMapBBox( const Point3d& ptP, const Vector3d& vtV, double& dU1, double& dU2) const
{
// Punti estremi del box dello Zmap
Point3d ptMin = ORIG ;
Point3d ptMax = ptMin + Vector3d( m_nNx[0] * m_dStep, m_nNy[0] * m_dStep, m_dMaxZ[0]) ;
return IntersLineBox( ptP, vtV, ptMin, ptMax, dU1, dU2) ;
}
//----------------------------------------------------------------------------
// Trova le intersezioni fra una retta e un dexel parallelepipedale (gli intervalli sono
// parallelepipdi). Punto e vettore devono essere espressi nel sistema grilgia che coincide
// con quello intrinseco dello Zmap solo nel caso della prima griglia. Per le altre griglie
// è necessario permutare ciclicamente le coordinate.
bool
VolZmap::IntersLineDexel( const Point3d& ptP, const Vector3d& vtV, unsigned int nGrid, unsigned int nI, unsigned int nJ,
double& dU1, double& dU2) const
{
// Determino l'indice del dexel e il numero di suoi intervalli
unsigned int nDexelPos = nJ * m_nNx[nGrid] + nI ;
unsigned int nDexelSize = unsigned int( m_Values[nGrid][nDexelPos].size()) ;
// Se non c'è materiale non devo fare alcunché
if ( nDexelSize == 0)
return false ;
// Determino estremi nel piano XY intrinseco del dexel
double dXmin = nI * m_dStep ;
double dYmin = nJ * m_dStep ;
double dXmax = ( nI + 1) * m_dStep ;
double dYmax = ( nJ + 1) * m_dStep ;
// ciclo sugli intervalli
dU1 = INFINITO ;
dU2 = - INFINITO ;
bool bInters = false ;
for ( unsigned int nIndex = 0 ; nIndex < nDexelSize ; nIndex += 1) {
// estremi del box del singolo intervallo
Point3d ptE1( dXmin, dYmin, m_Values[nGrid][nDexelPos][nIndex].dMin) ;
Point3d ptE2( dXmax, dYmax, m_Values[nGrid][nDexelPos][nIndex].dMax) ;
double dP1, dP2 ;
if ( IntersLineBox( ptP, vtV, ptE1, ptE2, dP1, dP2)) {
bInters = true ;
dU1 = min( dU1, dP1) ;
dU2 = max( dU2, dP2) ;
}
}
return bInters ;
}
//----------------------------------------------------------------------------
// Trova le intersezioni fra una semi-retta e un dexel parallelepipedale (gli intervalli sono
// parallelepipdi). Punto e vettore devono essere espressi nel sistema grilgia che coincide
// con quello intrinseco dello Zmap solo nel caso della prima griglia. Per le altre griglie
// è necessario permutare ciclicamente le coordinate.
bool
VolZmap::IntersRayDexel( const Point3d& ptP, const Vector3d& vtV, unsigned int nGrid, unsigned int nI, unsigned int nJ,
double& dU1, double& dU2) const
{
// Determino l'indice del dexel e il numero di suoi intervalli
unsigned int nDexelPos = nJ * m_nNx[nGrid] + nI ;
unsigned int nDexelSize = unsigned int( m_Values[nGrid][nDexelPos].size()) ;
// Se non c'è materiale non devo fare alcunché
if ( nDexelSize == 0)
return false ;
// Determino estremi nel piano XY intrinseco del dexel
double dXmin = nI * m_dStep ;
double dYmin = nJ * m_dStep ;
double dXmax = ( nI + 1) * m_dStep ;
double dYmax = ( nJ + 1) * m_dStep ;
// ciclo sugli intervalli
dU1 = INFINITO ;
dU2 = - INFINITO ;
bool bInters = false ;
for ( unsigned int nIndex = 0 ; nIndex < nDexelSize ; nIndex += 1) {
// estremi del box del singolo intervallo
Point3d ptE1( dXmin, dYmin, m_Values[nGrid][nDexelPos][nIndex].dMin) ;
Point3d ptE2( dXmax, dYmax, m_Values[nGrid][nDexelPos][nIndex].dMax) ;
double dP1, dP2 ;
if ( IntersLineBox( ptP, vtV, ptE1, ptE2, dP1, dP2)) {
if ( dP2 >= 0) {
bInters = true ;
if ( dP1 >= 0)
dU1 = min( dU1, dP1) ;
else
dU1 = - 1 ;
dU2 = max( dU2, dP2) ;
}
}
}
return bInters ;
}
//----------------------------------------------------------------------------
// Calcola la profondità del materiale lungo un raggio, identificato da un punto e un versoreore.
// Punto e versore devono essere espressi nel sistema di riferimento locale, in cui è immerso quello dello Zmap.
// InLength = distanza di ingresso (se -1 il punto è interno, se -2 il punto è esterno e il raggio non interseca lo Zmap)
// OutLength = distanza di uscita
bool
VolZmap::GetDepth( const Point3d& ptPLoc, const Vector3d& vtDLoc, double& dInLength, double& dOutLength, bool bExact) const
{
Point3d ptP = ptPLoc ;
Vector3d vtD = vtDLoc ;
ptP.ToLoc( m_MapFrame) ;
vtD.ToLoc( m_MapFrame) ;
if ( bExact && m_nMapNum == 3)
return GetDepthWithVoxel( ptP, vtD, dInLength, dOutLength, true) ;
else
return GetDepthWithDexel( ptP, vtD, dInLength, dOutLength) ;
}
//----------------------------------------------------------------------------
// Calcola la profondità del materiale usando i parallelepipedi corrispondenti ai segmenti di dexel di una griglia.
// Punto e versore devono essere espressi nel sistema di riferimento Zmap. Il vettore deve essere normalizzato.
// InLength = distanza di ingresso (se -1 il punto è interno, se -2 il punto è esterno e il raggio non interseca lo Zmap)
// OutLength = distanza di uscita
bool
VolZmap::GetDepthWithDexel( const Point3d& ptP, const Vector3d& vtV, double& dInLength, double& dOutLength) const
{
// Intersezione fra semiretta e BBox dello Zmap
double dU1, dU2 ;
bool bTest = IntersLineZMapBBox( ptP, vtV, dU1, dU2) && ( dU1 > 0 || dU2 > 0) ;
// Semiretta esterna al box dello Zmap quindi esterna anche allo Zmap
if ( ! bTest) {
dInLength = - 2 ;
dOutLength = - 2 ;
return true ;
}
double dInLen[3] ;
double dOutLen[3] ;
// Ciclo sulle griglie
for ( int nGrid = 0 ; nGrid < int( m_nMapNum) ; ++ nGrid) {
Point3d ptP0 = ptP ;
Vector3d vtV0 = vtV ;
Point3d ptI, ptF ;
// Una sola intersezione valida ( punto interno, intersezione valida 2)
if ( dU1 < 0 && dU2 > 0) {
ptI = ptP ;
ptF = ptP + dU2 * vtV ;
}
// due soluzioni valide ( punto esterno)
else {
ptI = ptP + dU1 * vtV ;
ptF = ptP + dU2 * vtV ;
}
// Passo dal sistema intrinseco alla griglia
if ( nGrid == 1) {
swap( ptP0.y, ptP0.z) ;
swap( ptP0.x, ptP0.z) ;
swap( vtV0.y, vtV0.z) ;
swap( vtV0.x, vtV0.z) ;
swap( ptI.y, ptI.z) ;
swap( ptI.x, ptI.z) ;
swap( ptF.y, ptF.z) ;
swap( ptF.x, ptF.z) ;
}
else if ( nGrid == 2) {
swap( ptP0.x, ptP0.z) ;
swap( ptP0.y, ptP0.z) ;
swap( vtV0.x, vtV0.z) ;
swap( vtV0.y, vtV0.z) ;
swap( ptI.x, ptI.z) ;
swap( ptI.y, ptI.z) ;
swap( ptF.x, ptF.z) ;
swap( ptF.y, ptF.z) ;
}
// Inizializzo distanze
dInLen[nGrid] = INFINITO ;
dOutLen[nGrid] = - INFINITO ;
// Determino asse di spostamento maggiore
bool bOnX = ( abs( ptF.y - ptI.y) <= abs( ptF.x - ptI.x)) ;
// Movimento crescente su asse di movimento principale
if ( ( bOnX && ptF.x < ptI.x) || ( ! bOnX && ptF.y < ptI.y) )
swap( ptI, ptF) ;
// Pendenza
double dDeltaX = ( ptF.x - ptI.x) ;
double dDeltaY = ( ptF.y - ptI.y) ;
double dM = 0 ;
if ( bOnX && abs( dDeltaX) > EPS_SMALL)
dM = dDeltaY / dDeltaX ;
else if ( ! bOnX && abs( dDeltaY) > EPS_SMALL)
dM = dDeltaX / dDeltaY ;
// Determinazione degli indici i j dei punti ptI e ptF
int nIi = Clamp( int( floor( ptI.x / m_dStep)), 0, m_nNx[nGrid] - 1) ;
int nIj = Clamp( int( floor( ptI.y / m_dStep)), 0, m_nNy[nGrid] - 1) ;
int nFi = Clamp( int( floor( ptF.x / m_dStep)), 0, m_nNx[nGrid] - 1) ;
int nFj = Clamp( int( floor( ptF.y / m_dStep)), 0, m_nNy[nGrid] - 1) ;
// mi muovo
int i = nIi ; int j = nIj ;
while ( ( bOnX && i <= nFi) || ( ! bOnX && j <= nFj)) {
// Eseguo controllo
double dU1, dU2 ;
if ( IntersRayDexel( ptP0, vtV0, nGrid, i, j, dU1, dU2)) {
dInLen[nGrid] = min( dInLen[nGrid], dU1) ;
dOutLen[nGrid] = max( dOutLen[nGrid], dU2) ;
}
// Calcolo spostamento (a destra o sopra)
if ( bOnX) {
double dMoveX = ( ( i + 1) * m_dStep - ptI.x) ;
double dMoveY = dMoveX * dM ;
double dY = ptI.y + dMoveY ;
int nNewJ = Clamp( int( floor( dY / m_dStep)), 0, m_nNy[nGrid] - 1) ;
if ( nNewJ != j)
j = nNewJ ;
else
++ i ;
}
else {
double dMoveY = ( ( j + 1) * m_dStep - ptI.y) ;
double dMoveX = dMoveY * dM ;
double dX = ptI.x + dMoveX ;
int nNewI = Clamp( int( floor( dX / m_dStep)), 0, m_nNx[nGrid] - 1) ;
if ( nNewI != i)
i = nNewI ;
else
++ j ;
}
}
// Se non abbiamo incontrato materiale
if ( dInLen[nGrid] > dOutLen[nGrid] - EPS_SMALL) {
dInLen[nGrid] = - 2 ;
dOutLen[nGrid] = - 2 ;
}
// Se parto dall'interno
else if ( dInLen[nGrid] < - EPS_SMALL)
dInLen[nGrid] = - 1 ;
}
if ( m_nMapNum == 1) {
dInLength = dInLen[0] ;
dOutLength = dOutLen[0] ;
return true ;
}
if ( abs( dInLen[0] + 2) < EPS_SMALL &&
abs( dInLen[1] + 2) < EPS_SMALL &&
abs( dInLen[2] + 2) < EPS_SMALL) {
dInLength = - 2 ;
dOutLength = - 2 ;
return true ;
}
else {
dInLength = INFINITO ;
dOutLength = - INFINITO ;
for ( int nGr = 0 ; nGr < 3 ; ++ nGr) {
if ( dInLen[nGr] > - 2 && dInLen[nGr] < dInLength)
dInLength = dInLen[nGr] ;
if ( dOutLen[nGr] > - 2 && dOutLen[nGr] > dOutLength)
dOutLength = dOutLen[nGr] ;
}
}
return true ;
}
//----------------------------------------------------------------------------
// Calcola la profondità del materiale usando i triangoli della rappresentazione grafica.
// Punto e versore devono essere espressi nel sistema di riferimento Zmap.
// Se si vuole che vengano utilizzati i triangoli con sharp-featue bEnh deve valere true, false altrimenti.
// InLength = distanza di ingresso (se -1 il punto è interno, se -2 il punto è esterno e il raggio non interseca lo Zmap)
// OutLength = distanza di uscita.
bool
VolZmap::GetDepthWithVoxel( const Point3d& ptP, const Vector3d& vtD, double& dInLength, double& dOutLength, bool bEnh) const
{
// Intersezione fra semiretta e BBox dello Zmap
double dU1, dU2 ;
bool bLineBBoxInters = IntersLineZMapBBox( ptP, vtD, dU1, dU2) && ( dU1 > 0 || dU2 > 0) ;
// Semiretta esterna al box dello Zmap quindi esterna anche allo Zmap
if ( ! bLineBBoxInters) {
dInLength = - 2 ;
dOutLength = - 2 ;
return true ;
}
// Determino il voxel di partenza
int nVoxI, nVoxJ, nVoxK ;
if ( ! GetPointVoxel( ptP, nVoxI, nVoxJ, nVoxK)) {
if ( ! GetPointVoxel( ptP + dU1 * vtD, nVoxI, nVoxJ, nVoxK))
return false ;
}
// Incrementi degli indici per sguire la retta
int nDeltaI = ( vtD.x > 0 ? 1 : ( vtD.x < 0 ? - 1 : 0)) ;
int nDeltaJ = ( vtD.y > 0 ? 1 : ( vtD.y < 0 ? - 1 : 0)) ;
int nDeltaK = ( vtD.z > 0 ? 1 : ( vtD.z < 0 ? - 1 : 0)) ;
// Scelgo i piani del voxel con cui intersecare la retta, per determinare il voxel successivo
int nPlaneI = ( vtD.x >= 0 ? 1 : 0) ;
int nPlaneJ = ( vtD.y >= 0 ? 1 : 0) ;
int nPlaneK = ( vtD.z >= 0 ? 1 : 0) ;
// Ciclo sui voxel
vector<VoxelIndexes> vVox ;
while ( IsValidVoxel( nVoxI, nVoxJ, nVoxK)) {
// Estremi della diagonale del voxel corrente
Point3d ptMin( ( nVoxI * N_DEXVOXRATIO + 0.5) * m_dStep,
( nVoxJ * N_DEXVOXRATIO + 0.5) * m_dStep,
( nVoxK * N_DEXVOXRATIO + 0.5) * m_dStep) ;
Point3d ptMax( ( ( nVoxI + 1) * N_DEXVOXRATIO + 0.5) * m_dStep,
( ( nVoxJ + 1) * N_DEXVOXRATIO + 0.5) * m_dStep,
( ( nVoxK + 1) * N_DEXVOXRATIO + 0.5) * m_dStep) ;
// Studio il voxel corrente
if ( IntersLineBox( ptP, vtD, ptMin, ptMax)) {
VoxelIndexes NewVox ;
NewVox.nI = nVoxI ;
NewVox.nJ = nVoxJ ;
NewVox.nK = nVoxK ;
vVox.emplace_back( NewVox) ;
}
// Interseco la retta con i piani frontiera del voxel
double dMaxTX = ( abs( vtD.x) > EPS_ZERO ?
abs( ( ( ( nVoxI + nPlaneI) * N_DEXVOXRATIO + 0.5) * m_dStep - ptP.x) / vtD.x) : INFINITO) ;
double dMaxTY = ( abs( vtD.y) > EPS_ZERO ?
abs( ( ( ( nVoxJ + nPlaneJ) * N_DEXVOXRATIO + 0.5) * m_dStep - ptP.y) / vtD.y) : INFINITO) ;
double dMaxTZ = ( abs( vtD.z) > EPS_ZERO ?
abs( ( ( ( nVoxK + nPlaneK) * N_DEXVOXRATIO + 0.5) * m_dStep - ptP.z) / vtD.z) : INFINITO) ;
// Determino gli incrementi
if ( dMaxTX < dMaxTY) {
if ( dMaxTX < dMaxTZ)
nVoxI += nDeltaI ;
else
nVoxK += nDeltaK ;
}
else {
if ( dMaxTY < dMaxTZ)
nVoxJ += nDeltaJ ;
else
nVoxK += nDeltaK ;
}
}
// Triangoli di frontiera dei voxel
TRIA3DEXLIST lstTria ;
ExtMarchingCubes( vVox, lstTria, bEnh) ;
// Dati dell'intersezione
struct LineTriaInt {
int nNum ;
double dPar1 ;
double dPar2 ;
double dDot ;
LineTriaInt( void) : nNum( 0) {}
LineTriaInt( double dP, double dD) : nNum( 1), dPar1( dP), dDot( dD) {}
LineTriaInt( double dP1, double dP2, double dD)
: nNum( 2), dPar1( dP1), dPar2( dP2), dDot( dD) {}
} ;
vector<LineTriaInt> vInt ;
// Ciclo sui triangoli dei voxel
for ( auto it = lstTria.begin() ; it != lstTria.end() ; ++it ) {
// Triangolo corrente e suoi punti di intersezione con la retta
const Triangle3d& CurrTria = *it ;
Point3d ptLineTria1, ptLineTria2 ;
// Studio dell'intersezione della retta con il triangolo corrente
int nIntType = IntersLineTria( ptP, vtD, 1.5 * dU2, CurrTria, ptLineTria1, ptLineTria2) ;
// Se non ci sono intersezioni passo al prossimo triangolo
if ( nIntType == ILTT_NO)
continue ;
// se altrimenti c'è una sola intersezione
else if ( nIntType == ILTT_VERT ||
nIntType == ILTT_EDGE ||
nIntType == ILTT_IN) {
vInt.emplace_back( ( ptLineTria1 - ptP) * vtD, vtD * CurrTria.GetN()) ;
}
// altrimenti ci sono due intersezioni
else {
double dP1 = ( ptLineTria1 - ptP) * vtD ;
double dP2 = ( ptLineTria2 - ptP) * vtD ;
double dD = vtD * CurrTria.GetN() ;
vInt.emplace_back( ( dP1 < dP2 ? dP1 : dP2), ( dP1 < dP2 ? dP2 : dP1), dD) ;
}
}
// Ordino le intersezioni in base al parametro distanza con segno da ptP
sort( vInt.begin(), vInt.end(),
[]( const LineTriaInt& a, const LineTriaInt& b)
{ double dFP = ( a.nNum == 2 ? 0.5 * ( a.dPar1 + a.dPar2) : a.dPar1) ;
double dLP = ( b.nNum == 2 ? 0.5 * ( b.dPar1 + b.dPar2) : b.dPar1) ;
return ( dLP > dFP) ; }) ;
// Inizializzo le distanze di ingresso e uscita:
// dInLength diminuisce, dOutLength aumenta.
dInLength = INFINITO ;
dOutLength = - INFINITO ;
int nFirstPosN ;
int nN = 0 ;
for ( ; nN < int( vInt.size()) ; ++ nN) {
if ( vInt[nN].dPar1 > - EPS_SMALL) {
nFirstPosN = nN ;
break ;
}
}
if ( nN == int( vInt.size())) {
dInLength = - 2 ;
dOutLength = - 2 ;
return true ;
}
if ( nFirstPosN > 0) {
if ( vInt[nFirstPosN - 1].dDot < EPS_ZERO)
dInLength = -1 ;
}
else if ( nFirstPosN == 0) {
if ( vInt[nFirstPosN].dDot > EPS_ZERO)
dInLength = -1 ;
else if ( GetPointVoxel( ptP, nVoxI, nVoxJ, nVoxK)) {
int nCubeType = CalcIndex( nVoxI, nVoxJ, nVoxK) ;
if ( nCubeType == 255)
dInLength = -1 ;
}
}
for ( int nN = nFirstPosN ; nN < int( vInt.size()) ; ++ nN) {
if ( vInt[nN].dDot > - EPS_ZERO) {
if ( vInt[nN].nNum == 2 && dOutLength < vInt[nN].dPar2)
dOutLength = vInt[nN].dPar2 ;
else if ( dOutLength < vInt[nN].dPar1)
dOutLength = vInt[nN].dPar1 ;
}
if ( vInt[nN].dDot < EPS_ZERO &&
dInLength > vInt[nN].dPar1)
dInLength = vInt[nN].dPar1 ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::AvoidBox( const Frame3d& frBox, const Vector3d& vtDiag) const
{
// BBox
BBox3d b3Box( ORIG, ORIG + vtDiag) ;
// lo porto nel riferimento intrinseco dello Zmap
b3Box.LocToLoc( frBox, m_MapFrame) ;
// BBox dello Zmap nel suo riferimento intrinseco
BBox3d b3Zmap( ORIG, Point3d( m_nNx[0] * m_dStep, m_nNy[0] * m_dStep, m_dMaxZ[0])) ;
// Se non interferiscono, posso uscire
BBox3d b3Int ;
if ( ! b3Zmap.FindIntersection( b3Box, b3Int))
return true ;
// Limiti su indici
int nStI = Clamp( int( b3Int.GetMin().x / m_dStep), 0, m_nNx[0] -1) ;
int nEnI = Clamp( int( b3Int.GetMax().x / m_dStep), 0, m_nNx[0] -1) ;
int nStJ = Clamp( int( b3Int.GetMin().y / m_dStep), 0, m_nNy[0] -1) ;
int nEnJ = Clamp( int( b3Int.GetMax().y / m_dStep), 0, m_nNy[0] -1) ;
// Vettore direzione dei dexel nel riferimento del Box
Vector3d vtK = Z_AX ; vtK.LocToLoc( m_MapFrame, frBox) ;
// Riferimento intrinseco dei dexel nel riferimento del box
Point3d ptO = ORIG ; ptO.LocToLoc( m_MapFrame, frBox) ;
Vector3d vtX = X_AX ; vtX.LocToLoc( m_MapFrame, frBox) ;
Vector3d vtY = Y_AX ; vtY.LocToLoc( m_MapFrame, frBox) ;
// Ciclo di intersezione dei dexel con il BBox
for ( int i = nStI ; i <= nEnI ; ++ i) {
for ( int j = nStJ ; j <= nEnJ ; ++ j) {
int nPos = j * m_nNx[0] + i ;
int nSize = int( m_Values[0][nPos].size()) ;
if ( nSize == 0)
continue ;
for ( int k = 0 ; k < 5 ; ++ k) {
Point3d ptT = ptO + ( i + 0.5) * m_dStep * vtX + ( j + 0.5) * m_dStep * vtY ;
if ( k == 0)
;
else if ( k == 1)
ptT += - 0.4 * m_dStep * vtX - 0.4 * m_dStep * vtY ;
else if ( k == 2)
ptT += + 0.4 * m_dStep * vtX - 0.4 * m_dStep * vtY ;
else if ( k == 3)
ptT += + 0.4 * m_dStep * vtX + 0.4 * m_dStep * vtY ;
else if ( k == 4)
ptT += - 0.4 * m_dStep * vtX + 0.4 * m_dStep * vtY ;
double dZmin, dZmax ;
if ( IntersLineBox( ptT, vtK, ORIG, ORIG + vtDiag, dZmin, dZmax)) {
for ( int nIndex = 0 ; nIndex < nSize ; nIndex += 1) {
if ( ! ( dZmax < m_Values[0][nPos][nIndex].dMin - EPS_SMALL ||
dZmin > m_Values[0][nPos][nIndex].dMax + EPS_SMALL))
return false ;
}
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::AvoidSphere( const Point3d& ptCenter, double dRad) const
{
// Porto la sfera nel riferimento intrinseco dello Zmap
Point3d ptC = ptCenter ;
ptC.ToLoc( m_MapFrame) ;
// BBox della sfera
BBox3d b3Box( ptC) ;
b3Box.Expand( dRad) ;
// BBox dello Zmap nel suo riferimento intrinseco
BBox3d b3Zmap( ORIG, Point3d( m_nNx[0] * m_dStep, m_nNy[0] * m_dStep, m_dMaxZ[0])) ;
// Se non interferiscono, posso uscire
BBox3d b3Int ;
if ( ! b3Zmap.FindIntersection( b3Box, b3Int))
return true ;
// Limiti su indici
int nStI = Clamp( int( b3Int.GetMin().x / m_dStep), 0, m_nNx[0] -1) ;
int nEnI = Clamp( int( b3Int.GetMax().x / m_dStep), 0, m_nNx[0] -1) ;
int nStJ = Clamp( int( b3Int.GetMin().y / m_dStep), 0, m_nNy[0] -1) ;
int nEnJ = Clamp( int( b3Int.GetMax().y / m_dStep), 0, m_nNy[0] -1) ;
// Ciclo di intersezione dei dexel con la sfera (nel riferimento intrinseco)
for ( int i = nStI ; i <= nEnI ; ++ i) {
for ( int j = nStJ ; j <= nEnJ ; ++ j) {
int nPos = j * m_nNx[0] + i ;
int nSize = int( m_Values[0][nPos].size()) ;
if ( nSize == 0)
continue ;
for ( int k = 0 ; k < 5 ; ++ k) {
Point3d ptT = ORIG + ( i + 0.5) * m_dStep * X_AX + ( j + 0.5) * m_dStep * Y_AX ;
if ( k == 0)
;
else if ( k == 1)
ptT += - 0.4 * m_dStep * X_AX - 0.4 * m_dStep * Y_AX ;
else if ( k == 2)
ptT += + 0.4 * m_dStep * X_AX - 0.4 * m_dStep * Y_AX ;
else if ( k == 3)
ptT += + 0.4 * m_dStep * X_AX + 0.4 * m_dStep * Y_AX ;
else if ( k == 4)
ptT += - 0.4 * m_dStep * X_AX + 0.4 * m_dStep * Y_AX ;
Point3d ptI1, ptI2 ;
if ( IntersLineSphere( ptT, Z_AX, ptC, dRad, ptI1, ptI2) != ILST_NO) {
double dZmin = ptI1.z ;
double dZmax = ptI2.z ;
for ( int nIndex = 0 ; nIndex < nSize ; nIndex += 1) {
if ( ! ( dZmax < m_Values[0][nPos][nIndex].dMin - EPS_SMALL ||
dZmin > m_Values[0][nPos][nIndex].dMax + EPS_SMALL))
return false ;
}
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::AvoidCylinder( const Frame3d& frCyl, double dL, double dR) const
{
return true ;
}
//----------------------------------------------------------------------------
// NB: L'origine del sistema di riferimento è nel centro della circonferenza di base
// e l'asse di simmetria coincide con l'asse z.
// La funzione restituisce true in caso di intersezione, false altrimenti.
bool
VolZmap::IntersLineCylinder( const Point3d& ptLineSt, const Vector3d& vtLineDir,
const Frame3d& CylFrame, double dH, double dR, bool bTapB, bool bTapT,
Point3d& ptInt1, Point3d& ptInt2, Vector3d& vtN1, Vector3d& vtN2)
{
Point3d ptP = ptLineSt ;
Vector3d vtV = vtLineDir ;
// Trasformazione delle coordinate:
// l'asse del cilindro corrisponde con
// l'asse z del sistema di riferimento
ptP.ToLoc( CylFrame) ;
vtV.ToLoc( CylFrame) ;
DBLVECTOR vdCoef(3) ;
DBLVECTOR vdRoots ;
// Non vogliamo che i dexel a filo vengano tagliati
double dSqRad = dR * dR ;
double dSqRadSafe = dSqRad - 2 * dR * EPS_SMALL ;
vdCoef[0] = ptP.x * ptP.x + ptP.y * ptP.y - dSqRad ;
vdCoef[1] = 2 * ( ptP.x * vtV.x + ptP.y * vtV.y) ;
vdCoef[2] = vtV.x * vtV.x + vtV.y * vtV.y ;
// Computo radici
int nRoot = PolynomialRoots( 2, vdCoef, vdRoots) ;
// Nessuna soluzione
if ( nRoot == 0 || nRoot == 1) {
if ( abs( vtV.z) > EPS_ZERO) {
// Intersezioni con i piani che limitano il cilindro in altezza
ptInt1 = ptP - ( ptP.z / vtV.z) * vtV ;
ptInt2 = ptP + ( ( dH - ptP.z) / vtV.z) * vtV ;
// Normali nei punti di interseione
vtN1 = Z_AX ;
vtN2 = - Z_AX ;
// Se le soluzioni sono all'interno delle circonferenze
if ( ptInt1.x * ptInt1.x + ptInt1.y * ptInt1.y <= dSqRadSafe &&
ptInt2.x * ptInt2.x + ptInt2.y * ptInt2.y <= dSqRadSafe) {
// Trasformiamo le coordinate nel sistema Zmap e abbiamo finito
ptInt1.ToGlob( CylFrame) ;
ptInt2.ToGlob( CylFrame) ;
vtN1.ToGlob( CylFrame) ;
vtN2.ToGlob( CylFrame) ;
return true ;
}
// Nessuna intersezione
else
return false ;
}
// Nessuna intersezione
else
return false ;
}
// L'equazione ammette o due soluzioni (eventualmente
// coincidenti) oppure nessuna o infinite se la la retta
// appartiene alla superficie
if ( nRoot == 2) {
// Ordino i parametri di intersezione
double dUmin = vdRoots[0] ;
double dUmax = vdRoots[1] ;
if ( dUmin > dUmax)
swap( dUmin, dUmax) ;
// Calcolo i punti d'intersezione (ordinati secondo Z crescente)
ptInt1 = ptP + vdRoots[0] * vtV ;
ptInt2 = ptP + vdRoots[1] * vtV ;
if ( ptInt1.z > ptInt2.z)
swap( ptInt1, ptInt2) ;
// Quote limitazione, dipendenti dalla tappatura estremità
double dZbot = ( bTapB ? -EPS_SMALL : EPS_SMALL) ;
double dZtop = ( bTapT ? dH + EPS_SMALL : dH - EPS_SMALL) ;
// Se intersezioni entrambe fuori dal cilindro limitato, non vanno considerate
if ( ptInt2.z < dZbot || ptInt1.z > dZtop)
return false ;
// Calcolo le normali
vtN1.Set( ( ORIG - ptInt1).x, ( ORIG - ptInt1).y, 0) ;
vtN1.Normalize() ;
vtN2.Set( ( ORIG - ptInt2).x, ( ORIG - ptInt2).y, 0) ;
vtN2.Normalize() ;
// Limitazioni per intersezione con piano basso
if ( ptInt1.z < dZbot - EPS_ZERO) {
ptInt1 = ptP + Clamp( ( dZbot - ptP.z / vtV.z), dUmin, dUmax) * vtV ;
vtN1.Set( 0, 0, 1) ;
}
// Limitazioni per intersezione con piano alto
if ( ptInt2.z > dZtop + EPS_ZERO) {
ptInt2 = ptP + Clamp( ( ( dZtop - ptP.z) / vtV.z), dUmin, dUmax) * vtV ;
vtN2.Set( 0, 0, -1) ;
}
// Riporto le coordinate nel sistema di riferimento griglia
ptInt1.ToGlob( CylFrame) ;
ptInt2.ToGlob( CylFrame) ;
vtN1.ToGlob( CylFrame) ;
vtN2.ToGlob( CylFrame) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::IntersLineConus( const Point3d& ptLineSt, const Vector3d& vtLineDir,
const Frame3d& ConusFrame, double dTan, double dh, double dH, bool bTapLow, bool bTapUp,
Point3d& ptInt1, Point3d& ptInt2, Vector3d& vtN1, Vector3d& vtN2)
{
// NB: L'origine del sistema di riferimento deve essere
// nel vertice del cono e l'asse di simmetria deve coincidere con l'asse x.
// La funzione restituisce true in caso di intersezione, false altrimenti.
Point3d ptP = ptLineSt ;
Vector3d vtV = vtLineDir ;
// Trasformazione delle coordinate
ptP.ToLoc( ConusFrame) ;
vtV.ToLoc( ConusFrame) ;
DBLVECTOR vdCoef(3) ;
DBLVECTOR vdRoots ;
double dSqTan = dTan * dTan ;
double dMinRad = dTan * dh ;
double dMaxRad = dTan * dH ;
double dDeltaR = dMaxRad - dMinRad ;
double dHei = dH - dh ;
vdCoef[0] = dSqTan * ptP.z * ptP.z - ptP.x * ptP.x - ptP.y * ptP.y ;
vdCoef[1] = 2 * ( dSqTan * ptP.z * vtV.z - ptP.x * vtV.x - ptP.y * vtV.y) ;
vdCoef[2] = dSqTan * vtV.z * vtV.z - vtV.x * vtV.x - vtV.y * vtV.y ;
// Computo radici
int nRoot = PolynomialRoots( 2, vdCoef, vdRoots) ;
// Nessuna soluzione
if ( nRoot == 0)
return false ;
double dEpsLow = ( bTapLow ? - EPS_SMALL : EPS_SMALL) ;
double dEpsUp = ( bTapUp ? EPS_SMALL : - EPS_SMALL) ;
// Una soluzione: la retta iterseca superficie
// laterale e un piano
if ( nRoot == 1) {
ptInt1 = ptP + vdRoots[0] * vtV ;
Vector3d vtU = ( ptInt1 - ORIG) - ( ptInt1 - ORIG).z * Z_AX ;
vtU.Normalize() ;
vtN1 = dDeltaR * Z_AX - dHei * vtU ;
vtN1.Normalize() ;
if ( ptInt1.z < dH + dEpsUp) {
if ( ptInt1.z > dh + dEpsLow) {
ptInt2 = ptP + ( ( dH - ptP.z) / vtV.z) * vtV ;
vtN2 = - Z_AX ;
}
else if ( ptInt1.z > - EPS_SMALL) {
ptInt1 = ptP + ( ( dh - ptP.z) / vtV.z) * vtV ;
ptInt2 = ptP + ( ( dH - ptP.z) / vtV.z) * vtV ;
vtN1 = Z_AX ;
vtN2 = - Z_AX ;
if ( ptInt2.x * ptInt2.x + ptInt2.y * ptInt2.y > dMaxRad * dMaxRad)
return false ;
}
else
return false ;
ptInt1.ToGlob( ConusFrame) ;
ptInt2.ToGlob( ConusFrame) ;
vtN1.ToGlob( ConusFrame) ;
vtN2.ToGlob( ConusFrame) ;
return true ;
}
else
return false ;
}
// Due soluzioni: la retta interseca due volte la
// superficie laterale
else if ( nRoot == 2) {
ptInt1 = ptP + vdRoots[0] * vtV ;
ptInt2 = ptP + vdRoots[1] * vtV ;
if ( ptInt1.z > ptInt2.z)
swap( ptInt1, ptInt2) ;
Vector3d vtU1 = ( ptInt1 - ORIG) - ( ptInt1 - ORIG).z * Z_AX ;
Vector3d vtU2 = ( ptInt2 - ORIG) - ( ptInt2 - ORIG).z * Z_AX ;
vtU1.Normalize() ;
vtU2.Normalize() ;
vtN1 = dDeltaR * Z_AX - dHei * vtU1 ;
vtN2 = dDeltaR * Z_AX - dHei * vtU2 ;
vtN1.Normalize() ;
vtN2.Normalize() ;
if ( abs( vtV.z) < EPS_ZERO) {
if ( ptInt1.z > dh + dEpsLow && ptInt1.z < dH + dEpsUp) {
ptInt1.ToGlob( ConusFrame) ;
ptInt2.ToGlob( ConusFrame) ;
vtN1.ToGlob( ConusFrame) ;
vtN2.ToGlob( ConusFrame) ;
vtN1.Normalize() ;
vtN2.Normalize() ;
return true ;
}
else
return false ;
}
if ( ptInt1.z < dH + dEpsUp) {
if ( ptInt1.z > dh + dEpsLow) {
if ( ptInt2.z > dH + dEpsUp) {
ptInt2 = ptP + ( ( dH - ptP.z) / vtV.z) * vtV ;
vtN2 = - Z_AX ;
}
}
else if ( ptInt1.z > - EPS_SMALL) {
if ( ptInt2.z > dH + dEpsUp) {
ptInt1 = ptP + ( ( dh - ptP.z) / vtV.z) * vtV ;
ptInt2 = ptP + ( ( dH - ptP.z) / vtV.z) * vtV ;
vtN1 = Z_AX ;
vtN2 = - Z_AX ;
}
else if ( ptInt2.z > dh + dEpsLow) {
ptInt1 = ptP + ( ( dh - ptP.z) / vtV.z) * vtV ;
vtN1 = Z_AX ;
}
else
return false ;
}
else {
if ( ptInt2.z < 0)
return false ;
else if ( ptInt2.z < dh + dEpsLow) {
ptInt1 = ptP + ( ( dh - ptP.z) / vtV.z) * vtV ;
ptInt2 = ptP + ( ( dH - ptP.z) / vtV.z) * vtV ;
vtN1 = Z_AX ;
vtN2 = - Z_AX ;
}
else if ( ptInt2.z < dH + dEpsUp) {
ptInt1 = ptP + ( ( dH - ptP.z) / vtV.z) * vtV ;
vtN1 = - Z_AX ;
}
else
return false ;
}
ptInt1.ToGlob( ConusFrame) ;
ptInt2.ToGlob( ConusFrame) ;
vtN1.ToGlob( ConusFrame) ;
vtN2.ToGlob( ConusFrame) ;
vtN1.Normalize() ;
vtN2.Normalize() ;
return true ;
}
else
return false ;
}
return false ;
}
//----------------------------------------------------------------------------
// NB: L'origine del sistema di riferimento deve essere
// nel centro della circonferenza di base, la cui traslazione obliqua
// genera il cilindro ellittico, e l'asse z deve essere l'asse
// di simmetria di tale circonferenza.
// La funzione restituisce true in caso di intersezione, false altrimenti.
// NB: dSqRad è il quadrato del raggio della circonferenza la cui
// traslazione obliqua genera il cilindro ellittico, dLongMvLen e
// dOrtMvLen sono rispettivamente le lunghezze delle proiezioni del
// movimento su z e x del sistema di riferimento CircFrame.
bool
VolZmap::IntersLineEllipticalCylinder( const Vector3d& vtLineDir, const Point3d& ptLineSt,
const Frame3d& CircFrame, double dRad, double dLongMvLen, double dOrtMvLen,
bool bTapLow, bool bTapUp,
Point3d& ptInt1, Point3d& ptInt2, Vector3d& vtN1, Vector3d& vtN2)
{
// Quadrato del raggio
double dSqRad = dRad * dRad ;
// Punto e vettore individuanti la retta
Point3d ptP = ptLineSt ;
Vector3d vtV = vtLineDir ;
// Asse cilindro ellittico
Vector3d vtAx( dOrtMvLen, 0, dLongMvLen) ;
vtAx.Normalize() ;
// Se il cilindro ellittico degenera in una superficie,
// non bisogna tagliare
if ( abs( vtAx.z) < EPS_SMALL)
return false ;
// Trasformazione delle coordinate
ptP.ToLoc( CircFrame) ;
vtV.ToLoc( CircFrame) ;
// Retta parallela all'asse del cilindro
if ( AreSameOrOppositeVectorApprox( vtV, vtAx)) {
// Interseco la retta con i piani delle circonferenze
Point3d ptOLsCirc( dOrtMvLen, 0, dLongMvLen) ;
ptInt1 = ptP - ( ptP.z / vtV.z) * vtV ;
ptInt2 = ptP - ( ( ptP.z - dLongMvLen) / vtV.z) * vtV ;
double dSafeSqRad = dSqRad - 2 * dRad * EPS_SMALL ;
if ( ( ptInt1 - ORIG).SqLenXY() < dSafeSqRad &&
( ptInt2 - ptOLsCirc).SqLenXY() < dSafeSqRad) {
vtN1 = Z_AX ;
vtN2 = - Z_AX ;
ptInt1.ToGlob( CircFrame) ;
ptInt2.ToGlob( CircFrame) ;
vtN1.ToGlob( CircFrame) ;
vtN2.ToGlob( CircFrame) ;
return true ;
}
else
return false ;
}
vector <double> vdCoef(3) ;
vector <double> vdRoots ;
// Coefficiente angolare della retta di movimento nel
// piano ZX del sistema di riferimento del movimento
// e suo quadrato
double dObCoef = dOrtMvLen / dLongMvLen ;
double dSqCoef = dObCoef * dObCoef ;
// Setto i coeficienti dell'equazione
vdCoef[0] = dSqCoef * ptP.z * ptP.z + ptP.x * ptP.x + ptP.y * ptP.y
- 2 * dObCoef * ptP.z * ptP.x - dSqRad ;
vdCoef[1] = 2 * ( dSqCoef * vtV.z * ptP.z + vtV.x * ptP.x + vtV.y * ptP.y
- dObCoef * ( vtV.z * ptP.x + vtV.x * ptP.z)) ;
vdCoef[2] = dSqCoef * vtV.z * vtV.z + vtV.x * vtV.x + vtV.y * vtV.y
- 2 * dObCoef * vtV.z * vtV.x ;
// Numero di soluzioni
int nRoot = PolynomialRoots( 2, vdCoef, vdRoots) ;
// L'equazione ammette o due soluzioni (eventualmente
// coincidenti) oppure nessuna o infinite se la la retta
// appartiene alla superficie
// Se ci sono intersezioni con i tappi o l'equazione
// degenera in una di primo grado, le eventuali
// soluzioni sono già state trovate.
if ( nRoot == 0 || nRoot == 1)
return false ;
// Due soluzioni trovate
else if ( nRoot == 2) {
// Flag per i tappi
double dEpsLow = ( bTapLow ? - EPS_SMALL : EPS_SMALL) ;
double dEpsUp = ( bTapUp ? EPS_SMALL : - EPS_SMALL) ;
// Vettore di movimento
Vector3d vtMv( dOrtMvLen, 0, dLongMvLen) ;
// Punti di intersezione
ptInt1 = ptP + vdRoots[0] * vtV ;
ptInt2 = ptP + vdRoots[1] * vtV ;
// Simmetria del problema
if ( ptInt1.z > ptInt2.z)
swap( ptInt1, ptInt2) ;
// Determino le normali alla superficie nei punti d'intersezione
Vector3d vtTest1 = ( ptInt1 - ORIG) - ( ptInt1 - ORIG) * vtAx * vtAx ;
Vector3d vtTest2 = ( ptInt2 - ORIG) - ( ptInt2 - ORIG) * vtAx * vtAx ;
double dX0_1, dX0_2 ;
if ( vtTest1.x > 0) {
dX0_1 = ( dSqRad - ptInt1.y * ptInt1.y > 0 ? sqrt( dSqRad - ptInt1.y * ptInt1.y) : 0) ;
}
else {
dX0_1 = ( dSqRad - ptInt1.y * ptInt1.y > 0 ? - sqrt( dSqRad - ptInt1.y * ptInt1.y) : 0) ;
}
Vector3d vtCirc1( - dX0_1, - ptInt1.y, 0) ;
Vector3d vtTan1( vtCirc1.y, - vtCirc1.x, 0) ;
Vector3d vtCross1 = vtTan1 ^ vtMv ;
// Vettore 1
vtN1 = ( vtCross1 * vtCirc1 > - EPS_ZERO ? vtCross1 : - vtCross1) ;
if ( vtTest2.x > 0) {
dX0_2 = ( dSqRad - ptInt2.y * ptInt2.y > 0 ? sqrt( dSqRad - ptInt2.y * ptInt2.y) : 0) ;
}
else {
dX0_2 = ( dSqRad - ptInt2.y * ptInt2.y > 0 ? - sqrt( dSqRad - ptInt2.y * ptInt2.y) : 0) ;
}
Vector3d vtCirc2( - dX0_2, - ptInt2.y, 0) ;
Vector3d vtTan2( vtCirc2.y, - vtCirc2.x, 0) ;
Vector3d vtCross2 = vtTan2 ^ vtMv ;
// Vettore 2
vtN2 = ( vtCross2 * vtCirc2 > - EPS_ZERO ? vtCross2 : - vtCross2) ;
// Normalizzo i vettori
vtN1.Normalize() ;
vtN2.Normalize() ;
// Studio le soluzioni: se ua è fuori dalla regione
// ammissibile, vuol dire che la retta esce da un tappo.
if ( ptInt1.z < dLongMvLen + dEpsUp) {
if ( ptInt1.z > + dEpsLow) {
// ptInt2 è sul tappo
if ( ptInt2.z > dLongMvLen + dEpsUp) {
ptInt2 = ptP + ( ( dLongMvLen - ptP.z) / vtV.z) * vtV ;
vtN2 = - Z_AX ;
}
}
else {
// Entrambe le soluzioni sono su un tappo
if ( ptInt2.z > dLongMvLen + dEpsUp) {
ptInt1 = ptP - ( ptP.z / vtV.z) * vtV ;
ptInt2 = ptP + ( ( dLongMvLen - ptP.z) / vtV.z) * vtV ;
vtN1.Set( 0, 0, 1) ;
vtN2.Set( 0, 0, -1) ;
if ( ptInt1.x * ptInt1.x + ptInt1.y * ptInt1.y > dSqRad &&
ptInt2.x * ptInt2.x + ptInt2.y * ptInt2.y > dSqRad)
return false ;
}
// La prima soluzione è sul tappo
else if ( ptInt2.z > dEpsLow) {
ptInt1 = ptP - ( ptP.z / vtV.z) * vtV ;
vtN1.Set( 0, 0, 1) ;
}
else
return false ;
}
}
else
return false ;
// Riporto le coordinate nel sistema
// di riferimento griglia.
ptInt1.ToGlob( CircFrame) ;
ptInt2.ToGlob( CircFrame) ;
vtN1.ToGlob( CircFrame) ;
vtN2.ToGlob( CircFrame) ;
return true ;
}
return false ;
}
//----------------------------------------------------------------------------
bool
VolZmap::IntersLineMyPolyhedron( const Point3d& ptLineSt, const Vector3d& vtLineDir,
const Frame3d& PolyFrame, double dLenX, double dLenY, double dLenZ, double dDeltaZ,
Point3d& ptInt1, Point3d& ptInt2, Vector3d& vtN1, Vector3d& vtN2)
{
Point3d ptP = ptLineSt ;
Vector3d vtV = vtLineDir ;
// Trasformazione delle coordinate
ptP.ToLoc( PolyFrame) ;
vtV.ToLoc( PolyFrame) ;
// Facce 1 e 2 parallele a XY
// Facce 3 e 4 parallele a XZ
// Facce 5 e 6 oblique
Point3d ptFacet135( 0, dLenY / 2, 0) ;
Point3d ptFacet246( dLenX , - dLenY / 2, dLenZ + dDeltaZ) ;
// Servono per descrivere i piani obliqui
Vector3d vtFacet5 = ptFacet135 - ptP ;
Vector3d vtFacet6 = ptFacet246 - ptP ;
Vector3d vtOb( - dDeltaZ, 0, dLenX) ;
vtOb.Normalize() ;
Point3d ptI1 = ptP + ( ( ptFacet135.y - ptP.y) / vtV.y) * vtV ;
Point3d ptI2 = ptP + ( ( ptFacet246.y - ptP.y) / vtV.y) * vtV ;
Point3d ptI3 = ptP + ( ( ptFacet135.x - ptP.x) / vtV.x) * vtV ;
Point3d ptI4 = ptP + ( ( ptFacet246.x - ptP.x) / vtV.x) * vtV ;
Point3d ptI5 = ptP + ( ( vtFacet5 * vtOb) / ( vtV * vtOb)) * vtV ;
Point3d ptI6 = ptP + ( ( vtFacet6 * vtOb) / ( vtV * vtOb)) * vtV ;
// Controlli affinché non vengano tagliati dexel a filo
// con il passaggio dell'utensile:
// Controllo sulle facce 1 e 2
if ( abs( vtV.y) < EPS_ZERO &&
abs( ptP.y) > dLenY / 2 - EPS_SMALL)
return false ;
// Controllo sulle facce 3 e 4
if ( abs( vtV.x) < EPS_ZERO &&
( ptP.x < EPS_SMALL ||
ptP.x > dLenX - EPS_SMALL))
return false ;
// Controllo sulle facce 5 e 6
/*Vector3d vtW( 0, dLenX, dDeltaZ) ;
vtW.Normalize() ;
Vector3d vtU = vtV - vtV.y * Y_AX - vtV * vtW * vtW ;
if ( vtU.Len() < EPS_ZERO &&
( ptP.z * dLenX < dDeltaZ * ptP.x + dLenX * EPS_SMALL ||
ptP.z * dLenX > dDeltaZ * ptP.x + dLenX * ( dLenY - EPS_SMALL)))
return false ;*/
double dDotObV = abs( vtV * vtOb) ;
Vector3d vtP1 = ptFacet135 - ptP ;
Vector3d vtP2 = ptFacet246 - ptP ;
double dP1 = abs ( vtP1 * vtOb) ;
double dP2 = abs ( vtP2 * vtOb) ;
if ( dDotObV < EPS_ZERO &&
( dP1 < EPS_SMALL || dP2 < EPS_SMALL))
return false ;
// Ricerca intersezioni con le facce
int nIntNum = 0 ;
// Intersezione con la prima faccia
if ( ptI1.x >= 0 && ptI1.x <= dLenX &&
ptI1.z * dLenX >= dDeltaZ * ptI1.x && ( ptI1.z - dLenZ) * dLenX <= dDeltaZ * ptI1.x) {
ptInt1 = ptI1 ;
vtN1 = - Y_AX ;
++ nIntNum ;
}
// Intersezione con la seconda faccia
if ( ptI2.x >= 0 && ptI2.x <= dLenX &&
ptI2.z * dLenX >= dDeltaZ * ptI2.x && ( ptI2.z - dLenZ) * dLenX <= dDeltaZ * ptI2.x) {
if ( nIntNum == 0) {
ptInt1 = ptI2 ;
vtN1 = Y_AX ;
++ nIntNum ;
}
else if ( ( ptInt1 - ptI2).SqLen() > SQ_EPS_SMALL) {
ptInt2 = ptI2 ;
vtN2 = Y_AX ;
++ nIntNum ;
}
}
// Intersezione con la terza faccia
if ( nIntNum < 2 &&
ptI3.z >= 0 && ptI3.z <= dLenZ &&
ptI3.y >= - ptFacet135.y && ptI3.y <= ptFacet135.y) {
if ( nIntNum == 0) {
ptInt1 = ptI3 ;
vtN1 = X_AX ;
++ nIntNum ;
}
else if ( ( ptInt1 - ptI3).SqLen() > SQ_EPS_SMALL) {
ptInt2 = ptI3 ;
vtN2 = X_AX ;
++ nIntNum ;
}
}
// Intersezione con la quarta faccia
if ( nIntNum < 2 &&
ptI4.z >= dDeltaZ && ptI4.z <= dLenZ + dDeltaZ &&
ptI4.y >= - ptFacet135.y && ptI4.y <= ptFacet135.y) {
if ( nIntNum == 0) {
ptInt1 = ptI4 ;
vtN1 = - X_AX ;
++ nIntNum ;
}
else if ( ( ptInt1 - ptI4).SqLen() > SQ_EPS_SMALL) {
ptInt2 = ptI4 ;
vtN2 = - X_AX ;
++ nIntNum ;
}
}
// Intersezione con la quinta faccia
if ( nIntNum < 2 &&
ptI5.x >= 0 && ptI5.x <= dLenX &&
ptI5.y >= - ptFacet135.y && ptI5.y <= ptFacet135.y) {
if ( nIntNum == 0) {
ptInt1 = ptI5 ;
vtN1 = vtOb ;
++ nIntNum ;
}
else if ( ( ptInt1 - ptI5).SqLen() > SQ_EPS_SMALL) {
ptInt2 = ptI5 ;
vtN2 = vtOb ;
++ nIntNum ;
}
}
// Intersezione con la sesta faccia
if ( nIntNum < 2 &&
ptI6.x >= 0 && ptI6.x <= dLenX &&
ptI6.y >= - ptFacet135.y && ptI6.y <= ptFacet135.y) {
if ( nIntNum == 0) {
ptInt1 = ptI6;
vtN1 = - vtOb ;
++ nIntNum ;
}
else if ( ( ptInt1 - ptI6).SqLen() > SQ_EPS_SMALL) {
ptInt2 = ptI6;
vtN2 = - vtOb ;
++ nIntNum ;
}
}
if ( nIntNum == 2) {
ptInt1.ToGlob( PolyFrame) ;
ptInt2.ToGlob( PolyFrame) ;
vtN1.ToGlob( PolyFrame) ;
vtN2.ToGlob( PolyFrame) ;
return true ;
}
else
return false ;
}
//----------------------------------------------------------------------------
bool
VolZmap::GetVolume( double& dVol) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// Eseguo il calcolo della lunghezza totale degli spilloni
double dLen = 0 ;
for ( int nMap = 0 ; nMap < int( m_nMapNum) ; ++ nMap) {
for ( int nDex = 0 ; nDex < int( m_Values[nMap].size()) ; ++ nDex) {
for ( int nInt = 0 ; nInt < int( m_Values[nMap][nDex].size()) ; ++ nInt) {
dLen += m_Values[nMap][nDex][nInt].dMax - m_Values[nMap][nDex][nInt].dMin ;
}
}
}
// Il volume si trova moltiplicando per l'area di ogni spillone e dividendo per il numero di mappe
dVol = dLen * ( m_dStep * m_dStep) / m_nMapNum ;
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::GetPartVolume( int nPart, double& dVol) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// Se una sola mappa o il numero di componenti è indefinito, errore
if ( m_nMapNum == 1 || m_nConnectedCompoCount == -1)
return false ;
// Se la componente richiesta non esiste, errore
if ( nPart < 0 || nPart > m_nConnectedCompoCount - 1)
return false ;
// Eseguo il calcolo della lunghezza totale degli spilloni
double dLen = 0 ;
for ( int nMap = 0 ; nMap < int( m_nMapNum) ; ++ nMap) {
for ( int nDex = 0 ; nDex < int( m_Values[nMap].size()) ; ++ nDex) {
for ( int nInt = 0 ; nInt < int( m_Values[nMap][nDex].size()) ; ++ nInt) {
// se il pezzo di spillone appartiene alla parte, ne aggiungo la lunghezza
if ( m_Values[nMap][nDex][nInt].nCompo == nPart + 1) {
dLen += m_Values[nMap][nDex][nInt].dMax - m_Values[nMap][nDex][nInt].dMin ;
}
}
}
}
// Il volume si trova moltiplicando per l'area di ogni spillone e dividendo per il numero di mappe
dVol = dLen * ( m_dStep * m_dStep) / 3 ;
return true ;
}
//----------------------------------------------------------------------------
// Il piano è espresso nel sistema locale, la funzione lo esprime nel sistema Zmap.
// I loop della flat region ottenuta dall'intersezione vengono salvati nello
// standard vector vLoop passato per riferimento.
// Se il processo va a buon fine viene restituito true, false altrimenti.
bool
VolZmap::GetPlaneIntersection( const Plane3d& plPlane, ICURVEPOVECTOR& vpLoop) const
{
// Verifico validità parametri
if ( ! plPlane.IsValid())
return false ;
// Porto il piano nel sistema Zmap
Plane3d plPlaneL = plPlane ;
plPlaneL.ToLoc( m_MapFrame) ;
// Vettore del piano
Vector3d vtNL = plPlaneL.GetVersN() ;
// Se il piano non interseca il bounding box del solido, abbiamo finito
if ( ! TestIntersPlaneZmapBBox( plPlaneL))
return true ;
// Cerco la mappa con i dexel più perpendicolari al piano e valuto
// se il versore del piano è equiverso o controverso ai dexel.
int nGrid = 0 ;
int nSign = ( vtNL.z > 0 ? 1 : - 1) ;
if ( abs( vtNL.x) > abs( vtNL.y) && abs( vtNL.x) > abs( vtNL.z)) {
nGrid = 1 ;
nSign = ( vtNL.x > 0 ? 1 : - 1) ;
}
else if ( abs( vtNL.y) > abs( vtNL.x) && abs( vtNL.y) > abs( vtNL.z)) {
nGrid = 2 ;
nSign = ( vtNL.y > 0 ? 1 : - 1) ;
}
// Ciclo sulle celle
vector<CurveLine> vLine ;
for ( int ni = - 1 ; ni < int( m_nNx[nGrid]) ; ++ ni) {
for ( int nj = - 1 ; nj < int( m_nNy[nGrid]) ; ++ nj) {
ProcessCell( nGrid, ni, nj, plPlaneL, vLine) ;
}
}
// Creo i loop
ChainCurves LoopCreator ;
LoopCreator.Init( false, EPS_SMALL, int( vLine.size())) ;
// Carico le curve per concatenarle
for ( int nCv = 0 ; nCv < int( vLine.size()) ; ++ nCv) {
Point3d ptSt = vLine[nCv].GetStart() ;
Point3d ptEn = vLine[nCv].GetEnd() ;
Vector3d vtDir ; vLine[nCv].GetStartDir( vtDir) ;
LoopCreator.AddCurve( nCv + 1, ptSt, vtDir, ptEn, vtDir) ;
}
// Recupero i concatenamenti
INTVECTOR vIds ;
Point3d ptNearStart ;
while ( LoopCreator.GetChainFromNear( ptNearStart, false, vIds)) {
PtrOwner<CurveComposite> pLoop( CreateBasicCurveComposite()) ;
if ( IsNull( pLoop))
return false ;
for ( auto i : vIds) {
// Aggiungo la linea alla curva composta.
if ( ! pLoop->AddCurve( vLine[i-1], true, EPS_SMALL))
return false ;
}
pLoop->SetExtrusion( vtNL) ;
pLoop->ToGlob( m_MapFrame) ;
// Se normali controverse, devo invertire il verso del loop.
if ( nSign < 0)
pLoop->Invert() ;
// eseguo approssimazione
PolyLine PL ;
if ( ! pLoop->ApproxWithLines( m_dStep, ANG_TOL_STD_DEG, ICurve::APL_RIGHT, PL) ||
! pLoop->Clear() || ! pLoop->FromPolyLine( PL))
return false ;
pLoop->MergeCurves( m_dStep, ANG_TOL_STD_DEG) ;
// Inserisco la curva composita nella raccolta da ritornare
vpLoop.emplace_back( Release( pLoop)) ;
}
return true ;
}
//----------------------------------------------------------------------------
// Data una cella, identificata dal numero della sua griglia e dai suoi indici i,j
// all'interno della griglia, genera gli eventuali segmenti che costituiscono la curva
// corrispondente alla frontiera della regione di piano interna la solido.
// Se la griglia o la cella non è valida, la funzione restituisce false,
// altrimenti valuta la tipologia della cella e crea gli eventuali segmenti.
// Se il processo va a buon fine la funzione restituisce true.
bool
VolZmap::ProcessCell( int nGrid, int nCellI, int nCellJ, const Plane3d& plPlane, vector<CurveLine>& vLine) const
{
// Se la griglia non esiste vi è un errore
if ( nGrid < 0 || nGrid > 2)
return false ;
// Se la cella non esiste vi è un errore
if ( nCellI < - 1 || nCellI >= int( m_nNx[nGrid]) ||
nCellJ < - 1 || nCellJ >= int( m_nNy[nGrid]))
return false ;
// Determino la configurazione della cella
int nIndex = CalcIndexForPlaneCells( plPlane, nGrid, nCellI, nCellJ) ;
// Tabella segmenti
static int nLineTable[16][5] = {
{ -1, -1, -1, -1, -1},
{ 0, 3, -1, -1, -1},
{ 1, 0, -1, -1, -1},
{ 1, 3, -1, -1, -1},
{ 2, 1, -1, -1, -1},
{ 0, 1, 2, 3, -1},
{ 2, 0, -1, -1, -1},
{ 2, 3, -1, -1, -1},
{ 3, 2, -1, -1, -1},
{ 0, 2, -1, -1, -1},
{ 1, 2, 3, 0, -1},
{ 1, 2, -1, -1, -1},
{ 3, 1, -1, -1, -1},
{ 0, 1, -1, -1, -1},
{ 3, 0, -1, -1, -1},
{ -1, -1, -1, -1, -1}
} ;
// Tabella dei punti medi dei segmenti: le righe rappresentano
// il numero di segmento (0, 1, 2, 3) le colonne rappresentano
// i e j.
static double dDeltaIJ[4][2] = {
{ 0.5, 0},
{ 1, 0.5},
{ 0.5, 1},
{ 0, 0.5}
} ;
// Se la cella è di frontiera costruisco i segmenti della curva
if ( nIndex != 0 && nIndex != 15) {
// Ciclo su tutti gli spigoli della cella che vengono attraversati dalla curva.
for ( int nEdge = 0 ; nLineTable[nIndex][nEdge] != -1 ; nEdge += 2) {
int nStEdge = nLineTable[nIndex][nEdge] ;
int nEnEdge = nLineTable[nIndex][nEdge + 1] ;
double nStDeltaI = dDeltaIJ[nStEdge][0] ;
double nStDeltaJ = dDeltaIJ[nStEdge][1] ;
double nEnDeltaI = dDeltaIJ[nEnEdge][0] ;
double nEnDeltaJ = dDeltaIJ[nEnEdge][1] ;
if ( nGrid == 0) {
// Punti sulla griglia
Point3d ptGrSt( ( nCellI + nStDeltaI + 0.5) * m_dStep, ( nCellJ + nStDeltaJ + 0.5) * m_dStep, 0) ;
Point3d ptGrEn( ( nCellI + nEnDeltaI + 0.5) * m_dStep, ( nCellJ + nEnDeltaJ + 0.5) * m_dStep, 0) ;
// Corrispondenti punti sul piano
Point3d ptSt, ptEn ;
if ( IntersLinePlane( ptGrSt, Z_AX, 10, plPlane, ptSt, false) &&
IntersLinePlane( ptGrEn, Z_AX, 10, plPlane, ptEn, false)) {
// Costruisco il tratto di curva
CurveLine cvLine ;
cvLine.Set( ptSt, ptEn) ;
vLine.emplace_back( cvLine) ;
}
}
else if ( nGrid == 1) {
// Punti sulla griglia
Point3d ptGrSt( 0, ( nCellI + nStDeltaI + 0.5) * m_dStep, ( nCellJ + nStDeltaJ + 0.5) * m_dStep) ;
Point3d ptGrEn( 0, ( nCellI + nEnDeltaI + 0.5) * m_dStep, ( nCellJ + nEnDeltaJ + 0.5) * m_dStep) ;
// Corrispondenti punti sul piano
Point3d ptSt, ptEn ;
if ( IntersLinePlane( ptGrSt, X_AX, 10, plPlane, ptSt, false) &&
IntersLinePlane( ptGrEn, X_AX, 10, plPlane, ptEn, false)) {
// Costruisco il tratto di curva
CurveLine cvLine ;
cvLine.Set( ptSt, ptEn) ;
vLine.emplace_back( cvLine) ;
}
}
else {
// Punti sulla griglia
Point3d ptGrSt( ( nCellJ + nStDeltaJ + 0.5) * m_dStep, 0, ( nCellI + nStDeltaI + 0.5) * m_dStep) ;
Point3d ptGrEn( ( nCellJ + nEnDeltaJ + 0.5) * m_dStep, 0, ( nCellI + nEnDeltaI + 0.5) * m_dStep) ;
// Corrispondenti punti sul piano
Point3d ptSt, ptEn ;
if ( IntersLinePlane( ptGrSt, Y_AX, 10, plPlane, ptSt, false) &&
IntersLinePlane( ptGrEn, Y_AX, 10, plPlane, ptEn, false)) {
// Costruisco il tratto di curva
CurveLine cvLine ;
cvLine.Set( ptSt, ptEn) ;
vLine.emplace_back( cvLine) ;
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
// Dato un dexel, identificato dal numero della sua griglia e dai suoi indici,
// determina se un suo intervallo attraversa il piano dato.
// Il numero di griglia e gli indici del dexel devono essere validi, se
// non lo sono, la funzione restituisce false, altrimenti cerca un
// tratto di dexel che intersechi il piano, se lo trova restituisce true,
// false altrimenti.
bool
VolZmap::InOut( const Plane3d& plPlane, int nGrid, int nI, int nJ) const
{
// Se la griglia non esiste, vi è un errore.
if ( nGrid < 0 || nGrid > 2)
return false ;
// Se gli indici sono di frontiera per lo
// Zmap o non esistono, non sono interni.
if ( nI <= - 1 || nI >= int( m_nNx[nGrid]) ||
nJ <= - 1 || nJ >= int( m_nNy[nGrid]))
return false ;
// Numero del dexel
int nDex = nJ * m_nNx[nGrid] + nI ;
// Ciclo sui segmenti del dexel
bool bNotFound = true ;
for ( int nK = 0 ; nK < int( m_Values[nGrid][nDex].size()) ; ++ nK) {
if ( nGrid == 0) {
// Punti estremi del segmento
Point3d ptSt( ( nI + 0.5) * m_dStep, ( nJ + 0.5) * m_dStep, m_Values[nGrid][nDex][nK].dMin) ;
Point3d ptEn( ( nI + 0.5) * m_dStep, ( nJ + 0.5) * m_dStep, m_Values[nGrid][nDex][nK].dMax) ;
// Se il segmento interseca il piano abbiamo finito
Point3d ptInt ;
if ( IntersLinePlane( ptSt, ptEn, plPlane, ptInt))
return true ;
}
else if ( nGrid == 1) {
// Punti estremi del segmento
Point3d ptSt( m_Values[nGrid][nDex][nK].dMin, ( nI + 0.5) * m_dStep, ( nJ + 0.5) * m_dStep) ;
Point3d ptEn( m_Values[nGrid][nDex][nK].dMax, ( nI + 0.5) * m_dStep, ( nJ + 0.5) * m_dStep) ;
// Se il segmento interseca il piano abbiamo finito
Point3d ptInt ;
if ( IntersLinePlane( ptSt, ptEn, plPlane, ptInt))
return true ;
}
else {
// Punti estremi del segmento
Point3d ptSt( ( nJ + 0.5) * m_dStep, m_Values[nGrid][nDex][nK].dMin, ( nI + 0.5) * m_dStep) ;
Point3d ptEn( ( nJ + 0.5) * m_dStep, m_Values[nGrid][nDex][nK].dMax, ( nI + 0.5) * m_dStep) ;
// Se il segmento interseca il piano abbiamo finito
Point3d ptInt ;
if ( IntersLinePlane( ptSt, ptEn, plPlane, ptInt))
return true ;
}
}
return false ;
}
//----------------------------------------------------------------------------
int
VolZmap::CalcIndexForPlaneCells( const Plane3d& plPlane, int nGrid, int nCellI, int nCellJ) const
{
int nIndex = 0 ;
if ( InOut( plPlane, nGrid, nCellI, nCellJ))
nIndex |= ( 1 << 0) ;
if ( InOut( plPlane, nGrid, nCellI + 1, nCellJ))
nIndex |= ( 1 << 1) ;
if ( InOut( plPlane, nGrid, nCellI + 1, nCellJ + 1))
nIndex |= ( 1 << 2) ;
if ( InOut( plPlane, nGrid, nCellI, nCellJ + 1))
nIndex |= ( 1 << 3) ;
return nIndex ;
}
//----------------------------------------------------------------------------
// dZ è una quota relativa alla mappa nGrid, se il dexel nDex esiste e
// dZ è interna a un suo intervallo restituisce true, false altrimenti.
bool
VolZmap::IsZInsideInterval( int nGrid, int nDex, double dZ) const
{
// Se la griglia non esiste vi è un errore.
if ( nGrid < 0 || nGrid > 2)
return false ;
// Se il dexel non esiste vi è un errore.
if ( nDex < 0 && nDex > int( m_Values[nGrid].size() - 1))
return false ;
// Valuto se dZ è interna a un intervallo.
for ( int nk = 0 ; nk < int( m_Values[nGrid][nDex].size()) ; ++ nk) {
double dZ1 = m_Values[nGrid][nDex][nk].dMin ;
double dZ2 = m_Values[nGrid][nDex][nk].dMax ;
// Se troviamo dZ in un intervallo abbiamo finito.
if ( dZ > dZ1 && dZ < dZ2)
return true ;
}
// dZ non sta in un intervallo.
return false ;
}
//----------------------------------------------------------------------------
// Box e piano devono essere nello stesso riferimento. Il box deve essere axis aligned.
bool
TestIntersPlaneBox( const BBox3d& b3Box, const Plane3d& plPlane)
{
// Calcolo le distanze con segno dei punti dal piano
Point3d ptE0 = b3Box.GetMin() ;
double dDist0 = DistPointPlane( ptE0, plPlane) ;
Point3d ptE1( b3Box.GetMax().x, b3Box.GetMin().y, b3Box.GetMin().z) ;
double dDist1 = DistPointPlane( ptE1, plPlane) ;
Point3d ptE2( b3Box.GetMax().x, b3Box.GetMax().y, b3Box.GetMin().z) ;
double dDist2 = DistPointPlane( ptE2, plPlane) ;
Point3d ptE3( b3Box.GetMin().x, b3Box.GetMax().y, b3Box.GetMin().z) ;
double dDist3 = DistPointPlane( ptE3, plPlane) ;
Point3d ptE4( b3Box.GetMin().x, b3Box.GetMin().y, b3Box.GetMax().z) ;
double dDist4 = DistPointPlane( ptE4, plPlane) ;
Point3d ptE5( b3Box.GetMax().x, b3Box.GetMin().y, b3Box.GetMax().z) ;
double dDist5 = DistPointPlane( ptE5, plPlane) ;
Point3d ptE6 = b3Box.GetMax() ;
double dDist6 = DistPointPlane( ptE6, plPlane) ;
Point3d ptE7( b3Box.GetMin().x, b3Box.GetMax().y, b3Box.GetMax().z) ;
double dDist7 = DistPointPlane( ptE7, plPlane) ;
// Distanze tutte positive
if ( dDist0 > EPS_SMALL && dDist1 > EPS_SMALL && dDist2 > EPS_SMALL && dDist3 > EPS_SMALL &&
dDist4 > EPS_SMALL && dDist5 > EPS_SMALL && dDist6 > EPS_SMALL && dDist7 > EPS_SMALL)
return false ;
// Distanze tutte negative
if ( dDist0 < - EPS_SMALL && dDist1 < - EPS_SMALL && dDist2 < - EPS_SMALL && dDist3 < - EPS_SMALL &&
dDist4 < - EPS_SMALL && dDist5 < - EPS_SMALL && dDist6 < - EPS_SMALL && dDist7 < - EPS_SMALL)
return false ;
// Il piano interseca il box
return true ;
}
//----------------------------------------------------------------------------
// Il piano deve essere espresso nel sistema di riferimento intrinseco dello Zmap.
bool
VolZmap::TestIntersPlaneZmapBBox( const Plane3d& plPlane) const
{
BBox3d b3Zmap( ORIG, Point3d( m_nNx[0] * m_dStep, m_nNy[0] * m_dStep, m_dMaxZ[0])) ;
return TestIntersPlaneBox( b3Zmap, plPlane) ;
}