5bcd4bb67d
- aggiunta classe Polygon3d (da EgtExchange) - razionalizzata classe Plane3d - corretta funzione IntersLineTria.
1364 lines
43 KiB
C++
1364 lines
43 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"
|
|
|
|
using namespace std ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
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) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::IntersLineZMapBBox( const Point3d& ptP, const Vector3d& vtV, unsigned int nGrid, double& dU1, double& dU2) const
|
|
{
|
|
// Punti estremi del box dello Zmap
|
|
Point3d ptMin = ORIG ;
|
|
Point3d ptMax = ptMin + Vector3d( m_nNx[nGrid] * m_dStep, m_nNy[nGrid] * m_dStep, m_dMaxZ[nGrid]) ;
|
|
|
|
return IntersLineBox( ptP, vtV, ptMin, ptMax, dU1, dU2) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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 ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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 ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// 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& ptPGlob, const Vector3d& vtDir, double& dInLength, double& dOutLength) const
|
|
{
|
|
#if 1
|
|
GetDepthWithVoxel( ptPGlob, vtDir, dInLength, dOutLength) ;
|
|
return true ;
|
|
#else
|
|
|
|
int nGrid = 0 ;
|
|
|
|
// Porto il raggio nel riferimento intrinseco
|
|
Point3d ptP = ptPGlob ;
|
|
ptP.ToLoc( m_MapFrame[nGrid]) ;
|
|
Vector3d vtV = vtDir ;
|
|
vtV.ToLoc( m_MapFrame[nGrid]) ;
|
|
vtV.Normalize() ;
|
|
|
|
// Intersezione fra semiretta e BBox dello Zmap
|
|
double dU1, dU2 ;
|
|
bool bTest = IntersLineZMapBBox( ptP, vtV, nGrid, 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 ;
|
|
}
|
|
|
|
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 ;
|
|
}
|
|
|
|
// Inizializzo distanze
|
|
dInLength = INFINITO ;
|
|
dOutLength = - 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( ptP, vtV, nGrid, i, j, dU1, dU2)) {
|
|
dInLength = min( dInLength, dU1) ;
|
|
dOutLength = max( dOutLength, 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 ( dInLength > dOutLength - EPS_SMALL) {
|
|
dInLength = - 2 ;
|
|
dOutLength = - 2 ;
|
|
return true ;
|
|
}
|
|
|
|
// Se parto dall'interno
|
|
if ( dInLength < - EPS_SMALL)
|
|
dInLength = - 1 ;
|
|
|
|
return true ;
|
|
#endif
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Punti e vettori devono essere espressi nel sistema locale (quello in cui è immerso lo 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::GetDepthWithVoxel( const Point3d& ptPLoc, const Vector3d& vtDir, double& dInLength, double& dOutLength) const
|
|
{
|
|
// Porto punto e vettore della retta nel sistema Zmap
|
|
Point3d ptP = ptPLoc ;
|
|
ptP.ToLoc( m_MapFrame[0]) ;
|
|
Vector3d vtD = vtDir ;
|
|
vtD.ToLoc( m_MapFrame[0]) ;
|
|
vtD.Normalize() ;
|
|
|
|
// Parametri di intersezione retta BBox dello Zmap
|
|
double dU1, dU2 ;
|
|
|
|
// Intersezione fra semiretta e BBox dello Zmap
|
|
bool bLineBBoxInters = IntersLineZMapBBox( ptP, vtD, 0, 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 ;
|
|
}
|
|
|
|
// Indici del voxel corrente
|
|
int nVoxI, nVoxJ, nVoxK ;
|
|
// Determino il voxel di partenza
|
|
if ( ! GetPointVoxel( ptP, nVoxI, nVoxJ, nVoxK)) {
|
|
if ( ! GetPointVoxel( ptP + dU1 * vtD, nVoxI, nVoxJ, nVoxK))
|
|
return false ;
|
|
}
|
|
|
|
// Indici dell'ultimo voxel
|
|
int nVxEndI, nVxEndJ, nVxEndK ;
|
|
// Determino il voxel finale
|
|
if ( ! GetPointVoxel( ptP + dU2 * vtD, nVxEndI, nVxEndJ, nVxEndK))
|
|
return false ;
|
|
|
|
// Struttura studio dell'intersezione
|
|
struct LineTriaInt {
|
|
double dPar ;
|
|
double dDot ;
|
|
} ;
|
|
std::vector<std::vector<LineTriaInt>> IntMatrix ;
|
|
|
|
int nStI = min( nVoxI, nVxEndI) ;
|
|
int nStJ = min( nVoxJ, nVxEndJ) ;
|
|
int nStK = min( nVoxK, nVxEndK) ;
|
|
int nEnI = max( nVoxI, nVxEndI) ;
|
|
int nEnJ = max( nVoxJ, nVxEndJ) ;
|
|
int nEnK = max( nVoxK, nVxEndK) ;
|
|
|
|
for ( int nI = nStI ; nI <= nEnI ; ++ nI) {
|
|
for ( int nJ = nStJ ; nJ <= nEnJ ; ++ nJ) {
|
|
for ( int nK = nStK ; nK <= nEnK ; ++ nK) {
|
|
|
|
Point3d ptMin( ( nI + 0.5) * m_dStep,
|
|
( nJ + 0.5) * m_dStep,
|
|
( nK + 0.5) * m_dStep) ;
|
|
Point3d ptMax( ( nI + 1.5) * m_dStep,
|
|
( nJ + 1.5) * m_dStep,
|
|
( nK + 1.5) * m_dStep) ;
|
|
|
|
if ( IsValidVoxel( nI, nJ, nK) &&
|
|
IntersLineBox( ptP, vtD, ptMin, ptMax)) {
|
|
|
|
// Analisi del voxel
|
|
int nCbType ;
|
|
TRIA3DLIST lstTria ;
|
|
ProcessCube( nI, nJ, nK, nCbType, lstTria) ;
|
|
|
|
// Se il voxel contiene triangoli
|
|
if ( nCbType == VOX_ON_BOUNDARY) {
|
|
|
|
// Ciclo sui triangoli del voxel
|
|
for ( auto it = lstTria.begin() ; it != lstTria.end() ; ++it ) {
|
|
|
|
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) {
|
|
LineTriaInt NewInt ;
|
|
NewInt.dPar = ( ptLineTria1 - ptP) * vtD ;
|
|
NewInt.dDot = vtD * CurrTria.GetN() ;
|
|
std::vector<LineTriaInt> vSing ;
|
|
vSing.emplace_back( NewInt) ;
|
|
|
|
IntMatrix.emplace_back( vSing) ;
|
|
}
|
|
// altrimenti ci sono due intersezioni
|
|
else {
|
|
LineTriaInt NewInt1, NewInt2 ;
|
|
std::vector<LineTriaInt> vCouple ;
|
|
double dP1 = ( ptLineTria1 - ptP) * vtD ;
|
|
double dP2 = ( ptLineTria2 - ptP) * vtD ;
|
|
NewInt1.dPar = ( dP1 < dP2 ? dP1 : dP2) ;
|
|
NewInt2.dPar = ( dP1 < dP2 ? dP2 : dP1) ;
|
|
NewInt1.dDot = vtD * CurrTria.GetN() ;
|
|
NewInt2.dDot = NewInt1.dDot ;
|
|
|
|
vCouple.emplace_back( NewInt1) ;
|
|
vCouple.emplace_back( NewInt2) ;
|
|
IntMatrix.emplace_back( vCouple) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ordino le intersezioni in base al parametro distanza con segno da ptP
|
|
for ( int nN = 0 ; nN < int( IntMatrix.size()) - 1 ; ++ nN) {
|
|
|
|
double dFP = ( IntMatrix[nN].size() == 2 ? 0.5 * ( IntMatrix[nN][0].dPar + IntMatrix[nN][1].dPar) :
|
|
IntMatrix[nN][0].dPar) ;
|
|
double dLP = ( IntMatrix[nN+1].size() == 2 ? 0.5 * ( IntMatrix[nN+1][0].dPar + IntMatrix[nN+1][1].dPar) :
|
|
IntMatrix[nN+1][0].dPar) ;
|
|
|
|
if ( dFP > dLP)
|
|
swap( IntMatrix[nN], IntMatrix[nN+1]) ;
|
|
}
|
|
|
|
std::vector<LineTriaInt> vInt ;
|
|
|
|
for ( int nN = 0 ; nN < int( IntMatrix.size()) ; ++ nN) {
|
|
vInt.emplace_back( IntMatrix[nN][0]) ;
|
|
if ( IntMatrix[nN].size() == 2)
|
|
vInt.emplace_back( IntMatrix[nN][1]) ;
|
|
}
|
|
|
|
// 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].dPar >= 0) {
|
|
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 ;
|
|
}
|
|
|
|
for ( int nN = nFirstPosN ; nN < int( vInt.size()) ; ++ nN) {
|
|
|
|
if ( vInt[nN].dDot > - EPS_ZERO &&
|
|
dOutLength < vInt[nN].dPar)
|
|
dOutLength = vInt[nN].dPar ;
|
|
|
|
if ( vInt[nN].dDot < EPS_ZERO &&
|
|
dInLength > vInt[nN].dPar)
|
|
dInLength = vInt[nN].dPar ;
|
|
}
|
|
|
|
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[0]) ;
|
|
|
|
// 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[0], frBox) ;
|
|
|
|
// Riferimento intrinseco dei dexel nel riferimento del box
|
|
Point3d ptO = ORIG ; ptO.LocToLoc( m_MapFrame[0], frBox) ;
|
|
Vector3d vtX = X_AX ; vtX.LocToLoc( m_MapFrame[0], frBox) ;
|
|
Vector3d vtY = Y_AX ; vtY.LocToLoc( m_MapFrame[0], 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 ;
|
|
|
|
Point3d ptC = ptO + ( i + 0.5) * m_dStep * vtX + ( j + 0.5) * m_dStep * vtY ;
|
|
|
|
double dZmin, dZmax ;
|
|
if ( IntersLineBox( ptC, 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::IntersLineCylinder( const Point3d& ptLineSt, const Vector3d& vtLineDir,
|
|
const Frame3d& CylFrame, double dL, double dR,
|
|
Point3d& ptInt1, Point3d& ptInt2, Vector3d& vtN1, Vector3d& vtN2,
|
|
bool bTapO, bool bTapL)
|
|
{
|
|
// NB: L'origine del sistema di riferimento deve essere
|
|
// nel centro della circonferenza di base 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:
|
|
// l'asse del cilindro corrisponde con
|
|
// l'asse x del sistema di riferimento
|
|
ptP.ToLoc( CylFrame) ;
|
|
vtV.ToLoc( CylFrame) ;
|
|
|
|
DBLVECTOR vdCoef(3) ;
|
|
DBLVECTOR vdRoots ;
|
|
|
|
double dSqRad = dR * dR - 2 * dR * EPS_SMALL ;
|
|
|
|
vdCoef[0] = ptP.y * ptP.y + ptP.z * ptP.z - dSqRad ;
|
|
vdCoef[1] = 2 * ( ptP.y * vtV.y + ptP.z * vtV.z) ;
|
|
vdCoef[2] = vtV.y * vtV.y + vtV.z * vtV.z ;
|
|
|
|
// Computo radici
|
|
int nRoot = PolynomialRoots( 2, vdCoef, vdRoots) ;
|
|
|
|
// Nessuna soluzione
|
|
if ( nRoot == 0 || nRoot == 1) {
|
|
|
|
if ( abs( vtV.x) > EPS_ZERO) {
|
|
|
|
ptInt1 = ptP - ( ptP.x / vtV.x) * vtV ;
|
|
ptInt2 = ptP + ( ( dL - ptP.x) / vtV.x) * vtV ;
|
|
|
|
vtN1 = X_AX ;
|
|
vtN2 = - X_AX ;
|
|
|
|
if ( ptInt1.y * ptInt1.y + ptInt1.z * ptInt1.z <= dSqRad &&
|
|
ptInt2.y * ptInt2.y + ptInt2.z * ptInt2.z <= dSqRad) {
|
|
|
|
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) {
|
|
|
|
double dEpsO = ( bTapO ? - EPS_SMALL : EPS_SMALL) ;
|
|
double dEpsL = ( bTapL ? EPS_SMALL : - EPS_SMALL) ;
|
|
|
|
ptInt1 = ptP + vdRoots[0] * vtV ;
|
|
ptInt2 = ptP + vdRoots[1] * vtV ;
|
|
|
|
if ( ptInt1.x > ptInt2.x)
|
|
swap( ptInt1, ptInt2) ;
|
|
|
|
vtN1.Set( 0, ( ORIG - ptInt1).y, ( ORIG - ptInt1).z) ;
|
|
vtN2.Set( 0, ( ORIG - ptInt2).y, ( ORIG - ptInt2).z) ;
|
|
|
|
|
|
if ( ptInt1.x < dL + dEpsL) {
|
|
|
|
if ( ptInt1.x > dEpsO) {
|
|
|
|
if ( ptInt2.x > dL + dEpsL) {
|
|
|
|
ptInt2 = ptP + ( ( dL - ptP.x) / vtV.x) * vtV ;
|
|
vtN2.Set( -1, 0, 0) ;
|
|
}
|
|
}
|
|
else {
|
|
|
|
if ( ptInt2.x > dL + dEpsL) {
|
|
|
|
ptInt1 = ptP - ( ptP.x / vtV.x) * vtV ;
|
|
ptInt2 = ptP + ( ( dL - ptP.x) / vtV.x) * vtV ;
|
|
vtN1.Set( 1, 0, 0) ;
|
|
vtN2.Set( -1, 0, 0) ;
|
|
}
|
|
else if ( ptInt2.x > dEpsO) {
|
|
|
|
ptInt1 = ptP - ( ptP.x / vtV.x) * vtV ;
|
|
vtN1.Set( 1, 0, 0) ;
|
|
}
|
|
else
|
|
return false ;
|
|
}
|
|
}
|
|
else
|
|
return false ;
|
|
|
|
// Riporto le coordinate nel sistema di riferimento griglia
|
|
ptInt1.ToGlob( CylFrame) ;
|
|
ptInt2.ToGlob( CylFrame) ;
|
|
vtN1.ToGlob( CylFrame) ;
|
|
vtN2.ToGlob( CylFrame) ;
|
|
|
|
vtN1.Normalize() ;
|
|
vtN2.Normalize() ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::IntersZLineCylinder( const Point3d& ptLine,
|
|
const Point3d& ptBase, const Point3d& ptTop, double dCylR,
|
|
double& dInfZ, double& dSupZ)
|
|
{
|
|
// NB: Le coordinate sono espresse nel sistema griglia
|
|
// La funzione restituisce true in caso di intersezione,
|
|
// false altrimenti.
|
|
|
|
double dSqRad = dCylR * dCylR ;
|
|
|
|
// Cilindro verticale
|
|
if ( AreSamePointXYApprox( ptBase, ptTop)) {
|
|
|
|
// Intersezione
|
|
if ( SqDistXY( ptLine, ptBase) < dSqRad) {
|
|
dInfZ = min( ptBase.z, ptTop.z) ;
|
|
dSupZ = max( ptBase.z, ptTop.z) ;
|
|
return true ;
|
|
}
|
|
|
|
// Non vi è intersezione
|
|
else
|
|
return false ;
|
|
}
|
|
|
|
// Cilindro non verticale
|
|
else {
|
|
|
|
// Studio delle simmetrie
|
|
Point3d ptS = ( ptBase.z < ptTop.z ? ptBase : ptTop) ;
|
|
Point3d ptE = ( ptBase.z < ptTop.z ? ptTop : ptBase) ;
|
|
|
|
Vector3d vtAx = ptE - ptS ;
|
|
|
|
Vector3d vtV1( vtAx.x, vtAx.y, 0) ;
|
|
|
|
double dLenXY = vtV1.LenXY() ;
|
|
double dSZ = ptS.z ;
|
|
double dEZ = ptE.z ;
|
|
double dDeltaZ = dEZ - dSZ ;
|
|
|
|
Vector3d vtL( ptLine.x - ptS.x, ptLine.y - ptS.y, 0) ;
|
|
|
|
// vtV1 e vtV2 formano un sistema ortonormale
|
|
// sul piano e insieme a ptSxy formano un sistema
|
|
// di riferimento bidimensionale
|
|
vtV1.Normalize() ;
|
|
Vector3d vtV2 = vtV1 ;
|
|
vtV2.Rotate( Z_AX, 90) ;
|
|
|
|
double dLen = vtAx.Len() ;
|
|
|
|
// Sono seno e coseno dell'angolo complementare
|
|
// rispetto a quello formato dal vettore movimento
|
|
// con il piano, per questo motivo si ha dCos con
|
|
// dDeltaZ e dSin con dLenXY
|
|
double dCos = dDeltaZ / dLen ;
|
|
double dSin = dLenXY / dLen ;
|
|
|
|
// Nuove coordinate piane del punto
|
|
double dLocX1 = vtL * vtV1 ;
|
|
double dLocX2 = vtL * vtV2 ;
|
|
|
|
double dSqRoot = sqrt( dSqRad - dLocX2 * dLocX2) ;
|
|
double dX1_0 = dCos * dSqRoot ;
|
|
|
|
if ( dLocX1 >= - dX1_0 && dLocX1 <= dLenXY + dX1_0 &&
|
|
abs( dLocX2) < dCylR) {
|
|
|
|
// Minimi
|
|
if ( dLocX1 < dX1_0) {
|
|
|
|
double dDotS = vtAx * ( ptS - ORIG) ;
|
|
// Qui usiamo ptLine perché servono coordinate griglia
|
|
dInfZ = ( dDotS - vtAx.x * ptLine.x - vtAx.y * ptLine.y) / vtAx.z ;
|
|
}
|
|
else {
|
|
|
|
double dZ0 = - dSin * dSqRoot ;
|
|
|
|
dInfZ = dSZ + dZ0 + ( dLocX1 - dX1_0) * dDeltaZ / dLenXY ;
|
|
}
|
|
|
|
// Massimi
|
|
if ( dLocX1 <= dLenXY - dX1_0) {
|
|
|
|
double dZ0 = dSin * dSqRoot ;
|
|
|
|
dSupZ = dSZ + dZ0 + ( dLocX1 + dX1_0) * dDeltaZ / dLenXY ;
|
|
}
|
|
else {
|
|
|
|
double dDotE = vtAx * ( ptE - ORIG) ;
|
|
// Qui usiamo ptLine perché servono coordinate griglia
|
|
dSupZ = ( dDotE - vtAx.x * ptLine.x - vtAx.y * ptLine.y) / vtAx.z ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
return false ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::IntersLineConus( const Point3d& ptLineSt, const Vector3d& vtLineDir,
|
|
const Frame3d& ConusFrame, double dTan, double dl, double dL,
|
|
Point3d& ptInt1, Point3d& ptInt2, Vector3d& vtN1, Vector3d& vtN2,
|
|
bool bTapLow, bool bTapUp)
|
|
{
|
|
// 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 * dl ;
|
|
double dMaxRad = dTan * dL ;
|
|
double dDeltaR = dMaxRad - dMinRad ;
|
|
double dHei = dL - dl ;
|
|
|
|
vdCoef[0] = dSqTan * ptP.x * ptP.x - ptP.y * ptP.y - ptP.z * ptP.z ;
|
|
vdCoef[1] = 2 * ( dSqTan * ptP.x * vtV.x - ptP.y * vtV.y - ptP.z * vtV.z) ;
|
|
vdCoef[2] = dSqTan * vtV.x * vtV.x - vtV.y * vtV.y - vtV.z * vtV.z ;
|
|
|
|
// 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).x * X_AX ;
|
|
|
|
vtU.Normalize() ;
|
|
|
|
vtN1 = dDeltaR * X_AX - dHei * vtU ;
|
|
|
|
vtN1.Normalize() ;
|
|
|
|
if ( ptInt1.x < dL + dEpsUp) {
|
|
|
|
if ( ptInt1.x > dl + dEpsLow) {
|
|
|
|
ptInt2 = ptP + ( ( dL - ptP.x) / vtV.x) * vtV ;
|
|
|
|
vtN2 = - X_AX ;
|
|
|
|
}
|
|
else if ( ptInt1.x > - EPS_SMALL) {
|
|
|
|
ptInt1 = ptP + ( ( dl - ptP.x) / vtV.x) * vtV ;
|
|
ptInt2 = ptP + ( ( dL - ptP.x) / vtV.x) * vtV ;
|
|
|
|
vtN1 = X_AX ;
|
|
vtN2 = - X_AX ;
|
|
|
|
if ( ptInt2.y * ptInt2.y + ptInt2.z * ptInt2.z > 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.x > ptInt2.x)
|
|
swap( ptInt1, ptInt2) ;
|
|
|
|
Vector3d vtU1 = ( ptInt1 - ORIG) - ( ptInt1 - ORIG).x * X_AX ;
|
|
Vector3d vtU2 = ( ptInt2 - ORIG) - ( ptInt2 - ORIG).x * X_AX ;
|
|
|
|
vtU1.Normalize() ;
|
|
vtU2.Normalize() ;
|
|
|
|
vtN1 = dDeltaR * X_AX - dHei * vtU1 ;
|
|
vtN2 = dDeltaR * X_AX - dHei * vtU2 ;
|
|
|
|
vtN1.Normalize() ;
|
|
vtN2.Normalize() ;
|
|
|
|
if ( abs( vtV.x) < EPS_ZERO) {
|
|
|
|
if ( ptInt1.x > dl + dEpsLow && ptInt1.x < dL + dEpsUp) {
|
|
|
|
ptInt1.ToGlob( ConusFrame) ;
|
|
ptInt2.ToGlob( ConusFrame) ;
|
|
|
|
vtN1.ToGlob( ConusFrame) ;
|
|
vtN2.ToGlob( ConusFrame) ;
|
|
|
|
vtN1.Normalize() ;
|
|
vtN2.Normalize() ;
|
|
|
|
return true ;
|
|
}
|
|
else
|
|
return false ;
|
|
}
|
|
|
|
|
|
if ( ptInt1.x < dL + dEpsUp) {
|
|
|
|
if ( ptInt1.x > dl + dEpsLow) {
|
|
|
|
if ( ptInt2.x > dL + dEpsUp) {
|
|
|
|
ptInt2 = ptP + ( ( dL - ptP.x) / vtV.x) * vtV ;
|
|
|
|
vtN2 = - X_AX ;
|
|
}
|
|
}
|
|
else if ( ptInt1.x > - EPS_SMALL) {
|
|
|
|
if ( ptInt2.x > dL + dEpsUp) {
|
|
|
|
ptInt1 = ptP + ( ( dl - ptP.x) / vtV.x) * vtV ;
|
|
ptInt2 = ptP + ( ( dL - ptP.x) / vtV.x) * vtV ;
|
|
|
|
vtN1 = X_AX ;
|
|
vtN2 = - X_AX ;
|
|
}
|
|
else if ( ptInt2.x > dl + dEpsLow) {
|
|
|
|
ptInt1 = ptP + ( ( dl - ptP.x) / vtV.x) * vtV ;
|
|
vtN1 = X_AX ;
|
|
}
|
|
else
|
|
return false ;
|
|
}
|
|
else {
|
|
|
|
if ( ptInt2.x < 0)
|
|
|
|
return false ;
|
|
|
|
else if ( ptInt2.x < dl + dEpsLow) {
|
|
|
|
ptInt1 = ptP + ( ( dl - ptP.x) / vtV.x) * vtV ;
|
|
ptInt2 = ptP + ( ( dL - ptP.x) / vtV.x) * vtV ;
|
|
|
|
vtN1 = X_AX ;
|
|
vtN2 = - X_AX ;
|
|
}
|
|
else if ( ptInt2.x < dL + dEpsUp) {
|
|
|
|
ptInt1 = ptP + ( ( dL - ptP.x) / vtV.x) * vtV ;
|
|
vtN1 = - X_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 ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::IntersLineEllipticalCylinder( const Vector3d& vtLineDir, const Point3d& ptLineSt,
|
|
const Frame3d& CircFrame, double dSqRad, double dLongMvLen, double dOrtMvLen,
|
|
Point3d& ptInt1, Point3d& ptInt2, Vector3d& vtN1, Vector3d& vtN2,
|
|
bool bTapLow, bool bTapUp)
|
|
{
|
|
// NB: L'origine del sistema di riferimento deve essere
|
|
// nel centro della circonferenza di base, la cui tralsazione obliqua
|
|
// genera il cilindro ellittico, e l'asse x 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 x e y del sistema di riferimento CircFrame.
|
|
|
|
double dObCoef = dOrtMvLen / dLongMvLen ;
|
|
double dSqCoef = dObCoef * dObCoef ;
|
|
|
|
Point3d ptP = ptLineSt ;
|
|
Vector3d vtV = vtLineDir ;
|
|
|
|
// Asse cilindro ellittico
|
|
Vector3d vtAx( dLongMvLen, dOrtMvLen, 0) ;
|
|
vtAx.Normalize() ;
|
|
|
|
// Trasformazione delle coordinate
|
|
ptP.ToLoc( CircFrame) ;
|
|
vtV.ToLoc( CircFrame) ;
|
|
|
|
std::vector <double> vdCoef(3) ;
|
|
std::vector <double> vdRoots ;
|
|
|
|
vdCoef[0] = dSqCoef * ptP.x * ptP.x + ptP.y * ptP.y + ptP.z * ptP.z - 2 * dObCoef * ptP.x * ptP.y - dSqRad ;
|
|
vdCoef[1] = 2 * ( dSqCoef * vtV.x * ptP.x + vtV.y * ptP.y + vtV.z * ptP.z - dObCoef * ( vtV.x * ptP.y + vtV.y * ptP.x)) ;
|
|
vdCoef[2] = dSqCoef * vtV.x * vtV.x + vtV.y * vtV.y + vtV.z * vtV.z - 2 * dObCoef * vtV.x * vtV.y ;
|
|
|
|
int nRoot = PolynomialRoots( 2, vdCoef, vdRoots) ;
|
|
|
|
|
|
// Nessuna soluzione
|
|
if ( nRoot == 0 || nRoot == 1) {
|
|
|
|
if ( abs( vtV.x) > EPS_ZERO) {
|
|
|
|
ptInt1 = ptP - ( ptP.x / vtV.x) * vtV ;
|
|
ptInt2 = ptP + ( ( dLongMvLen - ptP.x) / vtV.x) * vtV ;
|
|
|
|
if ( ptInt1.y * ptInt1.y + ptInt1.z * ptInt1.z < dSqRad &&
|
|
( ptInt2.y - dOrtMvLen) * ( ptInt2.y - dOrtMvLen) + ptInt2.z * ptInt2.z < dSqRad) {
|
|
|
|
ptInt1.ToGlob( CircFrame) ;
|
|
ptInt2.ToGlob( CircFrame) ;
|
|
|
|
vtN1 = X_AX ;
|
|
vtN2 = - X_AX ;
|
|
|
|
vtN1.ToGlob( CircFrame) ;
|
|
vtN2.ToGlob( CircFrame) ;
|
|
|
|
return true ;
|
|
}
|
|
// Nessuna intersezione
|
|
else
|
|
return false ;
|
|
}
|
|
// Nessuna intersezione
|
|
else
|
|
return false ;
|
|
}
|
|
|
|
double dEpsLow = ( bTapLow ? - EPS_SMALL : EPS_SMALL) ;
|
|
double dEpsUp = ( bTapUp ? EPS_SMALL : - EPS_SMALL) ;
|
|
|
|
// L'equazione ammette o due soluzioni (eventualmente
|
|
// coincidenti) oppure nessuna o infinite se la la retta
|
|
// appartiene alla superficie
|
|
|
|
Vector3d vtMv( dLongMvLen, dOrtMvLen, 0) ;
|
|
|
|
if ( nRoot == 2) {
|
|
|
|
ptInt1 = ptP + vdRoots[0] * vtV ;
|
|
ptInt2 = ptP + vdRoots[1] * vtV ;
|
|
|
|
|
|
if ( ptInt1.x > ptInt2.x)
|
|
|
|
swap( ptInt1, ptInt2) ;
|
|
|
|
Vector3d vtTest1 = ( ptInt1 - ORIG) - ( ptInt1 - ORIG) * vtAx * vtAx ;
|
|
Vector3d vtTest2 = ( ptInt2 - ORIG) - ( ptInt2 - ORIG) * vtAx * vtAx ;
|
|
|
|
double dY0_1, dY0_2 ;
|
|
|
|
if ( vtTest1.y > 0) {
|
|
|
|
dY0_1 = ( dSqRad - ptInt1.z * ptInt1.z > 0 ? sqrt( dSqRad - ptInt1.z * ptInt1.z) : 0) ;
|
|
}
|
|
else {
|
|
|
|
dY0_1 = ( dSqRad - ptInt1.z * ptInt1.z > 0 ? - sqrt( dSqRad - ptInt1.z * ptInt1.z) : 0) ;
|
|
}
|
|
|
|
Vector3d vtCirc1( 0, - dY0_1, - ptInt1.z) ;
|
|
Vector3d vtTan1( 0, - vtCirc1.z, vtCirc1.y) ;
|
|
Vector3d vtCross1 = vtTan1 ^ vtMv ;
|
|
|
|
vtN1 = ( vtCross1 * vtCirc1 > - EPS_ZERO ? vtCross1 : - vtCross1) ;
|
|
|
|
if ( vtTest2.y > 0) {
|
|
|
|
dY0_2 = ( dSqRad - ptInt2.z * ptInt2.z > 0 ? sqrt( dSqRad - ptInt2.z * ptInt2.z) : 0) ;
|
|
}
|
|
else {
|
|
|
|
dY0_2 = ( dSqRad - ptInt2.z * ptInt2.z > 0 ? - sqrt( dSqRad - ptInt2.z * ptInt2.z) : 0) ;
|
|
}
|
|
|
|
Vector3d vtCirc2( 0, - dY0_2, - ptInt2.z) ;
|
|
Vector3d vtTan2( 0, - vtCirc2.z, vtCirc2.y) ;
|
|
Vector3d vtCross2 = vtTan2 ^ vtMv ;
|
|
|
|
vtN2 = ( vtCross2 * vtCirc2 > - EPS_ZERO ? vtCross2 : - vtCross2) ;
|
|
|
|
|
|
|
|
if ( ptInt1.x < dLongMvLen + dEpsUp) {
|
|
|
|
if ( ptInt1.x > + dEpsLow) {
|
|
|
|
if ( ptInt2.x > dLongMvLen + dEpsUp) {
|
|
|
|
ptInt2 = ptP + ( ( dLongMvLen - ptP.x) / vtV.x) * vtV ;
|
|
vtN2 = - X_AX ;
|
|
}
|
|
}
|
|
else {
|
|
|
|
if ( ptInt2.x > dLongMvLen + dEpsUp) {
|
|
|
|
ptInt1 = ptP - ( ptP.x / vtV.x) * vtV ;
|
|
ptInt2 = ptP + ( ( dLongMvLen - ptP.x) / vtV.x) * vtV ;
|
|
|
|
vtN1.Set( 1, 0, 0) ;
|
|
vtN2.Set( -1, 0, 0) ;
|
|
|
|
if ( ptInt1.y * ptInt1.y + ptInt1.z * ptInt1.z > dSqRad &&
|
|
ptInt2.y * ptInt2.y + ptInt2.z * ptInt2.z > dSqRad)
|
|
|
|
return false ;
|
|
}
|
|
else if ( ptInt2.x > dEpsLow) {
|
|
|
|
ptInt1 = ptP - ( ptP.x / vtV.x) * vtV ;
|
|
vtN1.Set( 1, 0, 0) ;
|
|
}
|
|
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) ;
|
|
|
|
vtN1.Normalize() ;
|
|
vtN2.Normalize() ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::IntersLineMyPolyhedron( const Point3d& ptLineSt, const Vector3d& vtLineDir,
|
|
const Frame3d& PolyFrame, double dLenX, double dLenY, double dLenZ, double dDeltaX,
|
|
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, 0, dLenZ /2) ;
|
|
Point3d ptFacet246( dLenX + dDeltaX, dLenY, - dLenZ / 2) ;
|
|
|
|
// Servono per descrivere i piani obliqui
|
|
Vector3d vtFacet5 = ptFacet135 - ptP ;
|
|
Vector3d vtFacet6 = ptFacet246 - ptP ;
|
|
|
|
Vector3d vtOb( dLenY, - dDeltaX, 0) ;
|
|
|
|
vtOb.Normalize() ;
|
|
|
|
Point3d ptI1 = ptP + ( ( ptFacet135.z - ptP.z) / vtV.z) * vtV ;
|
|
Point3d ptI2 = ptP + ( ( ptFacet246.z - ptP.z) / vtV.z) * vtV ;
|
|
Point3d ptI3 = ptP + ( ( ptFacet135.y - ptP.y) / vtV.y) * vtV ;
|
|
Point3d ptI4 = ptP + ( ( ptFacet246.y - ptP.y) / vtV.y) * 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.z) < EPS_ZERO &&
|
|
abs( ptP.z) > dLenZ / 2 - EPS_SMALL)
|
|
return false ;
|
|
// Controllo sulle facce 3 e 4
|
|
if ( abs( vtV.y) < EPS_ZERO &&
|
|
( ptP.y < EPS_SMALL ||
|
|
ptP.y > dLenY - EPS_SMALL))
|
|
return false ;
|
|
// Controllo sulle facce 5 e 6
|
|
Vector3d vtW( dDeltaX, dLenY, 0) ;
|
|
vtW.Normalize() ;
|
|
Vector3d vtU = vtV - vtV.z * Z_AX - vtV * vtW * vtW ;
|
|
if ( vtU.Len() < EPS_ZERO &&
|
|
( ptP.x * dLenY < dDeltaX * ptP.y + dLenY * EPS_SMALL ||
|
|
ptP.x * dLenY > dDeltaX * ptP.y + dLenY * ( dLenX - EPS_SMALL)))
|
|
return false ;
|
|
|
|
// Ricerca intersezioni con le facce
|
|
int nIntNum = 0 ;
|
|
|
|
// Intersezione con la prima faccia
|
|
if ( ptI1.y >= 0 && ptI1.y <= dLenY &&
|
|
ptI1.x * dLenY >= dDeltaX * ptI1.y && ( ptI1.x - dLenX) * dLenY <= dDeltaX * ptI1.y) {
|
|
|
|
ptInt1 = ptI1 ;
|
|
vtN1 = - Z_AX ;
|
|
++ nIntNum ;
|
|
}
|
|
|
|
// Intersezione con la seconda faccia
|
|
if ( ptI2.y >= 0 && ptI2.y <= dLenY &&
|
|
ptI2.x * dLenY >= dDeltaX * ptI2.y && ( ptI2.x - dLenX) * dLenY <= dDeltaX * ptI2.y) {
|
|
if ( nIntNum == 0) {
|
|
ptInt1 = ptI2 ;
|
|
vtN1 = Z_AX ;
|
|
++ nIntNum ;
|
|
}
|
|
else if ( ( ptInt1 - ptI2).SqLen() > SQ_EPS_SMALL) {
|
|
ptInt2 = ptI2 ;
|
|
vtN2 = Z_AX ;
|
|
++ nIntNum ;
|
|
}
|
|
}
|
|
|
|
// Intersezione con la terza faccia
|
|
if ( nIntNum < 2 &&
|
|
ptI3.x >= 0 && ptI3.x <= dLenX &&
|
|
ptI3.z >= - ptFacet135.z && ptI3.z <= ptFacet135.z) {
|
|
if ( nIntNum == 0) {
|
|
ptInt1 = ptI3 ;
|
|
vtN1 = Y_AX ;
|
|
++ nIntNum ;
|
|
}
|
|
else if ( ( ptInt1 - ptI3).SqLen() > SQ_EPS_SMALL) {
|
|
ptInt2 = ptI3 ;
|
|
vtN2 = Y_AX ;
|
|
++ nIntNum ;
|
|
}
|
|
}
|
|
|
|
// Intersezione con la quarta faccia
|
|
if ( nIntNum < 2 &&
|
|
ptI4.x >= dDeltaX && ptI4.x <= dLenX + dDeltaX &&
|
|
ptI4.z >= - ptFacet135.z && ptI4.z <= ptFacet135.z) {
|
|
if ( nIntNum == 0) {
|
|
ptInt1 = ptI4 ;
|
|
vtN1 = - Y_AX ;
|
|
++ nIntNum ;
|
|
}
|
|
else if ( ( ptInt1 - ptI4).SqLen() > SQ_EPS_SMALL) {
|
|
ptInt2 = ptI4 ;
|
|
vtN2 = - Y_AX ;
|
|
++ nIntNum ;
|
|
}
|
|
}
|
|
|
|
// Intersezione con la quinta faccia
|
|
if ( nIntNum < 2 &&
|
|
ptI5.y >= 0 && ptI5.y <= dLenY &&
|
|
ptI5.z >= - ptFacet135.z && ptI5.z <= ptFacet135.z) {
|
|
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.y >= 0 && ptI6.y <= dLenY &&
|
|
ptI6.z >= - ptFacet135.z && ptI6.z <= ptFacet135.z) {
|
|
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 ;
|
|
}
|
|
|
|
|