4056be90d9
- modifiche a IntersLineBox e IntersPlaneBox - adattamenti conseguenti.
3396 lines
149 KiB
C++
3396 lines
149 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 "IntersLineBox.h"
|
|
#include "IntersLineSurfStd.h"
|
|
#include "/EgtDev/Include/EGkIntersLineTria.h"
|
|
#include "/EgtDev/Include/EGkIntersLinePlane.h"
|
|
#include "/EgtDev/Include/EGkIntersLineSphere.h"
|
|
#include "/EgtDev/Include/EGkIntersPlaneBox.h"
|
|
#include "/EgtDev/Include/EGkIntersPlaneTria.h"
|
|
#include "/EgtDev/Include/EGkChainCurves.h"
|
|
#include "/EgtDev/Include/ENkPolynomialRoots.h"
|
|
#include "/EgtDev/Include/EGnStringUtils.h"
|
|
#include "/EgtDev/Include/EgtNumUtils.h"
|
|
#include <future>
|
|
#include <atomic>
|
|
|
|
using namespace std ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
// 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 ;
|
|
if ( m_nMapNum == 3)
|
|
ptMax = ptMin + Vector3d( m_dMaxZ[1], m_dMaxZ[2], m_dMaxZ[0]) ;
|
|
else
|
|
ptMax = ptMin + Vector3d( ( m_nNx[0] + 0.5) * m_dStep, ( m_nNy[0] + 0.5) * 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, int nGrid, int nI, int nJ,
|
|
double& dU1, double& dU2) const
|
|
{
|
|
// Determino l'indice del dexel e il numero di suoi intervalli
|
|
int nDexelPos = nJ * m_nNx[nGrid] + nI ;
|
|
int nDexelSize = 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 ( 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, int nGrid, int nI, int nJ,
|
|
double& dU1, double& dU2) const
|
|
{
|
|
// Determino l'indice del dexel e il numero di suoi intervalli
|
|
int nDexelPos = nJ * m_nNx[nGrid] + nI ;
|
|
int nDexelSize = 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 ( 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 versore.
|
|
// 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
|
|
{
|
|
if ( bExact && m_nMapNum == 3)
|
|
return GetDepthWithVoxel( ptPLoc, vtDLoc, dInLength, dOutLength) ;
|
|
else {
|
|
return GetDepthWithDexel( ptPLoc, vtDLoc, 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& ptPLoc, const Vector3d& vtDLoc, double& dInLength, double& dOutLength) const
|
|
{
|
|
// Punto e direzione nel riferimento intrinseco
|
|
Point3d ptP = ptPLoc ;
|
|
Vector3d vtD = vtDLoc ;
|
|
ptP.ToLoc( m_MapFrame) ;
|
|
vtD.ToLoc( m_MapFrame) ;
|
|
vtD.Normalize() ;
|
|
|
|
// Intersezione fra semiretta e BBox dello Zmap
|
|
double dU1, dU2 ;
|
|
bool bTest = IntersLineZMapBBox( ptP, vtD, 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[N_MAPS] ;
|
|
double dOutLen[N_MAPS] ;
|
|
|
|
// Ciclo sulle griglie
|
|
for ( int nGrid = 0 ; nGrid < m_nMapNum ; ++ nGrid) {
|
|
|
|
Point3d ptP0 = ptP ;
|
|
Vector3d vtV0 = vtD ;
|
|
|
|
Point3d ptI, ptF ;
|
|
// Una sola intersezione valida ( punto interno, intersezione valida 2)
|
|
if ( dU1 < 0 && dU2 > 0) {
|
|
ptI = ptP ;
|
|
ptF = ptP + dU2 * vtD ;
|
|
}
|
|
// due soluzioni valide ( punto esterno)
|
|
else {
|
|
ptI = ptP + dU1 * vtD ;
|
|
ptF = ptP + dU2 * vtD ;
|
|
}
|
|
// 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 dV1, dV2 ;
|
|
if ( IntersRayDexel( ptP0, vtV0, nGrid, i, j, dV1, dV2)) {
|
|
dInLen[nGrid] = min( dInLen[nGrid], dV1) ;
|
|
dOutLen[nGrid] = max( dOutLen[nGrid], dV2) ;
|
|
}
|
|
|
|
// 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 < m_nMapNum ; ++ 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.
|
|
// 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) const
|
|
{
|
|
ILZIVECTOR vIntersInfo ;
|
|
if ( ! GetLineIntersection( ptP, vtD, vIntersInfo))
|
|
return false ;
|
|
|
|
if ( vIntersInfo.empty()) {
|
|
dInLength = -2. ;
|
|
dOutLength = -2. ;
|
|
return true ;
|
|
}
|
|
|
|
// Inizializzo le distanze di ingresso e uscita:
|
|
// dInLength diminuisce, dOutLength aumenta.
|
|
dInLength = INFINITO ;
|
|
dOutLength = -INFINITO ;
|
|
|
|
int nFirstPosN = 0 ;
|
|
for ( int nN = 0; nN < int( vIntersInfo.size()) ; ++ nN) {
|
|
if ( vIntersInfo[nN].dU > - EPS_SMALL) {
|
|
nFirstPosN = nN ;
|
|
break ;
|
|
}
|
|
}
|
|
|
|
if ( nFirstPosN == int( vIntersInfo.size())) {
|
|
dInLength = -2 ;
|
|
dOutLength = -2 ;
|
|
return true ;
|
|
}
|
|
|
|
if ( nFirstPosN > 0) {
|
|
if ( vIntersInfo[nFirstPosN - 1].trTria.GetN() * vtD < EPS_ZERO)
|
|
dInLength = -1 ;
|
|
}
|
|
else if ( nFirstPosN == 0) {
|
|
if ( vIntersInfo[nFirstPosN].trTria.GetN() * vtD > EPS_ZERO)
|
|
dInLength = -1 ;
|
|
else {
|
|
Point3d ptPi = ptP ;
|
|
ptPi.ToLoc( m_MapFrame) ;
|
|
int nVoxIJK[3] ;
|
|
GetBlockIJKFromN( vIntersInfo[0].nVox, nVoxIJK) ;
|
|
if ( GetPointVoxel( ptPi, nVoxIJK[0], nVoxIJK[1], nVoxIJK[2])) {
|
|
int nCubeType = CalcIndex( nVoxIJK[0], nVoxIJK[1], nVoxIJK[2]) ;
|
|
if ( nCubeType == 255)
|
|
dInLength = -1 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
for ( int nN = nFirstPosN ; nN < int( vIntersInfo.size()) ; ++ nN) {
|
|
if ( vIntersInfo[nN].trTria.GetN() * vtD > - EPS_ZERO) {
|
|
if ( ( vIntersInfo[nN].nILTT == ILTT_SEGM || vIntersInfo[nN].nILTT == ILTT_SEGM_ON_EDGE) &&
|
|
dOutLength < vIntersInfo[nN].dU2)
|
|
dOutLength = vIntersInfo[nN].dU2 ;
|
|
else if ( dOutLength < vIntersInfo[nN].dU)
|
|
dOutLength = vIntersInfo[nN].dU ;
|
|
}
|
|
if ( vIntersInfo[nN].trTria.GetN() * vtD < EPS_ZERO &&
|
|
dInLength > vIntersInfo[nN].dU)
|
|
dInLength = vIntersInfo[nN].dU ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::AvoidSimpleBox( const Frame3d& frBox, const Vector3d& vtDiag, bool bPrecise) const
|
|
{
|
|
// BBox
|
|
BBox3d b3Box( ORIG, ORIG + vtDiag) ;
|
|
|
|
// Porto il box 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 ;
|
|
|
|
// Se verifico solo prima mappa
|
|
if ( ! bPrecise) {
|
|
|
|
// 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 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// altrimenti verifico con tutte e tre le mappe
|
|
else {
|
|
// Ciclo di intersezione dei dexel con il BBox
|
|
for ( int nMap = 0 ; nMap < m_nMapNum ; ++ nMap) {
|
|
Point3d ptO = ORIG ;
|
|
Vector3d vtX = X_AX ;
|
|
Vector3d vtY = Y_AX ;
|
|
Vector3d vtK = Z_AX ;
|
|
// Estremi del box
|
|
Point3d ptBoxInf = b3Int.GetMin() ;
|
|
Point3d ptBoxSup = b3Int.GetMax() ;
|
|
if ( nMap == 1) {
|
|
swap( ptBoxInf.x, ptBoxInf.z) ;
|
|
swap( ptBoxInf.x, ptBoxInf.y) ;
|
|
swap( ptBoxSup.x, ptBoxSup.z) ;
|
|
swap( ptBoxSup.x, ptBoxSup.y) ;
|
|
vtX = Y_AX ;
|
|
vtY = Z_AX ;
|
|
vtK = X_AX ;
|
|
}
|
|
else if ( nMap == 2) {
|
|
swap( ptBoxInf.y, ptBoxInf.z) ;
|
|
swap( ptBoxInf.x, ptBoxInf.y) ;
|
|
swap( ptBoxSup.y, ptBoxSup.z) ;
|
|
swap( ptBoxSup.x, ptBoxSup.y) ;
|
|
vtX = Z_AX ;
|
|
vtY = X_AX ;
|
|
vtK = Y_AX ;
|
|
}
|
|
// Passo da sistema griglia a sistema BBox
|
|
ptO.ToLoc( frBox) ;
|
|
vtX.ToLoc( frBox) ;
|
|
vtY.ToLoc( frBox) ;
|
|
vtK.ToLoc( frBox) ;
|
|
// Limiti su indici
|
|
int nStI = Clamp( int( ptBoxInf.x / m_dStep), 0, m_nNx[nMap] - 1) ;
|
|
int nEnI = Clamp( int( ptBoxSup.x / m_dStep), 0, m_nNx[nMap] - 1) ;
|
|
int nStJ = Clamp( int( ptBoxInf.y / m_dStep), 0, m_nNy[nMap] - 1) ;
|
|
int nEnJ = Clamp( int( ptBoxSup.y / m_dStep), 0, m_nNy[nMap] - 1) ;
|
|
// Ciclo sui dexel.
|
|
for ( int i = nStI ; i <= nEnI ; ++ i) {
|
|
for ( int j = nStJ ; j <= nEnJ ; ++ j) {
|
|
int nPos = j * m_nNx[nMap] + i;
|
|
int nSize = int( m_Values[nMap][nPos].size()) ;
|
|
if ( nSize == 0)
|
|
continue ;
|
|
Point3d ptT = ptO + ( i + 0.5) * m_dStep * vtX + ( j + 0.5) * m_dStep * vtY ;
|
|
double dMinU, dMaxU ;
|
|
// La retta associata al dexel interseca il box.
|
|
if ( IntersLineBox( ptT, vtK, ORIG, ORIG + vtDiag, dMinU, dMaxU)) {
|
|
// Ciclo sui segmenti del dexel
|
|
for ( int nIndex = 0 ; nIndex < nSize ; nIndex += 1) {
|
|
// Se il segmento è interno all'intervallo d'intersezione, ho finito.
|
|
if ( dMaxU > m_Values[nMap][nPos][nIndex].dMin - EPS_SMALL &&
|
|
dMinU < m_Values[nMap][nPos][nIndex].dMax + EPS_SMALL)
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::AvoidBox( const Frame3d& frBox, const Vector3d& vtDiag, double dSafeDist, bool bPrecise) const
|
|
{
|
|
// Se distanza di sicurezza nulla
|
|
if ( dSafeDist < EPS_SMALL)
|
|
return AvoidSimpleBox( frBox, vtDiag, bPrecise) ;
|
|
|
|
// Verifica preliminare con box esteso
|
|
Frame3d frEst = frBox ; frEst.Translate( -dSafeDist * ( frBox.VersX() + frBox.VersY() + frBox.VersZ())) ;
|
|
if ( AvoidSimpleBox( frEst, vtDiag + 2 * Vector3d( dSafeDist, dSafeDist, dSafeDist), bPrecise))
|
|
return true ;
|
|
|
|
// Tre box aumentati con distanza di sicurezza in un sola dimensione
|
|
Frame3d frTmp = frBox ; frTmp.Translate( -dSafeDist * frBox.VersX()) ;
|
|
if ( ! AvoidSimpleBox( frTmp, vtDiag + 2 * dSafeDist * X_AX, bPrecise))
|
|
return false ;
|
|
frTmp = frBox ; frTmp.Translate( -dSafeDist * frBox.VersY()) ;
|
|
if ( ! AvoidSimpleBox( frTmp, vtDiag + 2 * dSafeDist * Y_AX, bPrecise))
|
|
return false ;
|
|
frTmp = frBox ; frTmp.Translate( -dSafeDist * frBox.VersZ()) ;
|
|
if ( ! AvoidSimpleBox( frTmp, vtDiag + 2 * dSafeDist * Z_AX, bPrecise))
|
|
return false ;
|
|
|
|
// Vertici del box
|
|
Point3d ptVert0 = frBox.Orig() ;
|
|
Point3d ptVert1 = ptVert0 + vtDiag.x * frBox.VersX() ;
|
|
Point3d ptVert2 = ptVert0 + vtDiag.y * frBox.VersY() ;
|
|
Point3d ptVert3 = ptVert1 + vtDiag.y * frBox.VersY() ;
|
|
Point3d ptVert4 = ptVert0 + vtDiag.z * frBox.VersZ() ;
|
|
Point3d ptVert5 = ptVert1 + vtDiag.z * frBox.VersZ() ;
|
|
Point3d ptVert6 = ptVert2 + vtDiag.z * frBox.VersZ() ;
|
|
Point3d ptVert7 = ptVert3 + vtDiag.z * frBox.VersZ() ;
|
|
|
|
// Sfere centrate negli otto vertici
|
|
if ( ! AvoidSimpleSphere( ptVert0, dSafeDist, bPrecise))
|
|
return false ;
|
|
if ( ! AvoidSimpleSphere( ptVert1, dSafeDist, bPrecise))
|
|
return false ;
|
|
if ( ! AvoidSimpleSphere( ptVert2, dSafeDist, bPrecise))
|
|
return false ;
|
|
if ( ! AvoidSimpleSphere( ptVert3, dSafeDist, bPrecise))
|
|
return false ;
|
|
if ( ! AvoidSimpleSphere( ptVert4, dSafeDist, bPrecise))
|
|
return false ;
|
|
if ( ! AvoidSimpleSphere( ptVert5, dSafeDist, bPrecise))
|
|
return false ;
|
|
if ( ! AvoidSimpleSphere( ptVert6, dSafeDist, bPrecise))
|
|
return false ;
|
|
if ( ! AvoidSimpleSphere( ptVert7, dSafeDist, bPrecise))
|
|
return false ;
|
|
|
|
// Cilindri centrati sui dodici spigoli
|
|
frTmp.Set( ptVert0, frBox.VersX()) ;
|
|
if ( ! AvoidSimpleCylinder( frTmp, dSafeDist, vtDiag.x, bPrecise))
|
|
return false ;
|
|
frTmp.Set( ptVert2, frBox.VersX()) ;
|
|
if ( ! AvoidSimpleCylinder( frTmp, dSafeDist, vtDiag.x, bPrecise))
|
|
return false ;
|
|
frTmp.Set( ptVert0, frBox.VersY()) ;
|
|
if ( ! AvoidSimpleCylinder( frTmp, dSafeDist, vtDiag.y, bPrecise))
|
|
return false ;
|
|
frTmp.Set( ptVert1, frBox.VersY()) ;
|
|
if ( ! AvoidSimpleCylinder( frTmp, dSafeDist, vtDiag.y, bPrecise))
|
|
return false ;
|
|
frTmp.Set( ptVert4, frBox.VersX()) ;
|
|
if ( ! AvoidSimpleCylinder( frTmp, dSafeDist, vtDiag.x, bPrecise))
|
|
return false ;
|
|
frTmp.Set( ptVert6, frBox.VersX()) ;
|
|
if ( ! AvoidSimpleCylinder( frTmp, dSafeDist, vtDiag.x, bPrecise))
|
|
return false ;
|
|
frTmp.Set( ptVert4, frBox.VersY()) ;
|
|
if ( ! AvoidSimpleCylinder( frTmp, dSafeDist, vtDiag.y, bPrecise))
|
|
return false ;
|
|
frTmp.Set( ptVert5, frBox.VersY()) ;
|
|
if ( ! AvoidSimpleCylinder( frTmp, dSafeDist, vtDiag.y, bPrecise))
|
|
return false ;
|
|
frTmp.Set( ptVert0, frBox.VersZ()) ;
|
|
if ( ! AvoidSimpleCylinder( frTmp, dSafeDist, vtDiag.z, bPrecise))
|
|
return false ;
|
|
frTmp.Set( ptVert1, frBox.VersZ()) ;
|
|
if ( ! AvoidSimpleCylinder( frTmp, dSafeDist, vtDiag.z, bPrecise))
|
|
return false ;
|
|
frTmp.Set( ptVert2, frBox.VersZ()) ;
|
|
if ( ! AvoidSimpleCylinder( frTmp, dSafeDist, vtDiag.z, bPrecise))
|
|
return false ;
|
|
frTmp.Set( ptVert3, frBox.VersZ()) ;
|
|
if ( ! AvoidSimpleCylinder( frTmp, dSafeDist, vtDiag.z, bPrecise))
|
|
return false ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::AvoidSimpleSphere( const Point3d& ptCenter, double dRad, bool bPrecise) 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 ;
|
|
|
|
// Se verifico solo prima mappa
|
|
if ( ! bPrecise) {
|
|
|
|
// 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 ;
|
|
if ( m_Values[0][nPos][nSize-1].dMax < b3Int.GetMin().z || m_Values[0][nPos][0].dMin > b3Int.GetMax().z)
|
|
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 ;
|
|
switch ( k) {
|
|
case 0 : break ;
|
|
case 1 : ptT += -0.4 * m_dStep * X_AX - 0.4 * m_dStep * Y_AX ; break ;
|
|
case 2 : ptT += +0.4 * m_dStep * X_AX - 0.4 * m_dStep * Y_AX ; break ;
|
|
case 3 : ptT += +0.4 * m_dStep * X_AX + 0.4 * m_dStep * Y_AX ; break ;
|
|
case 4 : ptT += -0.4 * m_dStep * X_AX + 0.4 * m_dStep * Y_AX ; break ;
|
|
}
|
|
Point3d ptI1, ptI2 ;
|
|
if ( ::IntersLineSphere( ptT, Z_AX, ptC, dRad, ptI1, ptI2) != ILST_NO) {
|
|
double dZmin = min( ptI1.z, ptI2.z) ;
|
|
double dZmax = max( ptI1.z, 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 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// altrimenti verifico con tutte e tre le mappe
|
|
else {
|
|
// Ciclo di intersezione dei dexel con la sfera (nel riferimento intrinseco)
|
|
for ( int nMap = 0 ; nMap < m_nMapNum ; ++ nMap) {
|
|
Vector3d vtX = X_AX ;
|
|
Vector3d vtY = Y_AX ;
|
|
Vector3d vtK = Z_AX ;
|
|
// Estremi del box
|
|
Point3d ptBoxInf = b3Int.GetMin() ;
|
|
Point3d ptBoxSup = b3Int.GetMax() ;
|
|
if ( nMap == 1) {
|
|
swap( ptBoxInf.x, ptBoxInf.z) ;
|
|
swap( ptBoxInf.x, ptBoxInf.y) ;
|
|
swap( ptBoxSup.x, ptBoxSup.z) ;
|
|
swap( ptBoxSup.x, ptBoxSup.y) ;
|
|
vtX = Y_AX ;
|
|
vtY = Z_AX ;
|
|
vtK = X_AX ;
|
|
}
|
|
else if ( nMap == 2) {
|
|
swap( ptBoxInf.y, ptBoxInf.z) ;
|
|
swap( ptBoxInf.x, ptBoxInf.y) ;
|
|
swap( ptBoxSup.y, ptBoxSup.z) ;
|
|
swap( ptBoxSup.x, ptBoxSup.y) ;
|
|
vtX = Z_AX ;
|
|
vtY = X_AX ;
|
|
vtK = Y_AX ;
|
|
}
|
|
// Limiti su indici
|
|
int nStI = Clamp( int( ptBoxInf.x / m_dStep), 0, m_nNx[nMap] - 1) ;
|
|
int nEnI = Clamp( int( ptBoxSup.x / m_dStep), 0, m_nNx[nMap] - 1) ;
|
|
int nStJ = Clamp( int( ptBoxInf.y / m_dStep), 0, m_nNy[nMap] - 1) ;
|
|
int nEnJ = Clamp( int( ptBoxSup.y / m_dStep), 0, m_nNy[nMap] - 1) ;
|
|
// Ciclo sui dexel.
|
|
for ( int i = nStI ; i <= nEnI ; ++ i) {
|
|
for ( int j = nStJ ; j <= nEnJ ; ++ j) {
|
|
int nPos = j * m_nNx[nMap] + i ;
|
|
int nSize = int( m_Values[nMap][nPos].size()) ;
|
|
if ( nSize == 0)
|
|
continue ;
|
|
if ( m_Values[nMap][nPos][nSize-1].dMax < b3Int.GetMin().z || m_Values[nMap][nPos][0].dMin > b3Int.GetMax().z)
|
|
continue ;
|
|
Point3d ptT = ORIG + ( i + 0.5) * m_dStep * vtX + ( j + 0.5) * m_dStep * vtY ;
|
|
Point3d ptI1, ptI2 ;
|
|
// La linea del dexel interseca la sfera.
|
|
if ( ::IntersLineSphere( ptT, vtK, ptC, dRad, ptI1, ptI2) != ILST_NO) {
|
|
double dMinU, dMaxU ;
|
|
if ( nMap == 0) {
|
|
dMinU = min( ptI1.z, ptI2.z) ;
|
|
dMaxU = max( ptI1.z, ptI2.z) ;
|
|
}
|
|
else if ( nMap == 1) {
|
|
dMinU = min( ptI1.x, ptI2.x) ;
|
|
dMaxU = max( ptI1.x, ptI2.x) ;
|
|
}
|
|
else {
|
|
dMinU = min( ptI1.y, ptI2.y) ;
|
|
dMaxU = max( ptI1.y, ptI2.y) ;
|
|
}
|
|
// Ciclo sui segmenti del dexel.
|
|
for ( int nIndex = 0 ; nIndex < nSize ; nIndex += 1) {
|
|
// Se il segmento è interno all'intervallo d'intersezione, ho finito.
|
|
if ( dMaxU > m_Values[nMap][nPos][nIndex].dMin - EPS_SMALL &&
|
|
dMinU < m_Values[nMap][nPos][nIndex].dMax + EPS_SMALL)
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::AvoidSphere( const Point3d& ptCenter, double dRad, double dSafeDist, bool bPrecise) const
|
|
{
|
|
return AvoidSimpleSphere( ptCenter, dRad + max( 0., dSafeDist), bPrecise) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::AvoidSimpleCylinder( const Frame3d& frCyl, double dR, double dH, bool bPrecise) const
|
|
{
|
|
// Porto il cilindro nel riferimento intrinseco dello Zmap
|
|
Frame3d frC = frCyl ;
|
|
frC.ToLoc( m_MapFrame) ;
|
|
|
|
// BBox del cilindro
|
|
Vector3d vtDirL = frC.VersZ() ;
|
|
BBox3d b3Box( frC.Orig()) ;
|
|
b3Box.Add( frC.Orig() + frC.VersZ() * dH) ;
|
|
if ( vtDirL.IsXplus() || vtDirL.IsXminus())
|
|
b3Box.Expand( 0, dR, dR) ;
|
|
else if ( vtDirL.IsYplus() || vtDirL.IsYminus())
|
|
b3Box.Expand( dR, 0, dR) ;
|
|
else if ( vtDirL.IsZplus() || vtDirL.IsZminus())
|
|
b3Box.Expand( dR, dR, 0) ;
|
|
else {
|
|
double dExpandX = dR * sqrt( 1 - vtDirL.x * vtDirL.x) ;
|
|
double dExpandY = dR * sqrt( 1 - vtDirL.y * vtDirL.y) ;
|
|
double dExpandZ = dR * sqrt( 1 - vtDirL.z * vtDirL.z) ;
|
|
b3Box.Expand( dExpandX, dExpandY, dExpandZ) ;
|
|
}
|
|
|
|
// 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 ;
|
|
|
|
// Se verifico solo prima mappa
|
|
if ( ! bPrecise) {
|
|
|
|
// 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 il cilindro (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 ;
|
|
if ( m_Values[0][nPos][nSize-1].dMax < b3Int.GetMin().z || m_Values[0][nPos][0].dMin > b3Int.GetMax().z)
|
|
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 ;
|
|
switch ( k) {
|
|
case 0 : break ;
|
|
case 1 : ptT += -0.4 * m_dStep * X_AX - 0.4 * m_dStep * Y_AX ; break ;
|
|
case 2 : ptT += +0.4 * m_dStep * X_AX - 0.4 * m_dStep * Y_AX ; break ;
|
|
case 3 : ptT += +0.4 * m_dStep * X_AX + 0.4 * m_dStep * Y_AX ; break ;
|
|
case 4 : ptT += -0.4 * m_dStep * X_AX + 0.4 * m_dStep * Y_AX ; break ;
|
|
}
|
|
Point3d ptI1, ptI2 ;
|
|
Vector3d vtN1, vtN2 ;
|
|
if ( IntersLineCylinder( ptT, Z_AX, frC, dH, dR, true, true, ptI1, vtN1, ptI2, vtN2)) {
|
|
double dZmin = min( ptI1.z, ptI2.z) ;
|
|
double dZmax = max( ptI1.z, 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 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// altrimenti verifico con tutte e tre le mappe
|
|
else {
|
|
// Ciclo di intersezione dei dexel con il cilindro (nel riferimento intrinseco)
|
|
for ( int nMap = 0 ; nMap < m_nMapNum ; ++ nMap) {
|
|
Vector3d vtX = X_AX ;
|
|
Vector3d vtY = Y_AX ;
|
|
Vector3d vtK = Z_AX ;
|
|
// Estremi del box
|
|
Point3d ptBoxInf = b3Int.GetMin() ;
|
|
Point3d ptBoxSup = b3Int.GetMax() ;
|
|
if ( nMap == 1) {
|
|
swap( ptBoxInf.x, ptBoxInf.z) ;
|
|
swap( ptBoxInf.x, ptBoxInf.y) ;
|
|
swap( ptBoxSup.x, ptBoxSup.z) ;
|
|
swap( ptBoxSup.x, ptBoxSup.y) ;
|
|
vtX = Y_AX ;
|
|
vtY = Z_AX ;
|
|
vtK = X_AX ;
|
|
}
|
|
else if ( nMap == 2) {
|
|
swap( ptBoxInf.y, ptBoxInf.z) ;
|
|
swap( ptBoxInf.x, ptBoxInf.y) ;
|
|
swap( ptBoxSup.y, ptBoxSup.z) ;
|
|
swap( ptBoxSup.x, ptBoxSup.y) ;
|
|
vtX = Z_AX ;
|
|
vtY = X_AX ;
|
|
vtK = Y_AX ;
|
|
}
|
|
// Limiti su indici
|
|
int nStI = Clamp( int( ptBoxInf.x / m_dStep), 0, m_nNx[nMap] - 1) ;
|
|
int nEnI = Clamp( int( ptBoxSup.x / m_dStep), 0, m_nNx[nMap] - 1) ;
|
|
int nStJ = Clamp( int( ptBoxInf.y / m_dStep), 0, m_nNy[nMap] - 1) ;
|
|
int nEnJ = Clamp( int( ptBoxSup.y / m_dStep), 0, m_nNy[nMap] - 1) ;
|
|
// Ciclo sui dexel.
|
|
for ( int i = nStI ; i <= nEnI ; ++ i) {
|
|
for ( int j = nStJ ; j <= nEnJ ; ++ j) {
|
|
int nPos = j * m_nNx[nMap] + i ;
|
|
int nSize = int( m_Values[nMap][nPos].size()) ;
|
|
if ( nSize == 0)
|
|
continue ;
|
|
if ( m_Values[nMap][nPos][nSize-1].dMax < b3Int.GetMin().z || m_Values[nMap][nPos][0].dMin > b3Int.GetMax().z)
|
|
continue ;
|
|
Point3d ptT = ORIG + ( i + 0.5) * m_dStep * vtX + ( j + 0.5) * m_dStep * vtY ;
|
|
Point3d ptI1, ptI2 ;
|
|
Vector3d vtN1, vtN2 ;
|
|
// La linea del dexel interseca il cilindro.
|
|
if ( IntersLineCylinder( ptT, vtK, frC, dH, dR, true, true, ptI1, vtN1, ptI2, vtN2)) {
|
|
double dMinU, dMaxU ;
|
|
if ( nMap == 0) {
|
|
dMinU = min( ptI1.z, ptI2.z) ;
|
|
dMaxU = max( ptI1.z, ptI2.z) ;
|
|
}
|
|
else if ( nMap == 1) {
|
|
dMinU = min( ptI1.x, ptI2.x) ;
|
|
dMaxU = max( ptI1.x, ptI2.x) ;
|
|
}
|
|
else {
|
|
dMinU = min( ptI1.y, ptI2.y) ;
|
|
dMaxU = max( ptI1.y, ptI2.y) ;
|
|
}
|
|
// Ciclo sui segmenti del dexel.
|
|
for ( int nIndex = 0 ; nIndex < nSize ; nIndex += 1) {
|
|
// Se il segmento è interno all'intervallo d'intersezione, ho finito.
|
|
if ( dMaxU > m_Values[nMap][nPos][nIndex].dMin - EPS_SMALL &&
|
|
dMinU < m_Values[nMap][nPos][nIndex].dMax + EPS_SMALL)
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::AvoidCylinder( const Frame3d& frCyl, double dR, double dH, double dSafeDist, bool bPrecise) const
|
|
{
|
|
// Se altezza negativa, sposto riferimento da faccia sopra a quella sotto
|
|
Frame3d frC = frCyl ;
|
|
if ( dH < 0) {
|
|
frC.Translate( dH * frC.VersZ()) ;
|
|
dH = - dH ;
|
|
}
|
|
|
|
// Se distanza di sicurezza nulla
|
|
if ( dSafeDist < EPS_SMALL)
|
|
return AvoidSimpleCylinder( frC, dR, dH, bPrecise) ;
|
|
|
|
// Verifica preliminare con cilindro esteso
|
|
Frame3d frEst = frC ; frEst.Translate( -dSafeDist * frC.VersZ()) ;
|
|
if ( AvoidSimpleCylinder( frEst, dR + dSafeDist, dH + 2 * dSafeDist, bPrecise))
|
|
return true ;
|
|
|
|
// Cilindro allargato
|
|
if ( ! AvoidSimpleCylinder( frC, dR + dSafeDist, dH, bPrecise))
|
|
return false ;
|
|
// Cilindro allungato
|
|
Frame3d frTmp = frC ; frTmp.Translate( - dSafeDist * frC.VersZ()) ;
|
|
if ( ! AvoidSimpleCylinder( frTmp, dR, dH + 2 * dSafeDist, bPrecise))
|
|
return false ;
|
|
// Toro inferiore
|
|
if ( ! AvoidSimpleTorus( frC, dR, dSafeDist, bPrecise))
|
|
return false ;
|
|
// Toro superiore
|
|
frTmp = frC ; frTmp.Translate( dH * frC.VersZ()) ;
|
|
if ( ! AvoidSimpleTorus( frTmp, dR, dSafeDist, bPrecise))
|
|
return false ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::SingleMapDexelConeCollision( int nStI, int nEnI, int nStJ, int nEnJ, const Point3d& ptRefPoint, const Vector3d& vtRefAx,
|
|
double dMinRad, double dMaxRad, double dHeight, double dMinBoxH, double dMaxBoxH) const
|
|
{
|
|
// Ciclo di intersezione dei dexel con il cono (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 ;
|
|
double dParMin = m_Values[0][nPos][0].dMin ;
|
|
double dParMax = m_Values[0][nPos][nSize-1].dMax ;
|
|
if ( dParMax < dMinBoxH || dParMin > dMaxBoxH)
|
|
continue ;
|
|
for ( int k = 0 ; k < 5 ; ++ k) {
|
|
// se richiesta interruzione, esco
|
|
if ( m_bBreak)
|
|
return false ;
|
|
// Calcolo spillone
|
|
Point3d ptLineSt = ORIG + ( i + 0.5) * m_dStep * X_AX + ( j + 0.5) * m_dStep * Y_AX ;
|
|
switch ( k) {
|
|
case 0 : break ;
|
|
case 1 : ptLineSt += -0.4 * m_dStep * X_AX - 0.4 * m_dStep * Y_AX ; break ;
|
|
case 2 : ptLineSt += +0.4 * m_dStep * X_AX - 0.4 * m_dStep * Y_AX ; break ;
|
|
case 3 : ptLineSt += +0.4 * m_dStep * X_AX + 0.4 * m_dStep * Y_AX ; break ;
|
|
case 4 : ptLineSt += -0.4 * m_dStep * X_AX + 0.4 * m_dStep * Y_AX ; break ;
|
|
}
|
|
// Cono proprio
|
|
if ( dMinRad < EPS_SMALL) {
|
|
Point3d ptSegSt = ptLineSt + dParMin * Z_AX ;
|
|
double dU1, dU2 ;
|
|
int nIntType = SegmentCone( ptSegSt, Z_AX, dParMax - dParMin, ptRefPoint, vtRefAx,
|
|
dMaxRad, dHeight, dU1, dU2) ;
|
|
if ( nIntType == LinCompCCIntersType::CC_ERROR_INT)
|
|
return true ;
|
|
else if ( nIntType != LinCompCCIntersType::CC_NO_INTERS) {
|
|
for ( int nIndex = 0 ; nIndex < nSize ; nIndex += 1) {
|
|
if ( m_Values[0][nPos][nIndex].dMax >= dU1 && m_Values[0][nPos][nIndex].dMin <= dU2)
|
|
return true ;
|
|
}
|
|
}
|
|
nIntType = SegmentDisc( ptSegSt, Z_AX, dParMax - dParMin, ptRefPoint + dHeight * vtRefAx,
|
|
vtRefAx, dMaxRad, dU1, dU2) ;
|
|
if ( nIntType == LinCompDiscIntersType::D_ERROR_INT)
|
|
return true ;
|
|
else if ( nIntType != LinCompDiscIntersType::D_NO_INTERS) {
|
|
for ( int nIndex = 0 ; nIndex < nSize ; nIndex += 1) {
|
|
if ( m_Values[0][nPos][nIndex].dMax >= dU1 && m_Values[0][nPos][nIndex].dMin <= dU2)
|
|
return true ;
|
|
}
|
|
}
|
|
}
|
|
// Tronco di cono
|
|
else {
|
|
Point3d ptSegSt = ptLineSt + dParMin * Z_AX ;
|
|
double dU1, dU2 ;
|
|
int nIntType = SegmentConeFrustum( ptSegSt, Z_AX, dParMax - dParMin, ptRefPoint, vtRefAx,
|
|
dMinRad, dMaxRad, dHeight, dU1, dU2) ;
|
|
if ( nIntType == LinCompCCIntersType::CC_ERROR_INT)
|
|
return true ;
|
|
else if ( nIntType != LinCompCCIntersType::CC_NO_INTERS) {
|
|
for ( int nIndex = 0 ; nIndex < nSize ; nIndex += 1) {
|
|
if ( m_Values[0][nPos][nIndex].dMax >= dU1 && m_Values[0][nPos][nIndex].dMin <= dU2)
|
|
return true ;
|
|
}
|
|
}
|
|
nIntType = SegmentDisc( ptSegSt, Z_AX, dParMax - dParMin, ptRefPoint + dHeight * vtRefAx,
|
|
vtRefAx, dMaxRad, dU1, dU2) ;
|
|
if ( nIntType == LinCompDiscIntersType::D_ERROR_INT)
|
|
return true ;
|
|
else if ( nIntType != LinCompDiscIntersType::D_NO_INTERS) {
|
|
for ( int nIndex = 0 ; nIndex < nSize ; nIndex += 1) {
|
|
if ( m_Values[0][nPos][nIndex].dMax >= dU1 && m_Values[0][nPos][nIndex].dMin <= dU2)
|
|
return true ;
|
|
}
|
|
}
|
|
nIntType = SegmentDisc( ptSegSt, Z_AX, dParMax - dParMin, ptRefPoint, vtRefAx, dMinRad, dU1, dU2) ;
|
|
if ( nIntType == LinCompDiscIntersType::D_ERROR_INT)
|
|
return true ;
|
|
else if ( nIntType != LinCompDiscIntersType::D_NO_INTERS) {
|
|
for ( int nIndex = 0 ; nIndex < nSize ; nIndex += 1) {
|
|
if ( m_Values[0][nPos][nIndex].dMax >= dU1 && m_Values[0][nPos][nIndex].dMin <= dU2)
|
|
return true ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::AvoidSimpleConeFrustum( const Frame3d& frCone, double dMinRad, double dMaxRad, double dHeight, bool bPrecise) const
|
|
{
|
|
// Porto il tronco di cono nel sistema intrinseco e normalizzo il vettore.
|
|
Point3d ptRefPoint = frCone.Orig() ;
|
|
Vector3d vtRefAx = frCone.VersZ() ;
|
|
ptRefPoint.ToLoc( m_MapFrame) ;
|
|
vtRefAx.ToLoc( m_MapFrame) ;
|
|
|
|
// BBox del tronco di cono
|
|
BBox3d b3Box( ptRefPoint) ;
|
|
b3Box.Add( ptRefPoint + vtRefAx * dHeight) ;
|
|
if ( vtRefAx.IsXplus() || vtRefAx.IsXminus())
|
|
b3Box.Expand( 0, dMaxRad, dMaxRad) ;
|
|
else if ( vtRefAx.IsYplus() || vtRefAx.IsYminus())
|
|
b3Box.Expand( dMaxRad, 0, dMaxRad) ;
|
|
else if ( vtRefAx.IsZplus() || vtRefAx.IsZminus())
|
|
b3Box.Expand( dMaxRad, dMaxRad, 0) ;
|
|
else {
|
|
double dExpandX = dMaxRad * sqrt( 1 - vtRefAx.x * vtRefAx.x) ;
|
|
double dExpandY = dMaxRad * sqrt( 1 - vtRefAx.y * vtRefAx.y) ;
|
|
double dExpandZ = dMaxRad * sqrt( 1 - vtRefAx.z * vtRefAx.z) ;
|
|
b3Box.Expand( dExpandX, dExpandY, dExpandZ) ;
|
|
}
|
|
|
|
// 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 ;
|
|
|
|
// Uso solo la prima mappa
|
|
if ( ! bPrecise) {
|
|
// 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) ;
|
|
// Limiti su Z
|
|
double dZmin = b3Int.GetMin().z ;
|
|
double dZmax = b3Int.GetMax().z ;
|
|
// Numero massimo di thread
|
|
int nThreadMax = max( 1, int( thread::hardware_concurrency()) - 1) ;
|
|
// se un solo thread
|
|
if ( nThreadMax == 1) {
|
|
m_bBreak = false ;
|
|
bool bCollision = SingleMapDexelConeCollision( nStI, nEnI, nStJ, nEnJ, ptRefPoint, vtRefAx,
|
|
dMinRad, dMaxRad, dHeight, dZmin, dZmax) ;
|
|
return ( ! bCollision) ;
|
|
}
|
|
// altrimenti esecuzione in parallelo dei calcoli
|
|
else {
|
|
//string sOut = "I=" + ToString( nStI) + "," + ToString( nEnI) + " J=" + ToString( nStJ) + "," + ToString( nEnJ) ;
|
|
//LOG_INFO( GetEGkLogger(), sOut.c_str())
|
|
m_bBreak = false ;
|
|
// lancio dei thread
|
|
int nSpanI = ( nEnI - nStI + 1) / nThreadMax + 1 ;
|
|
int nSpanJ = ( nEnJ - nStJ + 1) / nThreadMax + 1 ;
|
|
bool bOnI = ( nSpanI >= nSpanJ) ;
|
|
int nThreadTot = 0 ;
|
|
vector< future<bool>> vRes( nThreadMax) ;
|
|
for ( int nT = 0 ; nT < nThreadMax ; ++ nT) {
|
|
int nMyStI = ( bOnI ? nStI + nT * nSpanI : nStI) ;
|
|
int nMyEnI = ( bOnI ? min( nMyStI + nSpanI - 1, nEnI) : nEnI) ;
|
|
int nMyStJ = ( bOnI ? nStJ : nStJ + nT * nSpanJ) ;
|
|
int nMyEnJ = ( bOnI ? nEnJ : min( nMyStJ + nSpanJ - 1, nEnJ)) ;
|
|
if ( nMyStI > nEnI || nMyStJ > nEnJ)
|
|
break ;
|
|
//string sOut = "MyI=" + ToString( nMyStI) + "," + ToString( nMyEnI) + " MyJ=" + ToString( nMyStJ) + "," + ToString( nMyEnJ) ;
|
|
//LOG_INFO( GetEGkLogger(), sOut.c_str())
|
|
vRes[nT] = async( launch::async, &VolZmap::SingleMapDexelConeCollision, this,
|
|
nMyStI, nMyEnI, nMyStJ, nMyEnJ, cref( ptRefPoint), cref( vtRefAx),
|
|
dMinRad, dMaxRad, dHeight, dZmin, dZmax) ;
|
|
++ nThreadTot ;
|
|
}
|
|
// recupero i risultati dei thread alla loro terminazione
|
|
bool bCollision = false ;
|
|
int nTerminated = 0 ;
|
|
while ( nTerminated < nThreadTot) {
|
|
for ( int nT = 0 ; nT < nThreadTot ; ++ nT) {
|
|
// Async terminato
|
|
if ( vRes[nT].valid() && vRes[nT].wait_for( chrono::nanoseconds{ 1}) == future_status::ready) {
|
|
++ nTerminated ;
|
|
// Se c'è collisione ...
|
|
if ( vRes[nT].get()) {
|
|
bCollision = true ;
|
|
m_bBreak = true ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ( ! bCollision) ;
|
|
}
|
|
}
|
|
|
|
// Uso tutte le mappe
|
|
else {
|
|
// Ciclo sulle mappe.
|
|
for ( int nMap = 0 ; nMap < m_nMapNum ; ++ nMap) {
|
|
Point3d ptInfIntBox = b3Int.GetMin() ;
|
|
Point3d ptSupIntBox = b3Int.GetMax() ;
|
|
// Dal sistema intrinseco al sistema griglia (per la prima griglia coincidono).
|
|
if ( nMap == 1) {
|
|
swap( ptInfIntBox.x, ptInfIntBox.z) ;
|
|
swap( ptInfIntBox.x, ptInfIntBox.y) ;
|
|
swap( ptSupIntBox.x, ptSupIntBox.z) ;
|
|
swap( ptSupIntBox.x, ptSupIntBox.y) ;
|
|
}
|
|
else if ( nMap == 2) {
|
|
swap( ptInfIntBox.y, ptInfIntBox.z) ;
|
|
swap( ptInfIntBox.x, ptInfIntBox.y) ;
|
|
swap( ptSupIntBox.y, ptSupIntBox.z) ;
|
|
swap( ptSupIntBox.x, ptSupIntBox.y) ;
|
|
}
|
|
// Limiti su indici
|
|
int nStI = Clamp( int( ptInfIntBox.x / m_dStep), 0, m_nNx[nMap] - 1) ;
|
|
int nEnI = Clamp( int( ptSupIntBox.x / m_dStep), 0, m_nNx[nMap] - 1) ;
|
|
int nStJ = Clamp( int( ptInfIntBox.y / m_dStep), 0, m_nNy[nMap] - 1) ;
|
|
int nEnJ = Clamp( int( ptSupIntBox.y / m_dStep), 0, m_nNy[nMap] - 1) ;
|
|
// Ciclo sui dexel.
|
|
for ( int nDex = 0 ; nDex < int( m_Values[nMap].size()) ; ++ nDex) {
|
|
int nDexSize = (int)m_Values[nMap][nDex].size() ;
|
|
if ( nDexSize == 0 ||
|
|
m_Values[nMap][nDex][ nDexSize- 1].dMax < ptInfIntBox.z ||
|
|
m_Values[nMap][nDex][0].dMin > ptSupIntBox.z)
|
|
continue ;
|
|
// Indici del dexel.
|
|
int nI = nDex % m_nNx[nMap] ;
|
|
int nJ = nDex / m_nNx[nMap] ;
|
|
// Se fuori dalla regione ammissibile salto l'iterazione
|
|
if ( nI < nStI || nI > nEnI || nJ < nStJ || nJ > nEnJ)
|
|
continue ;
|
|
// Posizione del dexel.
|
|
double dX = ( nI + 0.5) * m_dStep ;
|
|
double dY = ( nJ + 0.5) * m_dStep ;
|
|
Point3d ptLineSt( dX, dY, 0.) ;
|
|
Vector3d vtLineDir( 0., 0., 1.) ;
|
|
// Dal sistema griglia al sistema intrinseco (per la prima griglia coincidono).
|
|
if ( nMap == 1) {
|
|
swap( ptLineSt.x, ptLineSt.y) ;
|
|
swap( ptLineSt.x, ptLineSt.z) ;
|
|
swap( vtLineDir.x, vtLineDir.y) ;
|
|
swap( vtLineDir.x, vtLineDir.z) ;
|
|
}
|
|
else if ( nMap == 2) {
|
|
swap( ptLineSt.x, ptLineSt.y) ;
|
|
swap( ptLineSt.y, ptLineSt.z) ;
|
|
swap( vtLineDir.x, vtLineDir.y) ;
|
|
swap( vtLineDir.y, vtLineDir.z) ;
|
|
}
|
|
// Cono proprio
|
|
if ( dMinRad < EPS_SMALL) {
|
|
double dMinPar = m_Values[nMap][nDex][0].dMin ;
|
|
double dMaxPar = m_Values[nMap][nDex][nDexSize - 1].dMax ;
|
|
Point3d ptSegSt = ptLineSt + dMinPar * vtLineDir ;
|
|
double dU1, dU2 ;
|
|
int nIntType = SegmentCone( ptSegSt, vtLineDir, dMaxPar - dMinPar, ptRefPoint, vtRefAx,
|
|
dMaxRad, dHeight, dU1, dU2) ;
|
|
if ( nIntType == LinCompCCIntersType::CC_ERROR_INT)
|
|
return false ;
|
|
else if ( nIntType != LinCompCCIntersType::CC_NO_INTERS) {
|
|
for ( int nIndex = 0 ; nIndex < nDexSize ; nIndex += 1) {
|
|
if ( m_Values[nMap][nDex][nIndex].dMax >= dU1 && m_Values[nMap][nDex][nIndex].dMin <= dU2)
|
|
return false ;
|
|
}
|
|
}
|
|
nIntType = SegmentDisc( ptSegSt, vtLineDir, dMaxPar - dMinPar, ptRefPoint + dHeight * vtRefAx,
|
|
vtRefAx, dMaxRad, dU1, dU2) ;
|
|
if ( nIntType == LinCompDiscIntersType::D_ERROR_INT)
|
|
return false ;
|
|
else if ( nIntType != LinCompDiscIntersType::D_NO_INTERS) {
|
|
for ( int nIndex = 0 ; nIndex < nDexSize ; nIndex += 1) {
|
|
if ( m_Values[nMap][nDex][nIndex].dMax >= dU1 && m_Values[nMap][nDex][nIndex].dMin <= dU2)
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
// Tronco di cono
|
|
else {
|
|
double dMinPar = m_Values[nMap][nDex][0].dMin ;
|
|
double dMaxPar = m_Values[nMap][nDex][nDexSize - 1].dMax ;
|
|
Point3d ptSegSt = ptLineSt + dMinPar * vtLineDir ;
|
|
double dU1, dU2 ;
|
|
int nIntType = SegmentConeFrustum( ptSegSt, vtLineDir, dMaxPar - dMinPar, ptRefPoint, vtRefAx,
|
|
dMinRad, dMaxRad, dHeight, dU1, dU2) ;
|
|
if ( nIntType == LinCompCCIntersType::CC_ERROR_INT)
|
|
return false ;
|
|
else if ( nIntType != LinCompCCIntersType::CC_NO_INTERS) {
|
|
for ( int nIndex = 0 ; nIndex < nDexSize ; nIndex += 1) {
|
|
if ( m_Values[nMap][nDex][nIndex].dMax >= dU1 && m_Values[nMap][nDex][nIndex].dMin <= dU2)
|
|
return false ;
|
|
}
|
|
}
|
|
nIntType = SegmentDisc( ptSegSt, vtLineDir, dMaxPar - dMinPar, ptRefPoint + dHeight * vtRefAx,
|
|
vtRefAx, dMaxRad, dU1, dU2) ;
|
|
if ( nIntType == LinCompDiscIntersType::D_ERROR_INT)
|
|
return false ;
|
|
else if ( nIntType != LinCompDiscIntersType::D_NO_INTERS) {
|
|
for ( int nIndex = 0 ; nIndex < nDexSize ; nIndex += 1) {
|
|
if ( m_Values[nMap][nDex][nIndex].dMax >= dU1 && m_Values[nMap][nDex][nIndex].dMin <= dU2)
|
|
return false ;
|
|
}
|
|
}
|
|
nIntType = SegmentDisc( ptSegSt, vtLineDir, dMaxPar - dMinPar, ptRefPoint, vtRefAx, dMinRad, dU1, dU2) ;
|
|
if ( nIntType == LinCompDiscIntersType::D_ERROR_INT)
|
|
return false ;
|
|
else if ( nIntType != LinCompDiscIntersType::D_NO_INTERS) {
|
|
for ( int nIndex = 0 ; nIndex < nDexSize ; nIndex += 1) {
|
|
if ( m_Values[nMap][nDex][nIndex].dMax >= dU1 && m_Values[nMap][nDex][nIndex].dMin <= dU2)
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Ha come asse Z l'asse del cono/tronco di cono. Se è un cono proprio l'origine
|
|
// è nel vertice del cono e l'asse Z è diretto verso l'apertura.
|
|
// Se è un tronco di cono l'origine è nel centro della base Bot e l'azze Z è diretto verso
|
|
// la base Top, a prescindere da quale base abbia raggio maggiore.
|
|
bool
|
|
VolZmap::AvoidConeFrustum( const Frame3d& frCone, double dRadBot, double dRadTop, double dHeight,
|
|
double dSafeDist, bool bPrecise) const
|
|
{
|
|
// Se cilindro
|
|
if ( abs( dRadBot - dRadTop) < EPS_SMALL)
|
|
return AvoidCylinder( frCone, max( dRadBot, dRadTop), dHeight, dSafeDist, bPrecise) ;
|
|
|
|
// Verifico che la base minore sia in basso nel suo riferimento
|
|
Frame3d frMyCone = frCone ;
|
|
if ( dRadBot > dRadTop) {
|
|
frMyCone.Translate( dHeight * frMyCone.VersZ()) ;
|
|
frMyCone.Rotate( frMyCone.Orig(), frMyCone.VersX(), -1, 0) ;
|
|
}
|
|
double dMinRad = min( dRadBot, dRadTop) ;
|
|
double dMaxRad = max( dRadBot, dRadTop) ;
|
|
|
|
// Se distanza di sicurezza nulla
|
|
if ( dSafeDist < EPS_SMALL)
|
|
return AvoidSimpleConeFrustum( frMyCone, dMinRad, dMaxRad, dHeight, bPrecise) ;
|
|
|
|
// Se vero e proprio cono
|
|
if ( dMinRad < EPS_SMALL) {
|
|
// Se non c'è collisione con l'offset esteso, ho finito.
|
|
double dDeltaVert = dSafeDist * sqrt( 1 + ( dHeight * dHeight / (dMaxRad * dMaxRad))) ;
|
|
double dHeightExt = dHeight + dSafeDist + dDeltaVert ;
|
|
double dRadExt = dMaxRad * dHeightExt / dHeight ;
|
|
Frame3d frFrame = frMyCone ;
|
|
frFrame.Translate( -dDeltaVert * frFrame.VersZ()) ;
|
|
if ( AvoidSimpleConeFrustum( frFrame, 0., dRadExt, dHeightExt, bPrecise))
|
|
return true ;
|
|
// Sfera nel vertice in basso
|
|
frFrame = frMyCone ;
|
|
if ( ! AvoidSimpleSphere( frMyCone.Orig(), dSafeDist, bPrecise))
|
|
return false ;
|
|
// Tronco di cono intermedio
|
|
double dHypo = sqrt( dMaxRad * dMaxRad + dHeight * dHeight ) ;
|
|
double dDeltaH = dSafeDist * dMaxRad / dHypo ;
|
|
double dDeltaR = dSafeDist * dHeight / dHypo ;
|
|
frFrame = frMyCone ; frFrame.Translate( -dDeltaH * frFrame.VersZ()) ;
|
|
if ( ! AvoidSimpleConeFrustum( frFrame, dDeltaR, dMaxRad + dDeltaR, dHeight, bPrecise))
|
|
return false ;
|
|
// Cilindro nel toro in alto
|
|
frFrame = frMyCone ; frFrame.Translate( ( dHeight - dSafeDist) * frFrame.VersZ()) ;
|
|
if ( ! AvoidSimpleCylinder( frFrame, dMaxRad, 2 * dSafeDist, bPrecise))
|
|
return false ;
|
|
// Toro in alto
|
|
frFrame = frMyCone ; frFrame.Translate( dHeight * frFrame.VersZ()) ;
|
|
if ( ! AvoidSimpleTorus( frFrame, dMaxRad, dSafeDist, bPrecise))
|
|
return false ;
|
|
return true ;
|
|
}
|
|
|
|
// Tronco di cono
|
|
// Definisco un sistema di riferimento che ha per origine il centro della base
|
|
// minore e asse Z l'asse di simmetria rivolto verso la direzione di apertura.
|
|
// Se non c'è collisione con l'offset esteso, ho finito.
|
|
double dDiffRad = dMaxRad - dMinRad ;
|
|
double dDeltaVert = dSafeDist * sqrt( 1 + ( dHeight * dHeight / ( dDiffRad * dDiffRad))) ;
|
|
double dDeltaMaxRad = ( dDeltaVert + dSafeDist) * dDiffRad / dHeight ;
|
|
double dDeltaMinRad = ( dDeltaVert - dSafeDist) * dDiffRad / dHeight ;
|
|
Frame3d frFrame = frMyCone ; frFrame.Translate( -dSafeDist * frFrame.VersZ()) ;
|
|
if ( AvoidSimpleConeFrustum( frFrame, dMinRad + dDeltaMinRad, dMaxRad + dDeltaMaxRad, dHeight + 2 * dSafeDist, bPrecise))
|
|
return true ;
|
|
// Tronco di cono intermedio
|
|
double dHypo = sqrt( dDiffRad * dDiffRad + dHeight * dHeight ) ;
|
|
double dDeltaH = dSafeDist * dDiffRad / dHypo ;
|
|
double dDeltaR = dSafeDist * dHeight / dHypo ;
|
|
frFrame = frMyCone ; frFrame.Translate( -dDeltaH * frFrame.VersZ()) ;
|
|
if ( ! AvoidSimpleConeFrustum( frFrame, dMinRad + dDeltaR, dMaxRad + dDeltaR, dHeight, bPrecise))
|
|
return false ;
|
|
// Cilindro sotto
|
|
frFrame = frMyCone ; frFrame.Translate( - dSafeDist * frFrame.VersZ()) ;
|
|
if ( ! AvoidSimpleCylinder( frFrame, dMinRad, 2 * dSafeDist, bPrecise))
|
|
return false ;
|
|
// Cilindro sopra
|
|
frFrame.Translate( dHeight * frFrame.VersZ()) ;
|
|
if ( ! AvoidSimpleCylinder( frFrame, dMaxRad, 2 * dSafeDist, bPrecise))
|
|
return false ;
|
|
// Toro sotto
|
|
frFrame = frMyCone ;
|
|
if ( ! AvoidSimpleTorus( frFrame, dMinRad, dSafeDist, bPrecise))
|
|
return false ;
|
|
// Toro sopra
|
|
frFrame.Translate( dHeight * frFrame.VersZ()) ;
|
|
if ( ! AvoidSimpleTorus( frFrame, dMaxRad, dSafeDist, bPrecise))
|
|
return false ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
RectPrismoidSegmentCollision( const Frame3d& frPrismoid, double dLenghtBaseX, double dLenghtBaseY,
|
|
double dLenghtTopX, double dLenghtTopY, double dHeight,
|
|
const Point3d& ptSt, const Point3d& ptEn)
|
|
{
|
|
// Se il solido non è ben definito, non ha senso continuare.
|
|
if ( max( dLenghtBaseX, dLenghtTopX) < EPS_SMALL ||
|
|
max( dLenghtBaseY, dLenghtTopY) < EPS_SMALL ||
|
|
dHeight < EPS_SMALL)
|
|
return false ;
|
|
|
|
// Porto il segmento nel sistema del tronco.
|
|
Point3d ptMySt = ptSt ;
|
|
ptMySt.ToLoc( frPrismoid) ;
|
|
Point3d ptMyEn = ptEn ;
|
|
ptMyEn.ToLoc( frPrismoid) ;
|
|
|
|
// Se il segmento non è ben definito, non ha senso continuare.
|
|
Vector3d vtMySeg = ptMyEn - ptMySt ;
|
|
if ( ! vtMySeg.Normalize())
|
|
return false ;
|
|
|
|
double dHalfBaseX = 0.5 * dLenghtBaseX ;
|
|
double dHalfBaseY = 0.5 * dLenghtBaseY ;
|
|
double dHalfTopX = 0.5 * dLenghtTopX ;
|
|
double dHalfTopY = 0.5 * dLenghtTopY ;
|
|
|
|
// Se almeno un vertice collide ho finito
|
|
if ( ( ptMySt.z > - EPS_SMALL && ptMySt.z < dHeight + EPS_SMALL &&
|
|
( ptMySt.x + dHalfBaseX + EPS_SMALL) * dHeight > ( dHalfBaseX - dHalfTopX) * ptMySt.z &&
|
|
( ptMySt.x - dHalfBaseX - EPS_SMALL) * dHeight < ( dHalfTopX - dHalfBaseX) * ptMySt.z &&
|
|
( ptMySt.y + dHalfBaseY + EPS_SMALL) * dHeight > ( dHalfBaseY - dHalfTopY) * ptMySt.z &&
|
|
( ptMySt.y - dHalfBaseY - EPS_SMALL) * dHeight < ( dHalfTopY - dHalfBaseY) * ptMySt.z) ||
|
|
( ptMyEn.z > - EPS_SMALL && ptMySt.z < dHeight + EPS_SMALL &&
|
|
( ptMyEn.x + dHalfBaseX + EPS_SMALL) * dHeight > ( dHalfBaseX - dHalfTopX) * ptMyEn.z &&
|
|
( ptMyEn.x - dHalfBaseX - EPS_SMALL) * dHeight < ( dHalfTopX - dHalfBaseX) * ptMyEn.z &&
|
|
( ptMyEn.y + dHalfBaseY + EPS_SMALL) * dHeight > ( dHalfBaseY - dHalfTopY) * ptMyEn.z &&
|
|
( ptMyEn.y - dHalfBaseY - EPS_SMALL) * dHeight < ( dHalfTopY - dHalfBaseY) * ptMyEn.z))
|
|
return true ;
|
|
|
|
// Se c'è collisione con almeno un triangolo delle facce ho finito
|
|
Triangle3d trFaceTria1, trFaceTria2 ;
|
|
Point3d ptInt, ptInt2 ;
|
|
// Faccia base
|
|
trFaceTria1.Set( Point3d( - dHalfBaseX, - dHalfBaseY, 0.),
|
|
Point3d( - dHalfBaseX, dHalfBaseY, 0.),
|
|
Point3d( dHalfBaseX, dHalfBaseY, 0.)) ;
|
|
if ( trFaceTria1.Validate() && IntersLineTria( ptMySt, ptMyEn, trFaceTria1, ptInt, ptInt2) != ILTT_NO)
|
|
return true ;
|
|
trFaceTria2.Set( Point3d( - dHalfBaseX, - dHalfBaseY, 0.),
|
|
Point3d( dHalfBaseX, dHalfBaseY, 0.),
|
|
Point3d( dHalfBaseX, - dHalfBaseY, 0.)) ;
|
|
if ( trFaceTria2.Validate() && IntersLineTria( ptMySt, ptMyEn, trFaceTria2, ptInt, ptInt2) != ILTT_NO)
|
|
return true ;
|
|
// Faccia top
|
|
trFaceTria1.Set( Point3d( - dHalfTopX, - dHalfTopY, dHeight),
|
|
Point3d( dHalfTopX, dHalfTopY, dHeight),
|
|
Point3d( - dHalfTopX, dHalfTopY, dHeight)) ;
|
|
if ( trFaceTria1.Validate() && IntersLineTria( ptMySt, ptMyEn, trFaceTria1, ptInt, ptInt2) != ILTT_NO)
|
|
return true ;
|
|
trFaceTria2.Set( Point3d( - dHalfTopX, - dHalfTopY, dHeight),
|
|
Point3d( dHalfTopX, - dHalfTopY, dHeight),
|
|
Point3d( dHalfTopX, dHalfTopY, dHeight)) ;
|
|
if ( trFaceTria2.Validate() && IntersLineTria( ptMySt, ptMyEn, trFaceTria2, ptInt, ptInt2) != ILTT_NO)
|
|
return true ;
|
|
// Faccia laterale 1
|
|
trFaceTria1.Set( Point3d( - dHalfBaseX, - dHalfBaseY, 0.),
|
|
Point3d( dHalfTopX , - dHalfTopY , dHeight),
|
|
Point3d( - dHalfTopX , - dHalfTopY , dHeight)) ;
|
|
if ( trFaceTria1.Validate() && IntersLineTria( ptMySt, ptMyEn, trFaceTria1, ptInt, ptInt2) != ILTT_NO)
|
|
return true ;
|
|
trFaceTria2.Set( Point3d( - dHalfBaseX, - dHalfBaseY, 0.),
|
|
Point3d( dHalfBaseX, - dHalfBaseY, 0.),
|
|
Point3d( dHalfTopX, - dHalfTopY , dHeight)) ;
|
|
if ( trFaceTria2.Validate() && IntersLineTria( ptMySt, ptMyEn, trFaceTria2, ptInt, ptInt2) != ILTT_NO)
|
|
return true ;
|
|
// Faccia laterale 2
|
|
trFaceTria1.Set( Point3d( dHalfBaseX, - dHalfBaseY, 0.),
|
|
Point3d( dHalfTopX , dHalfTopY , dHeight),
|
|
Point3d( dHalfTopX , - dHalfTopY , dHeight)) ;
|
|
if ( trFaceTria1.Validate() && IntersLineTria( ptMySt, ptMyEn, trFaceTria1, ptInt, ptInt2) != ILTT_NO)
|
|
return true ;
|
|
trFaceTria2.Set( Point3d( dHalfBaseX, - dHalfBaseY, 0.),
|
|
Point3d( dHalfBaseX, dHalfBaseY, 0.),
|
|
Point3d( dHalfTopX , dHalfTopY , dHeight)) ;
|
|
if ( trFaceTria2.Validate() && IntersLineTria( ptMySt, ptMyEn, trFaceTria2, ptInt, ptInt2) != ILTT_NO)
|
|
return true ;
|
|
// Faccia laterale 3
|
|
trFaceTria1.Set( Point3d( dHalfBaseX, dHalfBaseY, 0.),
|
|
Point3d( - dHalfTopX , dHalfTopY , dHeight),
|
|
Point3d( dHalfTopX , dHalfTopY , dHeight)) ;
|
|
if ( trFaceTria1.Validate() && IntersLineTria( ptMySt, ptMyEn, trFaceTria1, ptInt, ptInt2) != ILTT_NO)
|
|
return true ;
|
|
trFaceTria2.Set( Point3d( dHalfBaseX, dHalfBaseY, 0.),
|
|
Point3d( - dHalfBaseX, dHalfBaseY, 0.),
|
|
Point3d( - dHalfTopX , dHalfTopY , dHeight)) ;
|
|
if ( trFaceTria2.Validate() && IntersLineTria( ptMySt, ptMyEn, trFaceTria2, ptInt, ptInt2) != ILTT_NO)
|
|
return true ;
|
|
// Faccia laterale 4
|
|
trFaceTria1.Set( Point3d( - dHalfBaseX, dHalfBaseY, 0.),
|
|
Point3d( - dHalfTopX , - dHalfTopY , dHeight),
|
|
Point3d( - dHalfTopX , dHalfTopY , dHeight)) ;
|
|
if ( trFaceTria1.Validate() && IntersLineTria( ptMySt, ptMyEn, trFaceTria1, ptInt, ptInt2) != ILTT_NO)
|
|
return true ;
|
|
trFaceTria2.Set( Point3d( - dHalfBaseX, dHalfBaseY, 0.),
|
|
Point3d( - dHalfBaseX, - dHalfBaseY, 0.),
|
|
Point3d( - dHalfTopX , - dHalfTopY , dHeight)) ;
|
|
if ( trFaceTria2.Validate() && IntersLineTria( ptMySt, ptMyEn, trFaceTria2, ptInt, ptInt2) != ILTT_NO)
|
|
return true ;
|
|
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
IntersSegmentTrianglePlus( const Point3d& ptTr1, const Point3d& ptTr2, const Point3d& ptTr3,
|
|
const Point3d& ptLnSt, const Vector3d& vtLnDir, double dLnLen,
|
|
double& dStU, double& dEnU)
|
|
{
|
|
Triangle3d trFaceTria ;
|
|
trFaceTria.Set( ptTr1, ptTr2, ptTr3) ;
|
|
if ( trFaceTria.Validate()) {
|
|
Point3d ptMyIntSt, ptMyIntEn ;
|
|
int nIntType = IntersLineTria( ptLnSt, vtLnDir, dLnLen, trFaceTria, ptMyIntSt, ptMyIntEn, true) ;
|
|
if ( nIntType != ILTT_NO) {
|
|
if ( nIntType == ILTT_VERT || nIntType == ILTT_EDGE || nIntType == ILTT_IN) {
|
|
double dCurU = ( ptMyIntSt - ptLnSt) * vtLnDir ;
|
|
if ( dCurU < dStU)
|
|
dStU = dCurU ;
|
|
if ( dCurU > dEnU)
|
|
dEnU = dCurU ;
|
|
}
|
|
else {
|
|
double dCurStU = ( ptMyIntSt - ptLnSt) * vtLnDir ;
|
|
double dCurEnU = ( ptMyIntEn - ptLnSt) * vtLnDir ;
|
|
if ( dCurStU < dStU)
|
|
dStU = dCurStU ;
|
|
if ( dCurEnU > dEnU)
|
|
dEnU = dCurEnU ;
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
RectPrismoidSegmentCollisionPlus( const Frame3d& frPrismoid, double dLenghtBaseX, double dLenghtBaseY,
|
|
double dLenghtTopX, double dLenghtTopY, double dHeight,
|
|
const Point3d& ptSt, const Point3d& ptEn,
|
|
double& dStU, double& dEnU)
|
|
{
|
|
// Se il solido non è ben definito, non ha senso continuare.
|
|
if ( max( dLenghtBaseX, dLenghtTopX) < EPS_SMALL ||
|
|
max( dLenghtBaseY, dLenghtTopY) < EPS_SMALL ||
|
|
dHeight < EPS_SMALL)
|
|
return false ;
|
|
|
|
// Porto il segmento nel sistema del prismoide a base rettangolare
|
|
Point3d ptMySt = ptSt ;
|
|
ptMySt.ToLoc( frPrismoid) ;
|
|
Point3d ptMyEn = ptEn ;
|
|
ptMyEn.ToLoc( frPrismoid) ;
|
|
|
|
// Se il segmento non è ben definito, non ha senso continuare.
|
|
Vector3d vtMySeg = ptMyEn - ptMySt ;
|
|
double dSegLen = vtMySeg.Len() ;
|
|
if ( dSegLen < EPS_SMALL)
|
|
return false ;
|
|
vtMySeg /= dSegLen ;
|
|
|
|
// Semidimensioni delle basi
|
|
double dHalfBaseX = 0.5 * dLenghtBaseX ;
|
|
double dHalfBaseY = 0.5 * dLenghtBaseY ;
|
|
double dHalfTopX = 0.5 * dLenghtTopX ;
|
|
double dHalfTopY = 0.5 * dLenghtTopY ;
|
|
|
|
// Inizializzo gli estremi della parte di retta che interseca il prismoide
|
|
dStU = INFINITO ;
|
|
dEnU = -INFINITO ;
|
|
// Interseco la retta con le facce e salvo i punti d'intersezione
|
|
// Faccia base
|
|
IntersSegmentTrianglePlus( Point3d( -dHalfBaseX, -dHalfBaseY, 0.),
|
|
Point3d( -dHalfBaseX, dHalfBaseY, 0.),
|
|
Point3d( dHalfBaseX, dHalfBaseY, 0.),
|
|
ptMySt, vtMySeg, dSegLen,
|
|
dStU, dEnU) ;
|
|
IntersSegmentTrianglePlus( Point3d( -dHalfBaseX, -dHalfBaseY, 0.),
|
|
Point3d( dHalfBaseX, dHalfBaseY, 0.),
|
|
Point3d( dHalfBaseX, -dHalfBaseY, 0.),
|
|
ptMySt, vtMySeg, dSegLen,
|
|
dStU, dEnU) ;
|
|
// Faccia top
|
|
IntersSegmentTrianglePlus( Point3d( -dHalfTopX, -dHalfTopY, dHeight),
|
|
Point3d( dHalfTopX, dHalfTopY, dHeight),
|
|
Point3d( -dHalfTopX, dHalfTopY, dHeight),
|
|
ptMySt, vtMySeg, dSegLen,
|
|
dStU, dEnU) ;
|
|
IntersSegmentTrianglePlus( Point3d( -dHalfTopX, -dHalfTopY, dHeight),
|
|
Point3d( dHalfTopX, -dHalfTopY, dHeight),
|
|
Point3d( dHalfTopX, dHalfTopY, dHeight),
|
|
ptMySt, vtMySeg, dSegLen,
|
|
dStU, dEnU) ;
|
|
// Faccia laterale 1
|
|
IntersSegmentTrianglePlus( Point3d( -dHalfBaseX, -dHalfBaseY, 0.),
|
|
Point3d( dHalfTopX , -dHalfTopY , dHeight),
|
|
Point3d( -dHalfTopX , -dHalfTopY , dHeight),
|
|
ptMySt, vtMySeg, dSegLen,
|
|
dStU, dEnU) ;
|
|
IntersSegmentTrianglePlus( Point3d( -dHalfBaseX, -dHalfBaseY, 0.),
|
|
Point3d( dHalfBaseX, -dHalfBaseY, 0.),
|
|
Point3d( dHalfTopX, -dHalfTopY , dHeight),
|
|
ptMySt, vtMySeg, dSegLen,
|
|
dStU, dEnU) ;
|
|
// Faccia laterale 2
|
|
IntersSegmentTrianglePlus( Point3d( dHalfBaseX, -dHalfBaseY, 0.),
|
|
Point3d( dHalfTopX , dHalfTopY , dHeight),
|
|
Point3d( dHalfTopX , -dHalfTopY , dHeight),
|
|
ptMySt, vtMySeg, dSegLen,
|
|
dStU, dEnU) ;
|
|
IntersSegmentTrianglePlus( Point3d( dHalfBaseX, -dHalfBaseY, 0.),
|
|
Point3d( dHalfBaseX, dHalfBaseY, 0.),
|
|
Point3d( dHalfTopX , dHalfTopY , dHeight),
|
|
ptMySt, vtMySeg, dSegLen,
|
|
dStU, dEnU) ;
|
|
// Faccia laterale 3
|
|
IntersSegmentTrianglePlus( Point3d( dHalfBaseX, dHalfBaseY, 0.),
|
|
Point3d( -dHalfTopX , dHalfTopY , dHeight),
|
|
Point3d( dHalfTopX , dHalfTopY , dHeight),
|
|
ptMySt, vtMySeg, dSegLen,
|
|
dStU, dEnU) ;
|
|
IntersSegmentTrianglePlus( Point3d( dHalfBaseX, dHalfBaseY, 0.),
|
|
Point3d( -dHalfBaseX, dHalfBaseY, 0.),
|
|
Point3d( -dHalfTopX , dHalfTopY , dHeight),
|
|
ptMySt, vtMySeg, dSegLen,
|
|
dStU, dEnU) ;
|
|
// Faccia laterale 4
|
|
IntersSegmentTrianglePlus( Point3d( -dHalfBaseX, dHalfBaseY, 0.),
|
|
Point3d( -dHalfTopX , -dHalfTopY , dHeight),
|
|
Point3d( -dHalfTopX , dHalfTopY , dHeight),
|
|
ptMySt, vtMySeg, dSegLen,
|
|
dStU, dEnU) ;
|
|
IntersSegmentTrianglePlus( Point3d( -dHalfBaseX, dHalfBaseY, 0.),
|
|
Point3d( -dHalfBaseX, -dHalfBaseY, 0.),
|
|
Point3d( -dHalfTopX , -dHalfTopY , dHeight),
|
|
ptMySt, vtMySeg, dSegLen,
|
|
dStU, dEnU) ;
|
|
|
|
return ( dEnU > dStU - EPS_ZERO && dStU < dSegLen + EPS_SMALL && dEnU > -EPS_SMALL) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::AvoidSimpleRectPrismoid( const Frame3d& frPrismoid, double dLenghtBaseX, double dLenghtBaseY,
|
|
double dLenghtTopX, double dLenghtTopY, double dHeight, bool bPrecise) const
|
|
{
|
|
// IL sistema del tronco di piramide generalizzato è definito nel sistema locale.
|
|
// Lo porto nel sistema intrinseco.
|
|
Frame3d frMyFrame = frPrismoid ;
|
|
frMyFrame.ToLoc( m_MapFrame) ;
|
|
|
|
// Box del tronco nel suo sistema
|
|
double dMaxLenX = max( dLenghtBaseX, dLenghtTopX) ;
|
|
double dMaxLenY = max( dLenghtBaseY, dLenghtTopY) ;
|
|
BBox3d b3GenPyrBox( Point3d( -dMaxLenX / 2, -dMaxLenY / 2, 0.),
|
|
Point3d( dMaxLenX / 2, dMaxLenY / 2, dHeight)) ;
|
|
// Porto il box nel sistema intrinseco dello Zmap
|
|
b3GenPyrBox.ToGlob( frMyFrame) ;
|
|
|
|
// Box del solido
|
|
BBox3d b3Zmap( ORIG, Point3d( m_nNx[0] * m_dStep, m_nNy[0] * m_dStep, m_dMaxZ[0])) ;
|
|
BBox3d b3Int ;
|
|
|
|
// Se i box non si si sovrappongono, ho finito.
|
|
if ( ! b3Zmap.FindIntersection( b3GenPyrBox, b3Int))
|
|
return true ;
|
|
|
|
if ( ! bPrecise) {
|
|
// 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 il cilindro (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 ;
|
|
double dParMin = m_Values[0][nPos][0].dMin ;
|
|
double dParMax = m_Values[0][nPos][nSize-1].dMax ;
|
|
if ( dParMax < b3Int.GetMin().z || dParMin > b3Int.GetMax().z)
|
|
continue ;
|
|
for ( int k = 0 ; k < 5 ; ++ k) {
|
|
Point3d ptLineSt = ORIG + ( i + 0.5) * m_dStep * X_AX + ( j + 0.5) * m_dStep * Y_AX ;
|
|
switch ( k) {
|
|
case 0 : break ;
|
|
case 1 : ptLineSt += -0.4 * m_dStep * X_AX - 0.4 * m_dStep * Y_AX ; break ;
|
|
case 2 : ptLineSt += +0.4 * m_dStep * X_AX - 0.4 * m_dStep * Y_AX ; break ;
|
|
case 3 : ptLineSt += +0.4 * m_dStep * X_AX + 0.4 * m_dStep * Y_AX ; break ;
|
|
case 4 : ptLineSt += -0.4 * m_dStep * X_AX + 0.4 * m_dStep * Y_AX ; break ;
|
|
}
|
|
double dStU, dEnU ;
|
|
Point3d ptSegSt = ptLineSt + m_Values[0][nPos][0].dMin * Z_AX ;
|
|
Point3d ptSegEn = ptLineSt + m_Values[0][nPos][nSize-1].dMax * Z_AX ;
|
|
if ( RectPrismoidSegmentCollisionPlus( frMyFrame, dLenghtBaseX, dLenghtBaseY, dLenghtTopX, dLenghtTopY,
|
|
dHeight, ptSegSt, ptSegEn, dStU, dEnU)) {
|
|
for ( int nIndex = 0 ; nIndex < nSize ; nIndex += 1) {
|
|
if ( m_Values[0][nPos][nIndex].dMax >= dStU && m_Values[0][nPos][nIndex].dMin <= dEnU)
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// Ciclo sulle mappe
|
|
for ( int nMap = 0 ; nMap < m_nMapNum ; ++ nMap) {
|
|
Point3d ptInfIntBox = b3Int.GetMin();
|
|
Point3d ptSupIntBox = b3Int.GetMax();
|
|
// Dal sistema intrinseco al sistema griglia (per la prima griglia coincidono).
|
|
if ( nMap == 1) {
|
|
swap( ptInfIntBox.x, ptInfIntBox.z) ;
|
|
swap( ptInfIntBox.x, ptInfIntBox.y) ;
|
|
swap( ptSupIntBox.x, ptSupIntBox.z) ;
|
|
swap( ptSupIntBox.x, ptSupIntBox.y) ;
|
|
}
|
|
else if ( nMap == 2) {
|
|
swap( ptInfIntBox.y, ptInfIntBox.z) ;
|
|
swap( ptInfIntBox.x, ptInfIntBox.y) ;
|
|
swap( ptSupIntBox.y, ptSupIntBox.z) ;
|
|
swap( ptSupIntBox.x, ptSupIntBox.y) ;
|
|
}
|
|
// Limiti su indici
|
|
int nStI = Clamp( int( ptInfIntBox.x / m_dStep), 0, m_nNx[nMap] - 1) ;
|
|
int nEnI = Clamp( int( ptSupIntBox.x / m_dStep), 0, m_nNx[nMap] - 1) ;
|
|
int nStJ = Clamp( int( ptInfIntBox.y / m_dStep), 0, m_nNy[nMap] - 1) ;
|
|
int nEnJ = Clamp( int( ptSupIntBox.y / m_dStep), 0, m_nNy[nMap] - 1) ;
|
|
for ( int nDex = 0 ; nDex < int( m_Values[nMap].size()) ; ++ nDex) {
|
|
int nSize = int( m_Values[nMap][nDex].size()) ;
|
|
if ( nSize == 0)
|
|
continue ;
|
|
// Indici del dexel
|
|
int nI = nDex % m_nNx[nMap] ;
|
|
int nJ = nDex / m_nNx[nMap] ;
|
|
// Se fuori dalla regione ammissibile salto l'iterazione
|
|
if ( nI < nStI || nI > nEnI || nJ < nStJ || nJ > nEnJ)
|
|
continue ;
|
|
// Posizione del dexel
|
|
double dX = ( nI + 0.5) * m_dStep ;
|
|
double dY = ( nJ + 0.5) * m_dStep ;
|
|
Point3d ptLineSt( dX, dY, 0.) ;
|
|
Vector3d vtLineDir( 0., 0., 1.) ;
|
|
// Dal sistema griglia al sistema intrinseco (per la prima griglia coincidono).
|
|
if ( nMap == 1) {
|
|
swap( ptLineSt.x, ptLineSt.y) ;
|
|
swap( ptLineSt.x, ptLineSt.z) ;
|
|
swap( vtLineDir.x, vtLineDir.y) ;
|
|
swap( vtLineDir.x, vtLineDir.z) ;
|
|
}
|
|
else if ( nMap == 2) {
|
|
swap( ptLineSt.x, ptLineSt.y) ;
|
|
swap( ptLineSt.y, ptLineSt.z) ;
|
|
swap( vtLineDir.x, vtLineDir.y) ;
|
|
swap( vtLineDir.y, vtLineDir.z) ;
|
|
}
|
|
double dStU, dEnU ;
|
|
Point3d ptSegSt = ptLineSt + m_Values[nMap][nDex][0].dMin * vtLineDir ;
|
|
Point3d ptSegEn = ptLineSt + m_Values[nMap][nDex][nSize-1].dMax * vtLineDir ;
|
|
if ( RectPrismoidSegmentCollisionPlus( frMyFrame, dLenghtBaseX, dLenghtBaseY, dLenghtTopX, dLenghtTopY,
|
|
dHeight, ptSegSt, ptSegEn, dStU, dEnU)) {
|
|
for ( int nIndex = 0 ; nIndex < nSize ; nIndex += 1) {
|
|
if ( m_Values[nMap][nDex][nIndex].dMax >= dStU && m_Values[nMap][nDex][nIndex].dMin <= dEnU)
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::AvoidRectPrismoid( const Frame3d& frPrismoid, double dLenghtBaseX, double dLenghtBaseY,
|
|
double dLenghtTopX, double dLenghtTopY, double dHeight,
|
|
double dSafeDist, bool bPrecise) const
|
|
{
|
|
// Se il tronco di piramide non è ben definito non procedo
|
|
if ( max( dLenghtBaseX, dLenghtTopX) < EPS_SMALL ||
|
|
max( dLenghtBaseY, dLenghtTopY) < EPS_SMALL ||
|
|
dHeight < EPS_SMALL)
|
|
return false ;
|
|
|
|
// Se distanza di sicurezza nulla
|
|
if ( dSafeDist < EPS_SMALL)
|
|
return AvoidSimpleRectPrismoid( frPrismoid, dLenghtBaseX, dLenghtBaseY, dLenghtTopX, dLenghtTopY, dHeight, bPrecise) ;
|
|
|
|
// Verifica preliminare con offset esteso
|
|
double dHDiffX = ( dLenghtBaseX - dLenghtTopX) / 2 ;
|
|
double dTgAx = dHDiffX / dHeight ;
|
|
double dSecAx = sqrt( 1 + dTgAx * dTgAx) ;
|
|
double dOffsBaseX = dSafeDist * ( dSecAx + dTgAx) ;
|
|
double dOffsTopX = dSafeDist * ( dSecAx - dTgAx) ;
|
|
double dHDiffY = ( dLenghtBaseY - dLenghtTopY) / 2 ;
|
|
double dTgAy = dHDiffY / dHeight ;
|
|
double dSecAy = sqrt( 1 + dTgAy * dTgAy) ;
|
|
double dOffsBaseY = dSafeDist * ( dSecAy + dTgAy) ;
|
|
double dOffsTopY = dSafeDist * ( dSecAy - dTgAy) ;
|
|
Frame3d frFrame = frPrismoid ; frFrame.Translate( -dSafeDist * frFrame.VersZ()) ;
|
|
if ( AvoidSimpleRectPrismoid( frFrame, dLenghtBaseX + 2 * dOffsBaseX, dLenghtBaseY + 2 * dOffsBaseY,
|
|
dLenghtTopX + 2 * dOffsTopX, dLenghtTopY + 2 * dOffsTopY, dHeight + 2 * dSafeDist, bPrecise))
|
|
return true ;
|
|
|
|
// Sfere centrate nei vertici
|
|
double dHalfBaseX = dLenghtBaseX / 2 ;
|
|
double dHalfBaseY = dLenghtBaseY / 2 ;
|
|
double dHalfTopX = dLenghtTopX / 2 ;
|
|
double dHalfTopY = dLenghtTopY / 2 ;
|
|
PNTVECTOR vVert = { Point3d( -dHalfBaseX, -dHalfBaseY, 0.),
|
|
Point3d( dHalfBaseX, -dHalfBaseY, 0.),
|
|
Point3d( dHalfBaseX, dHalfBaseY, 0.),
|
|
Point3d( -dHalfBaseX, dHalfBaseY, 0.),
|
|
Point3d( -dHalfTopX, -dHalfTopY, dHeight),
|
|
Point3d( dHalfTopX, -dHalfTopY, dHeight),
|
|
Point3d( dHalfTopX, dHalfTopY, dHeight),
|
|
Point3d( -dHalfTopX, dHalfTopY, dHeight)} ;
|
|
for ( auto& ptV : vVert) {
|
|
ptV.ToGlob( frPrismoid) ;
|
|
if ( ! AvoidSimpleSphere( ptV, dSafeDist, bPrecise))
|
|
return false ;
|
|
}
|
|
// Cilindri con i segmenti come asse
|
|
frFrame.Set( vVert[0], frPrismoid.VersX()) ;
|
|
if ( ! AvoidSimpleCylinder( frFrame, dSafeDist, dLenghtBaseX, bPrecise))
|
|
return false ;
|
|
frFrame.Set( vVert[1], frPrismoid.VersY()) ;
|
|
if ( ! AvoidSimpleCylinder( frFrame, dSafeDist, dLenghtBaseY, bPrecise))
|
|
return false ;
|
|
frFrame.Set( vVert[2], -frPrismoid.VersX()) ;
|
|
if ( ! AvoidSimpleCylinder( frFrame, dSafeDist, dLenghtBaseX, bPrecise))
|
|
return false ;
|
|
frFrame.Set( vVert[3], -frPrismoid.VersY()) ;
|
|
if ( ! AvoidSimpleCylinder( frFrame, dSafeDist, dLenghtBaseY, bPrecise))
|
|
return false ;
|
|
frFrame.Set( vVert[4], frPrismoid.VersX()) ;
|
|
if ( ! AvoidSimpleCylinder( frFrame, dSafeDist, dLenghtTopX, bPrecise))
|
|
return false ;
|
|
frFrame.Set( vVert[5], frPrismoid.VersY()) ;
|
|
if ( ! AvoidSimpleCylinder( frFrame, dSafeDist, dLenghtTopY, bPrecise))
|
|
return false ;
|
|
frFrame.Set( vVert[6], -frPrismoid.VersX()) ;
|
|
if ( ! AvoidSimpleCylinder( frFrame, dSafeDist, dLenghtTopX, bPrecise))
|
|
return false ;
|
|
frFrame.Set( vVert[7], -frPrismoid.VersY()) ;
|
|
if ( ! AvoidSimpleCylinder( frFrame, dSafeDist, dLenghtTopY, bPrecise))
|
|
return false ;
|
|
Vector3d vtSeg04 = vVert[4] - vVert[0] ;
|
|
double dLenSeg04 = vtSeg04.Len() ;
|
|
frFrame.Set( vVert[0], vtSeg04) ;
|
|
if ( ! AvoidSimpleCylinder( frFrame, dSafeDist, dLenSeg04, bPrecise))
|
|
return false ;
|
|
Vector3d vtSeg15 = vVert[5] - vVert[1] ;
|
|
double dLenSeg15 = vtSeg15.Len() ;
|
|
frFrame.Set( vVert[1], vtSeg15) ;
|
|
if ( ! AvoidSimpleCylinder( frFrame, dSafeDist, dLenSeg15, bPrecise))
|
|
return false ;
|
|
Vector3d vtSeg26 = vVert[6] - vVert[2] ;
|
|
double dLenSeg26 = vtSeg26.Len() ;
|
|
frFrame.Set( vVert[2], vtSeg26) ;
|
|
if ( ! AvoidSimpleCylinder( frFrame, dSafeDist, dLenSeg26, bPrecise))
|
|
return false ;
|
|
Vector3d vtSeg37 = vVert[7] - vVert[3] ;
|
|
double dLenSeg37 = vtSeg37.Len();
|
|
frFrame.Set( vVert[3], vtSeg37) ;
|
|
if ( ! AvoidSimpleCylinder( frFrame, dSafeDist, dLenSeg37, bPrecise))
|
|
return false ;
|
|
// Box sotto
|
|
frFrame = frPrismoid ; frFrame.Translate( -dSafeDist * frFrame.VersZ()) ;
|
|
if ( ! AvoidSimpleBox( frFrame, Vector3d( dLenghtBaseX, dLenghtBaseY, dSafeDist), bPrecise))
|
|
return false ;
|
|
// Box sopra
|
|
frFrame = frPrismoid ; frFrame.Translate( dHeight * frFrame.VersZ()) ;
|
|
if ( ! AvoidSimpleBox( frFrame, Vector3d( dLenghtBaseX, dLenghtBaseY, dSafeDist), bPrecise))
|
|
return false ;
|
|
// Prismoide allungato in X
|
|
double dHypoX = sqrt( dHDiffX * dHDiffX + dHeight * dHeight) ;
|
|
double dOffsX = dSafeDist * dHeight / dHypoX ;
|
|
double dMoveXZ = dSafeDist * dHDiffX / dHypoX ;
|
|
frFrame = frPrismoid ; frFrame.Translate( dMoveXZ * frFrame.VersZ()) ;
|
|
if ( ! AvoidSimpleRectPrismoid( frFrame, dLenghtBaseX + 2 * dOffsX, dLenghtBaseY,
|
|
dLenghtTopX + 2 * dOffsX, dLenghtTopY, dHeight, bPrecise))
|
|
return false ;
|
|
// Prismoide allungato in Y
|
|
double dHypoY = sqrt( dHDiffY * dHDiffY + dHeight * dHeight) ;
|
|
double dOffsY = dSafeDist * dHeight / dHypoY ;
|
|
double dMoveYZ = dSafeDist * dHDiffY / dHypoY ;
|
|
frFrame = frPrismoid ; frFrame.Translate( dMoveYZ * frFrame.VersZ()) ;
|
|
if ( ! AvoidSimpleRectPrismoid( frFrame, dLenghtBaseX, dLenghtBaseY + 2 * dOffsY,
|
|
dLenghtTopX, dLenghtTopY + 2 * dOffsY, dHeight, bPrecise))
|
|
return false ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::AvoidSimpleTorus( const Frame3d& frTorus, double dMaxRad, double dMinRad, bool bPrecise) const
|
|
{
|
|
// Porto il toro nel sistema intrinseco dello Zmap.
|
|
Point3d ptMyCen = frTorus.Orig() ;
|
|
Vector3d vtMyAx = frTorus.VersZ() ;
|
|
ptMyCen.ToLoc( m_MapFrame) ;
|
|
vtMyAx.ToLoc( m_MapFrame) ;
|
|
|
|
// BBox del toro
|
|
BBox3d b3Box( ptMyCen) ;
|
|
b3Box.Add( ptMyCen + vtMyAx * dMinRad) ;
|
|
b3Box.Add( ptMyCen - vtMyAx * dMinRad) ;
|
|
double dTotRad = dMaxRad + dMinRad ;
|
|
if ( vtMyAx.IsXplus() || vtMyAx.IsXminus())
|
|
b3Box.Expand( 0, dTotRad, dTotRad) ;
|
|
else if ( vtMyAx.IsYplus() || vtMyAx.IsYminus())
|
|
b3Box.Expand( dTotRad, 0, dTotRad) ;
|
|
else if ( vtMyAx.IsZplus() || vtMyAx.IsZminus())
|
|
b3Box.Expand( dTotRad, dTotRad, 0) ;
|
|
else {
|
|
double dExpandX = dTotRad * sqrt( 1 - vtMyAx.x * vtMyAx.x) ;
|
|
double dExpandY = dTotRad * sqrt( 1 - vtMyAx.y * vtMyAx.y) ;
|
|
double dExpandZ = dTotRad * sqrt( 1 - vtMyAx.z * vtMyAx.z) ;
|
|
b3Box.Expand( dExpandX, dExpandY, dExpandZ) ;
|
|
}
|
|
|
|
// 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 ;
|
|
|
|
// Se verifico solo prima mappa
|
|
if ( ! bPrecise) {
|
|
// 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 il toro (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 ;
|
|
double dParMin = m_Values[0][nPos][0].dMin ;
|
|
double dParMax = m_Values[0][nPos][nSize-1].dMax ;
|
|
if ( dParMax < b3Int.GetMin().z || dParMin > b3Int.GetMax().z)
|
|
continue ;
|
|
for ( int k = 0 ; k < 5 ; ++ k) {
|
|
Point3d ptLineSt = ORIG + ( i + 0.5) * m_dStep * X_AX + ( j + 0.5) * m_dStep * Y_AX ;
|
|
switch ( k) {
|
|
case 0 : break ;
|
|
case 1 : ptLineSt += -0.4 * m_dStep * X_AX - 0.4 * m_dStep * Y_AX ; break ;
|
|
case 2 : ptLineSt += +0.4 * m_dStep * X_AX - 0.4 * m_dStep * Y_AX ; break ;
|
|
case 3 : ptLineSt += +0.4 * m_dStep * X_AX + 0.4 * m_dStep * Y_AX ; break ;
|
|
case 4 : ptLineSt += -0.4 * m_dStep * X_AX + 0.4 * m_dStep * Y_AX ; break ;
|
|
}
|
|
// Intersezione segmento toro
|
|
Point3d ptSegSt = ptLineSt + dParMin * Z_AX ;
|
|
BOOLVECTOR vbType ;
|
|
DBLVECTOR vdPar ;
|
|
int nIntType = SegmentTorus( ptSegSt, Z_AX, dParMax - dParMin, ptMyCen, vtMyAx, dMinRad, dMaxRad,
|
|
vbType, vdPar) ;
|
|
if ( nIntType == LinCompTorusIntersType::T_ERROR)
|
|
return false ;
|
|
else if ( nIntType != LinCompTorusIntersType::T_NO_INT) {
|
|
double dUmin = vdPar.front() ;
|
|
double dUmax = vdPar.back() ;
|
|
for ( int nIndex = 0 ; nIndex < nSize ; nIndex += 1) {
|
|
if ( m_Values[0][nPos][nIndex].dMax >= dUmin && m_Values[0][nPos][nIndex].dMin <= dUmax)
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// Ciclo sulle mappe
|
|
for ( int nMap = 0 ; nMap < m_nMapNum ; ++ nMap) {
|
|
Point3d ptInfIntBox = b3Int.GetMin() ;
|
|
Point3d ptSupIntBox = b3Int.GetMax() ;
|
|
// Dal sistema intrinseco al sistema griglia (per la prima griglia coincidono).
|
|
if ( nMap == 1) {
|
|
swap( ptInfIntBox.x, ptInfIntBox.z) ;
|
|
swap( ptInfIntBox.x, ptInfIntBox.y) ;
|
|
swap( ptSupIntBox.x, ptSupIntBox.z) ;
|
|
swap( ptSupIntBox.x, ptSupIntBox.y) ;
|
|
}
|
|
else if (nMap == 2) {
|
|
swap( ptInfIntBox.y, ptInfIntBox.z) ;
|
|
swap( ptInfIntBox.x, ptInfIntBox.y) ;
|
|
swap( ptSupIntBox.y, ptSupIntBox.z) ;
|
|
swap( ptSupIntBox.x, ptSupIntBox.y) ;
|
|
}
|
|
// Limiti su indici
|
|
int nStI = Clamp( int( ptInfIntBox.x / m_dStep), 0, m_nNx[nMap] - 1) ;
|
|
int nEnI = Clamp( int( ptSupIntBox.x / m_dStep), 0, m_nNx[nMap] - 1) ;
|
|
int nStJ = Clamp( int( ptInfIntBox.y / m_dStep), 0, m_nNy[nMap] - 1) ;
|
|
int nEnJ = Clamp( int( ptSupIntBox.y / m_dStep), 0, m_nNy[nMap] - 1) ;
|
|
for ( int nDex = 0 ; nDex < int( m_Values[nMap].size()) ; ++ nDex) {
|
|
int nSize = int( m_Values[nMap][nDex].size()) ;
|
|
if ( nSize == 0)
|
|
continue ;
|
|
double dParMin = m_Values[nMap][nDex][0].dMin ;
|
|
double dParMax = m_Values[nMap][nDex][nSize-1].dMax ;
|
|
if ( dParMax < ptInfIntBox.z || dParMin > ptSupIntBox.z)
|
|
continue ;
|
|
// Indici del dexel
|
|
int nI = nDex % m_nNx[nMap] ;
|
|
int nJ = nDex / m_nNx[nMap] ;
|
|
// Se fuori dalla regione ammissibile salto l'iterazione
|
|
if ( nI < nStI || nI > nEnI || nJ < nStJ || nJ > nEnJ)
|
|
continue ;
|
|
// Posizione del dexel
|
|
double dX = ( nI + 0.5) * m_dStep ;
|
|
double dY = ( nJ + 0.5) * m_dStep ;
|
|
Point3d ptLineSt( dX, dY, 0.) ;
|
|
Vector3d vtLineDir( 0., 0., 1.) ;
|
|
// Dal sistema griglia al sistema intrinseco (per la prima griglia coincidono).
|
|
if ( nMap == 1) {
|
|
swap( ptLineSt.x, ptLineSt.y) ;
|
|
swap( ptLineSt.x, ptLineSt.z) ;
|
|
swap( vtLineDir.x, vtLineDir.y) ;
|
|
swap( vtLineDir.x, vtLineDir.z) ;
|
|
}
|
|
else if ( nMap == 2) {
|
|
swap( ptLineSt.x, ptLineSt.y) ;
|
|
swap( ptLineSt.y, ptLineSt.z) ;
|
|
swap( vtLineDir.x, vtLineDir.y) ;
|
|
swap( vtLineDir.y, vtLineDir.z) ;
|
|
}
|
|
BOOLVECTOR vbType ;
|
|
DBLVECTOR vdPar ;
|
|
Point3d ptSegSt = ptLineSt + dParMin * vtLineDir ;
|
|
int nIntType = SegmentTorus( ptSegSt, vtLineDir, dParMax - dParMin, ptMyCen, vtMyAx, dMinRad, dMaxRad,
|
|
vbType, vdPar) ;
|
|
if ( nIntType == LinCompTorusIntersType::T_ERROR)
|
|
return false ;
|
|
else if ( nIntType != LinCompTorusIntersType::T_NO_INT) {
|
|
double dUmin = vdPar.front() ;
|
|
double dUmax = vdPar.back() ;
|
|
for ( int nIndex = 0 ; nIndex < nSize ; nIndex += 1) {
|
|
if ( m_Values[nMap][nDex][nIndex].dMax >= dUmin && m_Values[nMap][nDex][nIndex].dMin <= dUmax)
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::AvoidTorus( const Frame3d& frTorus, double dMaxRad, double dMinRad,
|
|
double dSafeDist, bool bPrecise) const
|
|
{
|
|
// I raggi devono essere non nulli
|
|
if ( dMaxRad < EPS_SMALL || dMinRad < EPS_SMALL)
|
|
return true ;
|
|
|
|
return AvoidSimpleTorus( frTorus, dMaxRad, dMinRad + max( 0., dSafeDist), bPrecise) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// La superficie deve essere valida e chiusa.
|
|
// La superficie deve essere espressa nel sistema locale, in cui è definito quello intrinseco.
|
|
// I conti sui box per scremare i triangoli e i dexel vengono eseguiti nel sistema intrinsco,
|
|
// quelli di intersezione segmento triangolo vengono eseguiti nel sistema locale. Questo perché
|
|
// è più veloce trasformare le coordinate degli estremi del segmento piuttosto che quelle del
|
|
// triangolo.
|
|
bool
|
|
VolZmap::AvoidSurfTm( const ISurfTriMesh& tmSurf, double dSafeDist, bool bPrecise) const
|
|
{
|
|
// Controllo sulla validità della superficie ed eventualmente sulla sua chiusura
|
|
if ( ! ( tmSurf.IsValid() && tmSurf.IsClosed()))
|
|
return false ;
|
|
// Bounding box della superficie espresso nel sistema locale
|
|
BBox3d b3SurfBox ;
|
|
tmSurf.GetLocalBBox( b3SurfBox) ;
|
|
// Se la distanza di sicurezza è significativa, espando il box
|
|
if ( dSafeDist > EPS_SMALL )
|
|
b3SurfBox.Expand( dSafeDist) ;
|
|
// Box dello Zmap nel suo sistema locale
|
|
BBox3d b3ZmapBox( ORIG, Point3d( m_nNx[0] * m_dStep, m_nNy[0] * m_dStep, m_dMaxZ[0])) ;
|
|
b3ZmapBox.ToGlob( m_MapFrame) ;
|
|
// Box intersezione: se non c'è intersezione ho finito.
|
|
BBox3d b3IntBox ;
|
|
if ( ! b3ZmapBox.FindIntersection( b3SurfBox, b3IntBox))
|
|
return true ;
|
|
// Recupero i triangoli della superficie che cadono nel box intersezione.
|
|
INTVECTOR vTriaIndex ;
|
|
tmSurf.GetAllTriaOverlapBox( b3IntBox, vTriaIndex) ;
|
|
// Non è richeista precisione
|
|
if ( ! bPrecise) {
|
|
// Ciclo sui triangoli che cadono nel box
|
|
for ( int nT : vTriaIndex) {
|
|
Triangle3d trTria ;
|
|
if ( ! ( tmSurf.GetTriangle( nT, trTria) && trTria.Validate()))
|
|
continue ;
|
|
BBox3d b3TriaBox ;
|
|
trTria.GetLocalBBox( b3TriaBox) ;
|
|
// Se è necessario, espando il box di una costante additiva pari alla distanza di sicurezza.
|
|
if ( dSafeDist > EPS_SMALL)
|
|
b3TriaBox.Expand( dSafeDist) ;
|
|
// Porto il bounding-box del triangolo nel sistema intrinseco.
|
|
b3TriaBox.ToLoc( m_MapFrame) ;
|
|
// Limiti su indici
|
|
int nStI = Clamp( int( b3TriaBox.GetMin().x / m_dStep), 0, m_nNx[0] - 1) ;
|
|
int nEnI = Clamp( int( b3TriaBox.GetMax().x / m_dStep), 0, m_nNx[0] - 1) ;
|
|
int nStJ = Clamp( int( b3TriaBox.GetMin().y / m_dStep), 0, m_nNy[0] - 1) ;
|
|
int nEnJ = Clamp( int( b3TriaBox.GetMax().y / m_dStep), 0, m_nNy[0] - 1) ;
|
|
// Ciclo di intersezione dei dexel con il toro (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 ptLineSt = ORIG + ( i + 0.5) * m_dStep * X_AX + ( j + 0.5) * m_dStep * Y_AX ;
|
|
if ( k == 0)
|
|
;
|
|
else if ( k == 1)
|
|
ptLineSt += - 0.4 * m_dStep * X_AX - 0.4 * m_dStep * Y_AX ;
|
|
else if ( k == 2)
|
|
ptLineSt += + 0.4 * m_dStep * X_AX - 0.4 * m_dStep * Y_AX ;
|
|
else if ( k == 3)
|
|
ptLineSt += + 0.4 * m_dStep * X_AX + 0.4 * m_dStep * Y_AX ;
|
|
else if ( k == 4)
|
|
ptLineSt += - 0.4 * m_dStep * X_AX + 0.4 * m_dStep * Y_AX ;
|
|
Vector3d vtLineDir = Z_AX ;
|
|
// Porto punto iniziale e vettore nel sistema locale
|
|
ptLineSt.ToGlob( m_MapFrame) ;
|
|
vtLineDir.ToGlob( m_MapFrame) ;
|
|
for ( int nIndex = 0 ; nIndex < nSize ; nIndex += 1) {
|
|
// Segmento ormai nel sistema locale
|
|
Point3d ptSegSt = ptLineSt + m_Values[0][nPos][nIndex].dMin * vtLineDir ;
|
|
double dSegLen = m_Values[0][nPos][nIndex].dMax - m_Values[0][nPos][nIndex].dMin ;
|
|
// Copia del triangolo che può essere evenutalmente traslata
|
|
Triangle3d trNewTria = trTria ;
|
|
// Se la distanza di sicurezza è significativa
|
|
if ( dSafeDist > EPS_SMALL) {
|
|
// Valuto sfere nei vertici e cilindri lungo gli edge.
|
|
for ( int nV = 0 ; nV < 3 ; ++ nV) {
|
|
Point3d ptVertP = trTria.GetP( nV) ;
|
|
Vector3d vtEdgeV = trTria.GetP( ( nV + 1)) - ptVertP ;
|
|
double dEdgeLen = vtEdgeV.Len() ;
|
|
vtEdgeV /= dEdgeLen ;
|
|
double dU1, dU2 ;
|
|
int nIntersType = SegmentSphere( ptSegSt, vtLineDir, dSegLen, ptVertP, dSafeDist, dU1, dU2) ;
|
|
if ( nIntersType != LinCompSphereIntersType::S_NO_INTERS)
|
|
return false ;
|
|
nIntersType = IntersSegmentCylinder( ptSegSt, vtLineDir, dSegLen, ptVertP, vtEdgeV,
|
|
dSafeDist, dEdgeLen, dU1, dU2) ;
|
|
if ( nIntersType != LinCompCCIntersType::CC_NO_INTERS )
|
|
return false ;
|
|
}
|
|
// Traslo il triangolo.
|
|
trNewTria.Translate( dSafeDist * trTria.GetN()) ;
|
|
}
|
|
// Intersezione segento triangolo
|
|
Point3d ptInt, ptInt2 ;
|
|
int nIntersType = IntersLineTria( ptSegSt, vtLineDir, dSegLen, trNewTria, ptInt, ptInt2) ;
|
|
// Collisione
|
|
if ( nIntersType != IntLineTriaType::ILTT_NO)
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// È richiesta precisione
|
|
else {
|
|
// Ciclo sui triangoli che cadono nel box
|
|
for ( int nT : vTriaIndex) {
|
|
Triangle3d trTria ;
|
|
if ( ! ( tmSurf.GetTriangle( nT, trTria) && trTria.Validate()))
|
|
continue ;
|
|
BBox3d b3TriaBox ;
|
|
trTria.GetLocalBBox( b3TriaBox) ;
|
|
// Se è necessario, espando il box di una costante additiva pari alla distanza di sicurezza.
|
|
if ( dSafeDist > EPS_SMALL)
|
|
b3TriaBox.Expand( dSafeDist) ;
|
|
// Porto il bounding-box del triangolo nel sistema intrinseco.
|
|
b3TriaBox.ToLoc( m_MapFrame) ;
|
|
// Ciclo sulle mappe
|
|
for ( int nMap = 0 ; nMap < m_nMapNum ; ++ nMap) {
|
|
Point3d ptInfIntBox = b3TriaBox.GetMin() ;
|
|
Point3d ptSupIntBox = b3TriaBox.GetMax() ;
|
|
// Dal sistema intrinseco al sistema griglia (per la prima griglia coincidono).
|
|
if ( nMap == 1) {
|
|
swap( ptInfIntBox.x, ptInfIntBox.z) ;
|
|
swap( ptInfIntBox.x, ptInfIntBox.y) ;
|
|
swap( ptSupIntBox.x, ptSupIntBox.z) ;
|
|
swap( ptSupIntBox.x, ptSupIntBox.y) ;
|
|
}
|
|
else if (nMap == 2) {
|
|
swap( ptInfIntBox.y, ptInfIntBox.z) ;
|
|
swap( ptInfIntBox.x, ptInfIntBox.y) ;
|
|
swap( ptSupIntBox.y, ptSupIntBox.z) ;
|
|
swap( ptSupIntBox.x, ptSupIntBox.y) ;
|
|
}
|
|
// Limiti su indici
|
|
int nStI = Clamp( int( ptInfIntBox.x / m_dStep), 0, m_nNx[nMap] - 1) ;
|
|
int nEnI = Clamp( int( ptSupIntBox.x / m_dStep), 0, m_nNx[nMap] - 1) ;
|
|
int nStJ = Clamp( int( ptInfIntBox.y / m_dStep), 0, m_nNy[nMap] - 1) ;
|
|
int nEnJ = Clamp( int( ptSupIntBox.y / m_dStep), 0, m_nNy[nMap] - 1) ;
|
|
for ( int nDex = 0 ; nDex < int( m_Values[nMap].size()) ; ++ nDex) {
|
|
// Indici del dexel
|
|
int nI = nDex % m_nNx[nMap] ;
|
|
int nJ = nDex / m_nNx[nMap] ;
|
|
// Se fuori dalla regione ammissibile salto l'iterazione
|
|
if ( nI < nStI || nI > nEnI || nJ < nStJ || nJ > nEnJ)
|
|
continue ;
|
|
// Posizione del dexel
|
|
double dX = ( nI + 0.5) * m_dStep ;
|
|
double dY = ( nJ + 0.5) * m_dStep ;
|
|
Point3d ptLineSt( dX, dY, 0.) ;
|
|
Vector3d vtLineDir( 0., 0., 1.) ;
|
|
// Dal sistema griglia al sistema intrinseco (per la prima griglia coincidono).
|
|
if ( nMap == 1) {
|
|
swap( ptLineSt.x, ptLineSt.y) ;
|
|
swap( ptLineSt.x, ptLineSt.z) ;
|
|
swap( vtLineDir.x, vtLineDir.y) ;
|
|
swap( vtLineDir.x, vtLineDir.z) ;
|
|
}
|
|
else if ( nMap == 2) {
|
|
swap( ptLineSt.x, ptLineSt.y) ;
|
|
swap( ptLineSt.y, ptLineSt.z) ;
|
|
swap( vtLineDir.x, vtLineDir.y) ;
|
|
swap( vtLineDir.y, vtLineDir.z) ;
|
|
}
|
|
// Porto punto iniziale e vettore nel sistema locale
|
|
ptLineSt.ToGlob( m_MapFrame) ;
|
|
vtLineDir.ToGlob( m_MapFrame) ;
|
|
// Ciclo sui segmenti del dexel.
|
|
for ( int nInt = 0 ; nInt < int( m_Values[nMap][nDex].size()) ; ++ nInt) {
|
|
// Segmento ormai nel sistema locale
|
|
Point3d ptSegSt = ptLineSt + m_Values[nMap][nDex][nInt].dMin * vtLineDir ;
|
|
double dSegLen = m_Values[nMap][nDex][nInt].dMax - m_Values[nMap][nDex][nInt].dMin ;
|
|
// Copia del triangolo che può essere evenutalmente traslata
|
|
Triangle3d trNewTria = trTria ;
|
|
// Se la distanza di sicurezza è significativa
|
|
if ( dSafeDist > EPS_SMALL) {
|
|
// Valuto sfere nei vertici e cilindri lungo gli edge.
|
|
for ( int nV = 0 ; nV < 3 ; ++ nV) {
|
|
Point3d ptVertP = trTria.GetP( nV) ;
|
|
Vector3d vtEdgeV = trTria.GetP( ( nV + 1)) - ptVertP ;
|
|
double dEdgeLen = vtEdgeV.Len() ;
|
|
vtEdgeV /= dEdgeLen ;
|
|
double dU1, dU2 ;
|
|
int nIntersType = SegmentSphere( ptSegSt, vtLineDir, dSegLen, ptVertP, dSafeDist, dU1, dU2) ;
|
|
if ( nIntersType != LinCompSphereIntersType::S_NO_INTERS)
|
|
return false ;
|
|
nIntersType = IntersSegmentCylinder( ptSegSt, vtLineDir, dSegLen, ptVertP, vtEdgeV,
|
|
dSafeDist, dEdgeLen, dU1, dU2) ;
|
|
if ( nIntersType != LinCompCCIntersType::CC_NO_INTERS )
|
|
return false ;
|
|
}
|
|
// Traslo il triangolo.
|
|
trNewTria.Translate( dSafeDist * trTria.GetN()) ;
|
|
}
|
|
// Intersezione segento triangolo
|
|
Point3d ptInt, ptInt2 ;
|
|
int nIntersType = IntersLineTria( ptSegSt, vtLineDir, dSegLen, trNewTria, ptInt, ptInt2) ;
|
|
// Collisione
|
|
if ( nIntersType != IntLineTriaType::ILTT_NO)
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Riferimento con origine nel centro della base e asse di simmetria coincidente 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 dRad, bool bTapLow, bool bTapUp,
|
|
Point3d& ptInt1, Vector3d& vtN1, Point3d& ptInt2, Vector3d& vtN2) const
|
|
{
|
|
// Porto la linea nel riferimento del cilindro
|
|
Point3d ptP = ptLineSt ; ptP.ToLoc( CylFrame) ;
|
|
Vector3d vtV = vtLineDir ; vtV.ToLoc( CylFrame) ;
|
|
|
|
// Determino le eventuali intersezioni con le due basi a quota minima e massima (solo se linea non parallela ad esse)
|
|
int nBasInt = 0 ;
|
|
if ( abs( vtV.z) > EPS_ZERO) {
|
|
// le linee tangenti al cilindro non sono considerate intersecanti
|
|
double EpsRad = ( vtV.IsZeroXY() ? - EPS_SMALL : EPS_SMALL) ;
|
|
ptInt1 = ptP + ( ( 0 - ptP.z) / vtV.z) * vtV ;
|
|
if ( ptInt1.x * ptInt1.x + ptInt1.y * ptInt1.y < dRad * dRad + 2 * dRad * EpsRad) {
|
|
nBasInt += 1 ;
|
|
vtN1 = Z_AX ;
|
|
}
|
|
ptInt2 = ptP + ( ( dH - ptP.z) / vtV.z) * vtV ;
|
|
if ( ptInt2.x * ptInt2.x + ptInt2.y * ptInt2.y < dRad * dRad + 2 * dRad * EpsRad) {
|
|
nBasInt += 2 ;
|
|
vtN2 = - Z_AX ;
|
|
}
|
|
}
|
|
|
|
// Se la linea interseca entrambe le basi, si sono trovate le due intersezioni
|
|
if ( nBasInt == 3) {
|
|
// Porto i punti e i versori nel riferimento globale
|
|
ptInt1.ToGlob( CylFrame) ;
|
|
vtN1.ToGlob( CylFrame) ;
|
|
ptInt2.ToGlob( CylFrame) ;
|
|
vtN2.ToGlob( CylFrame) ;
|
|
// Trovate intersezioni
|
|
return true ;
|
|
}
|
|
|
|
// Determino le intersezioni con la superficie laterale del cilindro
|
|
DBLVECTOR vdCoef(3) ;
|
|
double dSqRad = dRad * dRad ;
|
|
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 ;
|
|
DBLVECTOR vdRoots ;
|
|
int nRoot = PolynomialRoots( 2, vdCoef, vdRoots) ;
|
|
|
|
// Epsilon per piani di tappo
|
|
double dEpsLow = ( bTapLow ? - EPS_SMALL : EPS_SMALL) ;
|
|
double dEpsUp = ( bTapUp ? EPS_SMALL : - EPS_SMALL) ;
|
|
|
|
// Elimino le soluzioni cha danno intersezioni fuori dai limiti in Z del cilindro
|
|
if ( nRoot == 2) {
|
|
double dIntZ2 = ptP.z + vdRoots[1] * vtV.z ;
|
|
if ( dIntZ2 < 0 + dEpsLow || dIntZ2 > dH + dEpsUp)
|
|
nRoot = 1 ;
|
|
}
|
|
if ( nRoot >= 1) {
|
|
double dIntZ1 = ptP.z + vdRoots[0] * vtV.z ;
|
|
if ( dIntZ1 < 0 + dEpsLow || dIntZ1 > dH + dEpsUp) {
|
|
if ( nRoot == 2)
|
|
vdRoots[0] = vdRoots[1] ;
|
|
-- nRoot ;
|
|
}
|
|
}
|
|
|
|
// Due soluzioni: la retta interseca due volte la superficie laterale
|
|
if ( nRoot == 2) {
|
|
// Punti di intersezione con la superficie del cilindro
|
|
ptInt1 = ptP + vdRoots[0] * vtV ;
|
|
ptInt2 = ptP + vdRoots[1] * vtV ;
|
|
// Determino le normali
|
|
vtN1.Set( -ptInt1.x, -ptInt1.y, 0) ;
|
|
vtN1.Normalize() ;
|
|
vtN2.Set( -ptInt2.x, -ptInt2.y, 0) ;
|
|
vtN2.Normalize() ;
|
|
// Porto i punti e i versori nel riferimento globale
|
|
ptInt1.ToGlob( CylFrame) ;
|
|
vtN1.ToGlob( CylFrame) ;
|
|
ptInt2.ToGlob( CylFrame) ;
|
|
vtN2.ToGlob( CylFrame) ;
|
|
// Trovate intersezioni
|
|
return true ;
|
|
}
|
|
|
|
// Una soluzione : la retta interseca la superficie laterale e un piano
|
|
else if ( nRoot == 1) {
|
|
// Se piano superiore
|
|
if ( nBasInt == 2) {
|
|
// Punto di intersezione
|
|
ptInt1 = ptP + vdRoots[0] * vtV ;
|
|
// Normale alla superficie del cilindro verso l'interno
|
|
vtN1.Set( -ptInt1.x, -ptInt1.y, 0) ;
|
|
vtN1.Normalize() ;
|
|
}
|
|
// altrimenti piano inferiore
|
|
else if ( nBasInt == 1) {
|
|
// Punto di intersezione
|
|
ptInt2 = ptP + vdRoots[0] * vtV ;
|
|
// Normale alla superficie del cilindro verso l'interno
|
|
vtN2.Set( -ptInt2.x, -ptInt2.y, 0) ;
|
|
vtN2.Normalize() ;
|
|
}
|
|
// altrimenti niente
|
|
else
|
|
return false ;
|
|
// Porto i punti e i versori nel riferimento globale
|
|
ptInt1.ToGlob( CylFrame) ;
|
|
vtN1.ToGlob( CylFrame) ;
|
|
ptInt2.ToGlob( CylFrame) ;
|
|
vtN2.ToGlob( CylFrame) ;
|
|
// Trovate intersezioni
|
|
return true ;
|
|
}
|
|
|
|
// Nessuna soluzione : nessuna intersezione
|
|
else
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Riferimento con origine nel vertice del cono e asse di simmetria coincidente con l'asse Z.
|
|
// La funzione restituisce true in caso di intersezione, false altrimenti.
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::IntersLineConus( const Point3d& ptLineSt, const Vector3d& vtLineDir,
|
|
const Frame3d& ConusFrame, double dTan, double dMinH, double dMaxH, bool bTapLow, bool bTapUp,
|
|
Point3d& ptInt1, Vector3d& vtN1, Point3d& ptInt2, Vector3d& vtN2) const
|
|
{
|
|
// Porto la linea nel riferimento del cono
|
|
Point3d ptP = ptLineSt ; ptP.ToLoc( ConusFrame) ;
|
|
Vector3d vtV = vtLineDir ; vtV.ToLoc( ConusFrame) ;
|
|
|
|
// Raggi delle due basi
|
|
double dMinRad = dTan * dMinH ;
|
|
double dMaxRad = dTan * dMaxH ;
|
|
|
|
// Epsilon per piani di tappo
|
|
double dEpsLow = ( bTapLow ? - EPS_SMALL : EPS_SMALL) ;
|
|
double dEpsUp = ( bTapUp ? EPS_SMALL : - EPS_SMALL) ;
|
|
|
|
// Determino le eventuali intersezioni con le due basi a quota minima e massima (solo se linea non parallela ad esse)
|
|
int nBasInt = 0 ;
|
|
if ( abs( vtV.z) > EPS_ZERO) {
|
|
ptInt1 = ptP + ( ( dMinH - ptP.z) / vtV.z) * vtV ;
|
|
if ( ptInt1.x * ptInt1.x + ptInt1.y * ptInt1.y < dMinRad * dMinRad + 2 * dMinRad * dTan * dEpsLow) {
|
|
nBasInt += 1 ;
|
|
vtN1 = Z_AX ;
|
|
}
|
|
ptInt2 = ptP + ( ( dMaxH - ptP.z) / vtV.z) * vtV ;
|
|
if ( ptInt2.x * ptInt2.x + ptInt2.y * ptInt2.y < dMaxRad * dMaxRad + 2 * dMaxRad * dTan * dEpsUp) {
|
|
nBasInt += 2 ;
|
|
vtN2 = - Z_AX ;
|
|
}
|
|
}
|
|
|
|
// Se la linea interseca entrambe le basi, si sono trovate le due intersezioni
|
|
if ( nBasInt == 3) {
|
|
// Porto i punti e i versori nel riferimento globale
|
|
ptInt1.ToGlob( ConusFrame) ;
|
|
vtN1.ToGlob( ConusFrame) ;
|
|
ptInt2.ToGlob( ConusFrame) ;
|
|
vtN2.ToGlob( ConusFrame) ;
|
|
// Trovate intersezioni
|
|
return true ;
|
|
}
|
|
|
|
// Determino le intersezioni con la superficie laterale del cono
|
|
DBLVECTOR vdCoef( 3) ;
|
|
double dSqTan = dTan * dTan ;
|
|
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 ;
|
|
DBLVECTOR vdRoots ;
|
|
int nRoot = PolynomialRoots( 2, vdCoef, vdRoots) ;
|
|
|
|
// Elimino le soluzioni cha danno intersezioni fuori dai limiti in Z del tronco
|
|
if ( nRoot == 2) {
|
|
double dIntZ2 = ptP.z + vdRoots[1] * vtV.z ;
|
|
if ( dIntZ2 < dMinH + dEpsLow || dIntZ2 > dMaxH + dEpsUp)
|
|
nRoot = 1 ;
|
|
}
|
|
if ( nRoot >= 1) {
|
|
double dIntZ1 = ptP.z + vdRoots[0] * vtV.z ;
|
|
if ( dIntZ1 < dMinH + dEpsLow || dIntZ1 > dMaxH + dEpsUp) {
|
|
if ( nRoot == 2)
|
|
vdRoots[0] = vdRoots[1] ;
|
|
-- nRoot ;
|
|
}
|
|
}
|
|
|
|
// Due soluzioni: la retta interseca due volte la superficie laterale
|
|
if ( nRoot == 2) {
|
|
// Punti di intersezione con la superficie del cono
|
|
ptInt1 = ptP + vdRoots[0] * vtV ;
|
|
ptInt2 = ptP + vdRoots[1] * vtV ;
|
|
if ( ptInt1.z > ptInt2.z)
|
|
swap( ptInt1, ptInt2) ;
|
|
// Determino le normali
|
|
vtN1.Set( -ptInt1.x, -ptInt1.y, ( ptInt1.x * ptInt1.x + ptInt1.y * ptInt1.y) / ptInt1.z) ;
|
|
vtN1.Normalize() ;
|
|
vtN2.Set( -ptInt2.x, -ptInt2.y, ( ptInt2.x * ptInt2.x + ptInt2.y * ptInt2.y) / ptInt2.z) ;
|
|
vtN2.Normalize() ;
|
|
// Porto i punti e i versori nel riferimento globale
|
|
ptInt1.ToGlob( ConusFrame) ;
|
|
vtN1.ToGlob( ConusFrame) ;
|
|
ptInt2.ToGlob( ConusFrame) ;
|
|
vtN2.ToGlob( ConusFrame) ;
|
|
// Trovate intersezioni
|
|
return true ;
|
|
}
|
|
|
|
// Una soluzione : la retta interseca la superficie laterale e un piano
|
|
else if ( nRoot == 1) {
|
|
// Se piano superiore
|
|
if ( nBasInt == 2) {
|
|
// Punto di intersezione
|
|
ptInt1 = ptP + vdRoots[0] * vtV ;
|
|
// Normale alla superficie del cono verso l'interno
|
|
vtN1.Set( -ptInt1.x, -ptInt1.y, ( ptInt1.x * ptInt1.x + ptInt1.y * ptInt1.y) / ptInt1.z) ;
|
|
vtN1.Normalize() ;
|
|
}
|
|
// altrimenti piano inferiore
|
|
else if( nBasInt == 1) {
|
|
// Punto di intersezione
|
|
ptInt2 = ptP + vdRoots[0] * vtV ;
|
|
// Normale alla superficie del cono verso l'interno
|
|
vtN2.Set( -ptInt2.x, -ptInt2.y, ( ptInt2.x * ptInt2.x + ptInt2.y * ptInt2.y) / ptInt2.z) ;
|
|
vtN2.Normalize() ;
|
|
}
|
|
// altrimenti niente
|
|
else
|
|
return false ;
|
|
// Porto i punti e i versori nel riferimento globale
|
|
ptInt1.ToGlob( ConusFrame) ;
|
|
vtN1.ToGlob( ConusFrame) ;
|
|
ptInt2.ToGlob( ConusFrame) ;
|
|
vtN2.ToGlob( ConusFrame) ;
|
|
// Trovate intersezioni
|
|
return true ;
|
|
}
|
|
|
|
// Nessuna soluzione : nessuna intersezione
|
|
else
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// 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 Point3d& ptLineSt, const Vector3d& vtLineDir,
|
|
const Frame3d& CircFrame, double dRad, double dLongMvLen, double dOrtMvLen,
|
|
bool bTapLow, bool bTapUp,
|
|
Point3d& ptInt1, Vector3d& vtN1, Point3d& ptInt2, Vector3d& vtN2) const
|
|
{
|
|
// Se il cilindrico ellittico degenera in un piano, non bisogna tagliare
|
|
if ( abs( dLongMvLen) < EPS_SMALL)
|
|
return false ;
|
|
|
|
// Porto la linea nel riferimento del cilindro
|
|
Point3d ptP = ptLineSt ; ptP.ToLoc( CircFrame) ;
|
|
Vector3d vtV = vtLineDir ; vtV.ToLoc( CircFrame) ;
|
|
|
|
// Quadrato del raggio
|
|
double dSqRad = dRad * dRad ;
|
|
// Asse cilindro ellittico
|
|
Vector3d vtAx( dOrtMvLen, 0, dLongMvLen) ;
|
|
vtAx.Normalize() ;
|
|
|
|
// 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 ;
|
|
}
|
|
|
|
// 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
|
|
DBLVECTOR vdCoef(3) ;
|
|
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
|
|
DBLVECTOR vdRoots ;
|
|
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 numero di soluzioni diverso da due le eventuali intersezioni sono già state trovate
|
|
if ( nRoot != 2)
|
|
return false ;
|
|
|
|
// Due soluzioni trovate
|
|
// 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
|
|
// Vettore 1
|
|
Vector3d vtTest1 = ( ptInt1 - ORIG) - ( ptInt1 - ORIG) * vtAx * vtAx ;
|
|
double dX0_1 = ( vtTest1.x > 0 ? 1 : -1) * sqrt( max( dSqRad - ptInt1.y * ptInt1.y, 0.)) ;
|
|
Vector3d vtCirc1( - dX0_1, - ptInt1.y, 0) ;
|
|
Vector3d vtTan1( vtCirc1.y, - vtCirc1.x, 0) ;
|
|
Vector3d vtCross1 = vtTan1 ^ vtMv ;
|
|
vtN1 = ( vtCross1 * vtCirc1 > - EPS_ZERO ? vtCross1 : - vtCross1) ;
|
|
vtN1.Normalize() ;
|
|
// Vettore 2
|
|
Vector3d vtTest2 = ( ptInt2 - ORIG) - ( ptInt2 - ORIG) * vtAx * vtAx ;
|
|
double dX0_2 = ( vtTest2.x > 0 ? 1 : -1) * sqrt( max( dSqRad - ptInt2.y * ptInt2.y, 0.)) ;
|
|
Vector3d vtCirc2( - dX0_2, - ptInt2.y, 0) ;
|
|
Vector3d vtTan2( vtCirc2.y, - vtCirc2.x, 0) ;
|
|
Vector3d vtCross2 = vtTan2 ^ vtMv ;
|
|
vtN2 = ( vtCross2 * vtCirc2 > - EPS_ZERO ? vtCross2 : - vtCross2) ;
|
|
vtN2.Normalize() ;
|
|
|
|
// Flag per i tappi
|
|
double dEpsLow = ( bTapLow ? - EPS_SMALL : EPS_SMALL) ;
|
|
double dEpsUp = ( bTapUp ? EPS_SMALL : - EPS_SMALL) ;
|
|
|
|
// Studio le soluzioni: se una è 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 ;
|
|
|
|
// Se il secondo punto è sceso in Z sotto il primo o il primo è salito sopra il secondo vuol
|
|
// dire che l'intersezione è al limite del cilindro ellittico; non c'è reale intersezione.
|
|
if ( ptInt1.z > ptInt2.z)
|
|
return false ;
|
|
|
|
// Porto i punti e i versori nel riferimento globale
|
|
ptInt1.ToGlob( CircFrame) ;
|
|
vtN1.ToGlob( CircFrame) ;
|
|
ptInt2.ToGlob( CircFrame) ;
|
|
vtN2.ToGlob( CircFrame) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::IntersLineMyPolyhedron( const Point3d& ptLineSt, const Vector3d& vtLineDir,
|
|
const Frame3d& PolyFrame, double dLenX, double dLenY, double dLenZ, double dDeltaZ,
|
|
Point3d& ptInt1, Vector3d& vtN1, Point3d& ptInt2, Vector3d& vtN2) const
|
|
{
|
|
// Controllo sulle dimensioni lineari affinché sia valido il poliedro
|
|
if ( dLenX <= EPS_SMALL || dLenY <= EPS_SMALL || dLenZ <= EPS_SMALL)
|
|
return false ;
|
|
|
|
// Porto la linea nel riferimento del poliedro
|
|
Point3d ptP = ptLineSt ; ptP.ToLoc( PolyFrame) ;
|
|
Vector3d vtV = vtLineDir ; 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) ;
|
|
|
|
// Vettori per descrizione piani obliqui
|
|
Vector3d vtFacet5 = ptFacet135 - ptP ;
|
|
Vector3d vtFacet6 = ptFacet246 - ptP ;
|
|
Vector3d vtOb( - dDeltaZ, 0, dLenX) ;
|
|
vtOb.Normalize() ;
|
|
|
|
// 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) > ptFacet135.y)
|
|
return false ;
|
|
// Controllo sulle facce 3 e 4
|
|
if ( abs( vtV.x) < EPS_ZERO && ( ptP.x < ptFacet135.x || ptP.x > ptFacet246.x))
|
|
return false ;
|
|
// Controllo sulle facce 5 e 6
|
|
double dP1 = abs ( ( ptFacet135 - ptP) * vtOb) ;
|
|
double dP2 = abs ( ( ptFacet246 - ptP) * vtOb) ;
|
|
if ( abs( vtV * vtOb) < EPS_ZERO && ( dP1 < EPS_SMALL || dP2 < EPS_SMALL))
|
|
return false ;
|
|
|
|
// Punti notevoli
|
|
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 ;
|
|
|
|
// 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)
|
|
return false ;
|
|
|
|
// Porto i punti e i versori nel riferimento globale
|
|
ptInt1.ToGlob( PolyFrame) ;
|
|
ptInt2.ToGlob( PolyFrame) ;
|
|
vtN1.ToGlob( PolyFrame) ;
|
|
vtN2.ToGlob( PolyFrame) ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
VolZmap::IntersLineTruncatedPyramid( const Point3d& ptLineSt, const Vector3d& vtLineDir,
|
|
const Frame3d& frTruncPyramFrame, double dSegMin, double dSegMax, double dHeight,
|
|
Point3d& ptInt1, Vector3d& vtN1, Point3d& ptInt2, Vector3d& vtN2) const
|
|
{
|
|
// Controllo sulle dimensioni lineari affinché sia valido il solido
|
|
if ( dSegMin < EPS_SMALL || dSegMax < EPS_SMALL || dHeight < EPS_SMALL)
|
|
return false ;
|
|
|
|
// Porto la linea nel riferimento del solido
|
|
Point3d ptP = ptLineSt ;
|
|
Vector3d vtV = vtLineDir ;
|
|
ptP.ToLoc( frTruncPyramFrame) ;
|
|
vtV.ToLoc( frTruncPyramFrame) ;
|
|
|
|
// Se la retta sta sopra o sotto il solido non vi può essere intersezione
|
|
if ( abs( vtV.z) < EPS_ZERO && ( ptP.z < EPS_SMALL || ptP.z > dHeight + EPS_SMALL))
|
|
return false ;
|
|
|
|
double dHalfMax = 0.5 * dSegMax ;
|
|
double dHalfMin = 0.5 * dSegMin ;
|
|
|
|
// Cerco le intersezioni con i piani delle facce
|
|
int nIntNum = 0 ;
|
|
// Base maggiore
|
|
Point3d ptIntPlaneMax = ptP + ( - ptP.z / vtV.z) * vtV ;
|
|
if ( abs( ptIntPlaneMax.x) <= dHalfMax && abs( ptIntPlaneMax.y) <= dHalfMax) {
|
|
ptInt1 = ptIntPlaneMax ;
|
|
vtN1 = - Z_AX ;
|
|
++ nIntNum ;
|
|
}
|
|
// Base minore
|
|
Point3d ptIntPlaneMin = ptP + ( ( dHeight - ptP.z) / vtV.z) * vtV ;
|
|
if ( abs( ptIntPlaneMin.x) <= dHalfMin && abs( ptIntPlaneMin.y) <= dHalfMin) {
|
|
if ( nIntNum == 0) {
|
|
ptInt1 = ptIntPlaneMin ;
|
|
vtN1 = Z_AX ;
|
|
}
|
|
else {
|
|
ptInt2 = ptIntPlaneMin ;
|
|
vtN2 = Z_AX ;
|
|
}
|
|
++ nIntNum ;
|
|
}
|
|
|
|
// Se la retta intersca i piani delle basi al loro interno, ho finito
|
|
if ( nIntNum == 2) {
|
|
if ( ( ptInt1 - ptP) * vtV > ( ptInt2 - ptP) * vtV) {
|
|
swap( ptInt1, ptInt2) ;
|
|
swap( vtN1, vtN2) ;
|
|
}
|
|
ptInt1.ToGlob( frTruncPyramFrame) ;
|
|
ptInt2.ToGlob( frTruncPyramFrame) ;
|
|
vtN1.ToGlob( frTruncPyramFrame) ;
|
|
vtN2.ToGlob( frTruncPyramFrame) ;
|
|
return true ;
|
|
}
|
|
|
|
// Altrimenti se le intersezioni sono fuori dalle basi e dallo stesso lato rispetto a queste ultime non c'è intersezione
|
|
if ( nIntNum == 0 &&
|
|
( ( ptIntPlaneMax.x < - dHalfMax - EPS_SMALL && ptIntPlaneMin.x < - dHalfMin - EPS_SMALL) ||
|
|
( ptIntPlaneMax.x > dHalfMax + EPS_SMALL && ptIntPlaneMin.x > dHalfMin + EPS_SMALL) ||
|
|
( ptIntPlaneMax.y < - dHalfMax - EPS_SMALL && ptIntPlaneMin.y < - dHalfMin - EPS_SMALL) ||
|
|
( ptIntPlaneMax.y > dHalfMax + EPS_SMALL && ptIntPlaneMin.y > dHalfMin + EPS_SMALL)))
|
|
return false ;
|
|
|
|
// Cerco le eventuali intersezioni con i piani delle facce laterali
|
|
Point3d ptPlaneP( - dHalfMax, - dHalfMax, 0.) ;
|
|
Vector3d vtPlaneN( 0., - dHeight, ( dHalfMax - dHalfMin)) ;
|
|
vtPlaneN.Normalize() ;
|
|
if ( nIntNum < 2 && abs( vtV * vtPlaneN) > EPS_ZERO) {
|
|
if ( nIntNum == 0) {
|
|
ptInt1 = ptP + ( ( ( ptPlaneP - ptP) * vtPlaneN) / ( vtV * vtPlaneN)) * vtV ;
|
|
vtN1 = vtPlaneN ;
|
|
if ( ptInt1.z >= 0 && ptInt1.z <= dHeight &&
|
|
( ptInt1.x + dHalfMax) * dHeight >= ( dHalfMax - dHalfMin) * ptInt1.z &&
|
|
( ptInt1.x - dHalfMax) * dHeight <= ( dHalfMin - dHalfMax) * ptInt1.z)
|
|
++ nIntNum ;
|
|
}
|
|
else {
|
|
ptInt2 = ptP + ( ( ( ptPlaneP - ptP) * vtPlaneN) / ( vtV * vtPlaneN)) * vtV ;
|
|
vtN2 = vtPlaneN ;
|
|
if ( ( ptInt2 - ptInt2).SqLen() > SQ_EPS_SMALL &&
|
|
ptInt2.z >= 0 && ptInt1.z <= dHeight &&
|
|
( ptInt2.x + dHalfMax) * dHeight >= ( dHalfMax - dHalfMin) * ptInt2.z &&
|
|
( ptInt2.x - dHalfMax) * dHeight <= ( dHalfMin - dHalfMax) * ptInt2.z)
|
|
++ nIntNum ;
|
|
}
|
|
}
|
|
vtPlaneN = Vector3d( - dHeight, 0., ( dHalfMax - dHalfMin)) ;
|
|
vtPlaneN.Normalize() ;
|
|
if ( nIntNum < 2 && abs( vtV * vtPlaneN) > EPS_ZERO) {
|
|
if ( nIntNum == 0) {
|
|
ptInt1 = ptP + ( ( ( ptPlaneP - ptP) * vtPlaneN) / ( vtV * vtPlaneN)) * vtV ;
|
|
vtN1 = vtPlaneN ;
|
|
if ( ptInt1.z >= 0 && ptInt1.z <= dHeight &&
|
|
( ptInt1.y + dHalfMax) * dHeight >= ( dHalfMax - dHalfMin) * ptInt1.z &&
|
|
( ptInt1.y - dHalfMax) * dHeight <= ( dHalfMin - dHalfMax) * ptInt1.z)
|
|
++ nIntNum ;
|
|
}
|
|
else {
|
|
ptInt2 = ptP + ( ( ( ptPlaneP - ptP) * vtPlaneN) / ( vtV * vtPlaneN)) * vtV ;
|
|
vtN2 = vtPlaneN ;
|
|
if ( ( ptInt1 - ptInt2).SqLen() > SQ_EPS_SMALL &&
|
|
ptInt2.z >= 0 && ptInt2.z <= dHeight &&
|
|
( ptInt2.y + dHalfMax) * dHeight >= ( dHalfMax - dHalfMin) * ptInt2.z &&
|
|
( ptInt2.y - dHalfMax) * dHeight <= ( dHalfMin - dHalfMax) * ptInt2.z)
|
|
++ nIntNum ;
|
|
}
|
|
}
|
|
ptPlaneP = Point3d( dHalfMax, dHalfMax, 0.) ;
|
|
vtPlaneN = Vector3d( dHeight, 0., ( dHalfMax - dHalfMin)) ;
|
|
vtPlaneN.Normalize() ;
|
|
if ( nIntNum < 2 && abs( vtV * vtPlaneN) > EPS_ZERO) {
|
|
if ( nIntNum == 0) {
|
|
ptInt1 = ptP + ( ( ( ptPlaneP - ptP) * vtPlaneN) / ( vtV * vtPlaneN)) * vtV ;
|
|
vtN1 = vtPlaneN ;
|
|
if ( ptInt1.z >= 0 && ptInt1.z <= dHeight &&
|
|
( ptInt1.y + dHalfMax) * dHeight >= ( dHalfMax - dHalfMin) * ptInt1.z &&
|
|
( ptInt1.y - dHalfMax) * dHeight <= ( dHalfMin - dHalfMax) * ptInt1.z)
|
|
++ nIntNum ;
|
|
}
|
|
else {
|
|
ptInt2 = ptP + ( ( ( ptPlaneP - ptP) * vtPlaneN) / ( vtV * vtPlaneN)) * vtV ;
|
|
vtN2 = vtPlaneN ;
|
|
if ( ( ptInt1 - ptInt2).SqLen() > SQ_EPS_SMALL &&
|
|
ptInt2.z >= 0 && ptInt2.z <= dHeight &&
|
|
( ptInt2.y + dHalfMax) * dHeight >= ( dHalfMax - dHalfMin) * ptInt2.z &&
|
|
( ptInt2.y - dHalfMax) * dHeight <= ( dHalfMin - dHalfMax) * ptInt2.z)
|
|
++ nIntNum ;
|
|
}
|
|
}
|
|
vtPlaneN = Vector3d( 0., dHeight, ( dHalfMax - dHalfMin)) ;
|
|
vtPlaneN.Normalize() ;
|
|
if ( nIntNum < 2 && abs( vtV * vtPlaneN) > EPS_ZERO) {
|
|
if ( nIntNum == 0) {
|
|
ptInt1 = ptP + ( ( ( ptPlaneP - ptP) * vtPlaneN) / ( vtV * vtPlaneN)) * vtV ;
|
|
vtN1 = vtPlaneN ;
|
|
if ( ptInt1.z >= 0 && ptInt1.z <= dHeight &&
|
|
( ptInt1.x + dHalfMax) * dHeight >= ( dHalfMax - dHalfMin) * ptInt1.z &&
|
|
( ptInt1.x - dHalfMax) * dHeight <= ( dHalfMin - dHalfMax) * ptInt1.z)
|
|
++ nIntNum ;
|
|
}
|
|
else {
|
|
ptInt2 = ptP + ( ( ( ptPlaneP - ptP) * vtPlaneN) / ( vtV * vtPlaneN)) * vtV ;
|
|
vtN2 = vtPlaneN ;
|
|
if ( ( ptInt1 - ptInt2).SqLen() > SQ_EPS_SMALL &&
|
|
ptInt2.z >= 0 && ptInt1.z <= dHeight &&
|
|
( ptInt2.x + dHalfMax) * dHeight >= ( dHalfMax - dHalfMin) * ptInt2.z &&
|
|
( ptInt2.x - dHalfMax) * dHeight <= ( dHalfMin - dHalfMax) * ptInt2.z)
|
|
++ nIntNum ;
|
|
}
|
|
}
|
|
|
|
// La retta interseca il tronco di piramide
|
|
if ( nIntNum == 2) {
|
|
if ( ( ptInt1 - ptP) * vtV > ( ptInt2 - ptP) * vtV) {
|
|
swap( ptInt1, ptInt2) ;
|
|
swap( vtN1, vtN2) ;
|
|
}
|
|
ptInt1.ToGlob( frTruncPyramFrame) ;
|
|
ptInt2.ToGlob( frTruncPyramFrame) ;
|
|
vtN1.ToGlob( frTruncPyramFrame) ;
|
|
vtN2.ToGlob( frTruncPyramFrame) ;
|
|
return true ;
|
|
}
|
|
|
|
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 < m_nMapNum ; ++ nMap) {
|
|
for ( int nDex = 0 ; nDex < m_nDim[nMap] ; ++ 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 ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// La retta deve essere espressa nel sistema Zmap.
|
|
// Per riferimento viene restituito un vettore di intersezioni della retta con i triangoli della superficie del solido.
|
|
// Si restituisce false in caso di errore, true altrimenti.
|
|
bool
|
|
VolZmap::GetLineIntersection( const Point3d& ptP, const Vector3d& vtD, ILZIVECTOR& vIntersInfo) const
|
|
{
|
|
// Direzione normalizzata
|
|
Vector3d vtDir = vtD ;
|
|
vtDir.Normalize() ;
|
|
|
|
// Punto e vettore espressi nel riferimento intrinseco dello Zmap
|
|
Point3d ptLocP = ptP ;
|
|
Vector3d vtDirL = vtDir ;
|
|
ptLocP.ToLoc( m_MapFrame) ;
|
|
vtDirL.ToLoc( m_MapFrame) ;
|
|
|
|
// Intersezione fra semiretta e BBox dello Zmap
|
|
double dU1, dU2 ;
|
|
bool bLineBBoxInters = IntersLineZMapBBox( ptLocP, vtDirL, dU1, dU2) && ( dU1 > 0 || dU2 > 0) ;
|
|
|
|
// Semiretta esterna al box dello Zmap quindi esterna anche allo Zmap
|
|
if ( ! bLineBBoxInters)
|
|
return true ;
|
|
|
|
// Lancio eventuale aggiornamento pendente della grafica
|
|
if ( m_nMapNum == 1)
|
|
UpdateSingleMapGraphics() ;
|
|
else
|
|
UpdateTripleMapGraphics() ;
|
|
|
|
// Ciclo sui blocchi
|
|
for ( int nB = 0 ; nB < m_nNumBlock ; ++ nB) {
|
|
// Determino indici IJK del blocco; se non trovo il blocco, errore
|
|
int nBlockIJK[3] ;
|
|
if ( ! GetBlockIJKFromN( nB, nBlockIJK))
|
|
return false ;
|
|
// Costruisco il bounding-box del blocco; se non è possibile, errore
|
|
BBox3d b3BlockBox ;
|
|
if ( ! GetBlockBox( nBlockIJK, b3BlockBox))
|
|
return false ;
|
|
// Se c'è intersezione valuto tutti i voxel interni
|
|
if ( TestIntersLineBox( ptLocP, vtDirL, b3BlockBox.GetMin(), b3BlockBox.GetMax())) {
|
|
// Ciclo sui voxel del blocco.
|
|
// Triangoli smooth
|
|
for ( int nV = 0 ; nV < int( m_BlockSmoothTria[nB].size()) ; ++ nV) {
|
|
// Box del voxel
|
|
BBox3d b3Vox ;
|
|
int nCurVoxIJK[3] = { m_BlockSmoothTria[nB][nV].i,
|
|
m_BlockSmoothTria[nB][nV].j,
|
|
m_BlockSmoothTria[nB][nV].k } ;
|
|
GetVoxelBox( nCurVoxIJK[0], nCurVoxIJK[1], nCurVoxIJK[2], b3Vox) ;
|
|
// Se non c'è intersezione col voxel, passo al successivo.
|
|
if ( ! TestIntersLineBox( ptLocP, vtDirL, b3Vox.GetMin(), b3Vox.GetMax()))
|
|
continue ;
|
|
for ( int nT = 0 ; nT < int( m_BlockSmoothTria[nB][nV].vTria.size()) ; ++ nT) {
|
|
Triangle3d trTria = m_BlockSmoothTria[nB][nV].vTria[nT] ;
|
|
if ( ! trTria.Validate( true))
|
|
continue ;
|
|
Point3d ptLineTria1, ptLineTria2 ;
|
|
// Studio dell'intersezione della retta con il triangolo corrente
|
|
int nIntType = IntersLineTria( ptP, vtDir, 1.5 * dU2, trTria, 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) {
|
|
int nNumVox ;
|
|
GetVoxNFromIJK( nCurVoxIJK[0], nCurVoxIJK[1], nCurVoxIJK[2], nNumVox) ;
|
|
vIntersInfo.emplace_back( nIntType, ( ptLineTria1 - ptP) * vtDir,
|
|
nNumVox, nB, ptLineTria1, trTria) ;
|
|
}
|
|
// altrimenti ci sono due intersezioni
|
|
else {
|
|
int nNumVox ;
|
|
GetVoxNFromIJK( nCurVoxIJK[0], nCurVoxIJK[1], nCurVoxIJK[2], nNumVox) ;
|
|
double dP1 = ( ptLineTria1 - ptP) * vtDir ;
|
|
double dP2 = ( ptLineTria2 - ptP) * vtDir ;
|
|
vIntersInfo.emplace_back( nIntType, ( dP1 < dP2 ? dP1 : dP2), ( dP1 < dP2 ? dP2 : dP1),
|
|
nNumVox, nB, ptLineTria1, ptLineTria2, trTria) ;
|
|
}
|
|
}
|
|
}
|
|
// Triangoli sharp interni al blocco
|
|
for ( int nV = 0 ; nV < int( m_BlockSharpTria[nB].size()) ; ++ nV) {
|
|
int nCurVoxIJK[3] = { m_BlockSharpTria[nB][nV].i,
|
|
m_BlockSharpTria[nB][nV].j,
|
|
m_BlockSharpTria[nB][nV].k } ;
|
|
|
|
// Ciclo sulle componenti connesse
|
|
for ( int nC = 0 ; nC < int( m_BlockSharpTria[nB][nV].vCompoTria.size()) ; ++ nC) {
|
|
for ( int nT = 0 ; nT < int( m_BlockSharpTria[nB][nV].vCompoTria[nC].size()) ; ++ nT) {
|
|
Triangle3d trTria = m_BlockSharpTria[nB][nV].vCompoTria[nC][nT] ;
|
|
if ( ! trTria.Validate( true))
|
|
continue ;
|
|
Point3d ptLineTria1, ptLineTria2 ;
|
|
// Studio dell'intersezione della retta con il triangolo corrente
|
|
int nIntType = IntersLineTria( ptP, vtDir, 1.5 * dU2, trTria, 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) {
|
|
int nNumVox ;
|
|
GetVoxNFromIJK( nCurVoxIJK[0], nCurVoxIJK[1], nCurVoxIJK[2], nNumVox) ;
|
|
vIntersInfo.emplace_back( nIntType, ( ptLineTria1 - ptP) * vtDir,
|
|
nNumVox, nB, ptLineTria1, trTria) ;
|
|
}
|
|
// altrimenti ci sono due intersezioni
|
|
else {
|
|
int nNumVox ;
|
|
GetVoxNFromIJK( nCurVoxIJK[0], nCurVoxIJK[1], nCurVoxIJK[2], nNumVox) ;
|
|
double dP1 = ( ptLineTria1 - ptP) * vtDir ;
|
|
double dP2 = ( ptLineTria2 - ptP) * vtDir ;
|
|
vIntersInfo.emplace_back( nIntType, ( dP1 < dP2 ? dP1 : dP2), ( dP1 < dP2 ? dP2 : dP1),
|
|
nNumVox, nB, ptLineTria1, ptLineTria2, trTria) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Triangoli grandi del blocco
|
|
for ( int nT = 0 ; nT < int( m_BlockBigTria[nB].size()) ; ++ nT) {
|
|
Triangle3d trTria = m_BlockBigTria[nB][nT] ;
|
|
Point3d ptLineTria1, ptLineTria2 ;
|
|
// Studio dell'intersezione della retta con il triangolo corrente
|
|
int nIntType = IntersLineTria( ptP, vtDir, 1.5 * dU2, trTria, 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) {
|
|
vIntersInfo.emplace_back( nIntType, ( ptLineTria1 - ptP) * vtDir,
|
|
-1, nB, ptLineTria1, trTria) ;
|
|
}
|
|
// altrimenti ci sono due intersezioni
|
|
else {
|
|
double dP1 = ( ptLineTria1 - ptP) * vtDir ;
|
|
double dP2 = ( ptLineTria2 - ptP) * vtDir ;
|
|
vIntersInfo.emplace_back( nIntType, ( dP1 < dP2 ? dP1 : dP2), ( dP1 < dP2 ? dP2 : dP1),
|
|
-1, nB, ptLineTria1, ptLineTria2, trTria) ;
|
|
}
|
|
}
|
|
}
|
|
// In ogni caso valuto i triangoli sharp fra blocchi
|
|
for ( int nV = 0 ; nV < int( m_InterBlockSharpTria[nB].size()) ; ++ nV) {
|
|
int nCurVoxIJK[3] = { m_InterBlockSharpTria[nB][nV].i,
|
|
m_InterBlockSharpTria[nB][nV].j,
|
|
m_InterBlockSharpTria[nB][nV].k } ;
|
|
// Ciclo sulle componenti connesse
|
|
for ( int nC = 0 ; nC < int( m_InterBlockSharpTria[nB][nV].vCompoTria.size()) ; ++ nC) {
|
|
for ( int nT = 0 ; nT < int( m_InterBlockSharpTria[nB][nV].vCompoTria[nC].size()) ; ++ nT) {
|
|
Triangle3d trTria = m_InterBlockSharpTria[nB][nV].vCompoTria[nC][nT] ;
|
|
if ( ! trTria.Validate( true))
|
|
continue ;
|
|
Point3d ptLineTria1, ptLineTria2 ;
|
|
// Studio dell'intersezione della retta con il triangolo corrente
|
|
int nIntType = IntersLineTria( ptP, vtDir, 1.5 * dU2, trTria, 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) {
|
|
int nNumVox ;
|
|
GetVoxNFromIJK( nCurVoxIJK[0], nCurVoxIJK[1], nCurVoxIJK[2], nNumVox) ;
|
|
vIntersInfo.emplace_back( nIntType, ( ptLineTria1 - ptP) * vtDir,
|
|
nNumVox, nB, ptLineTria1, trTria) ;
|
|
}
|
|
// altrimenti ci sono due intersezioni
|
|
else {
|
|
int nNumVox ;
|
|
GetVoxNFromIJK( nCurVoxIJK[0], nCurVoxIJK[1], nCurVoxIJK[2], nNumVox) ;
|
|
double dP1 = ( ptLineTria1 - ptP) * vtDir ;
|
|
double dP2 = ( ptLineTria2 - ptP) * vtDir ;
|
|
vIntersInfo.emplace_back( nIntType, ( dP1 < dP2 ? dP1 : dP2), ( dP1 < dP2 ? dP2 : dP1),
|
|
nNumVox, nB, ptLineTria1, ptLineTria2, trTria) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ordino le intersezioni in base al parametro distanza con segno da ptP
|
|
sort( vIntersInfo.begin(), vIntersInfo.end(),
|
|
[]( const IntLineZmapInfo& a, const IntLineZmapInfo& b)
|
|
{ double dFP = (( a.nILTT == ILTT_SEGM || a.nILTT == ILTT_SEGM_ON_EDGE) ? 0.5 * ( a.dU + a.dU2) : a.dU) ;
|
|
double dLP = (( b.nILTT == ILTT_SEGM || b.nILTT == ILTT_SEGM_ON_EDGE) ? 0.5 * ( b.dU + b.dU2) : b.dU) ;
|
|
return ( dLP > dFP) ; }) ;
|
|
|
|
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 plPlaneLoc = plPlane ;
|
|
plPlaneLoc.ToLoc( m_MapFrame) ;
|
|
|
|
// Se non c'è intersezione fra piano e bounding-box del solido, ho finito.
|
|
if ( ! TestIntersPlaneZmapBBox( plPlaneLoc))
|
|
return true ;
|
|
// Lancio eventuale aggiornamento pendente della grafica
|
|
if ( m_nMapNum == 1)
|
|
UpdateSingleMapGraphics() ;
|
|
else
|
|
UpdateTripleMapGraphics() ;
|
|
// Vettore di segmenti
|
|
vector<CurveLine> vLine ;
|
|
// Ciclo sui blocchi
|
|
for ( int nB = 0 ; nB < m_nNumBlock ; ++ nB) {
|
|
// Determino indici IJK del blocco; Se non trovo il blocco, errore
|
|
int nBlockIJK[3] ;
|
|
if ( ! GetBlockIJKFromN( nB, nBlockIJK))
|
|
return false ;
|
|
// Costruisco il bounding-bx del blocco; se non è possiblie, errore
|
|
BBox3d b3BlockBox ;
|
|
if ( ! GetBlockBox( nBlockIJK, b3BlockBox))
|
|
return false ;
|
|
// Se c'è intersezione valuto tutti i voxel interni
|
|
if ( TestIntersPlaneBox( plPlaneLoc, b3BlockBox)) {
|
|
// Ciclo sui voxel del blocco.
|
|
// Triangoli smooth
|
|
for ( int nV = 0 ; nV < int( m_BlockSmoothTria[nB].size()) ; ++ nV) {
|
|
// Box del voxel
|
|
BBox3d b3Vox ;
|
|
GetVoxelBox( m_BlockSmoothTria[nB][nV].i, m_BlockSmoothTria[nB][nV].j, m_BlockSmoothTria[nB][nV].k, b3Vox) ;
|
|
// Se non c'è intersezione col voxel, passo al successivo.
|
|
if ( ! TestIntersPlaneBox( plPlaneLoc, b3Vox))
|
|
continue ;
|
|
for ( int nT = 0 ; nT < int( m_BlockSmoothTria[nB][nV].vTria.size()) ; ++ nT) {
|
|
Triangle3d trTria = m_BlockSmoothTria[nB][nV].vTria[nT] ;
|
|
Point3d ptSt, ptEn ;
|
|
int nIntersType = IntersPlaneTria( plPlane, trTria, ptSt, ptEn) ;
|
|
if ( nIntersType == IPTT_EDGE || nIntersType == IPTT_YES) {
|
|
// Costruisco il tratto di curva
|
|
CurveLine cvLine ;
|
|
if ( cvLine.Set( ptSt, ptEn))
|
|
vLine.emplace_back( cvLine) ;
|
|
}
|
|
}
|
|
}
|
|
// Triangoli sharp interni al blocco
|
|
for ( int nV = 0 ; nV < int( m_BlockSharpTria[nB].size()) ; ++ nV) {
|
|
// Box del voxel
|
|
BBox3d b3Vox ;
|
|
GetVoxelBox( m_BlockSharpTria[nB][nV].i, m_BlockSharpTria[nB][nV].j, m_BlockSharpTria[nB][nV].k, b3Vox) ;
|
|
// Se non c'è intersezione col voxel, passo al successivo.
|
|
// Ciclo sulle componenti connesse
|
|
for ( int nC = 0 ; nC < int( m_BlockSharpTria[nB][nV].vCompoTria.size()) ; ++ nC) {
|
|
for ( int nT = 0 ; nT < int( m_BlockSharpTria[nB][nV].vCompoTria[nC].size()) ; ++ nT) {
|
|
Triangle3d trTria = m_BlockSharpTria[nB][nV].vCompoTria[nC][nT] ;
|
|
Point3d ptSt, ptEn ;
|
|
int nIntersType = IntersPlaneTria(plPlane, trTria, ptSt, ptEn) ;
|
|
if (nIntersType == IPTT_EDGE || nIntersType == IPTT_YES) {
|
|
// Costruisco il tratto di curva
|
|
CurveLine cvLine ;
|
|
if ( cvLine.Set(ptSt, ptEn))
|
|
vLine.emplace_back( cvLine) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Triangoli grandi del blocco
|
|
for ( int nT = 0 ; nT < int( m_BlockBigTria[nB].size()) ; ++ nT) {
|
|
Triangle3d trTria = m_BlockBigTria[nB][nT] ;
|
|
Point3d ptSt, ptEn ;
|
|
int nIntersType = IntersPlaneTria(plPlane, trTria, ptSt, ptEn) ;
|
|
if ( nIntersType == IPTT_EDGE || nIntersType == IPTT_YES) {
|
|
// Costruisco il tratto di curva
|
|
CurveLine cvLine ;
|
|
if ( cvLine.Set(ptSt, ptEn))
|
|
vLine.emplace_back( cvLine) ;
|
|
}
|
|
}
|
|
}
|
|
// In ogni caso valuto i triangoli sharp fra blocchi
|
|
for ( int nV = 0 ; nV < int( m_InterBlockSharpTria[nB].size()) ; ++ nV) {
|
|
// Ciclo sulle componenti connesse
|
|
for ( int nC = 0 ; nC < int( m_InterBlockSharpTria[nB][nV].vCompoTria.size()) ; ++ nC) {
|
|
for ( int nT = 0 ; nT < int( m_InterBlockSharpTria[nB][nV].vCompoTria[nC].size()) ; ++ nT) {
|
|
Triangle3d trTria = m_InterBlockSharpTria[nB][nV].vCompoTria[nC][nT] ;
|
|
Point3d ptSt, ptEn ;
|
|
int nIntersType = IntersPlaneTria( plPlane, trTria, ptSt, ptEn) ;
|
|
if ( nIntersType == IPTT_EDGE || nIntersType == IPTT_YES) {
|
|
// Costruisco il tratto di curva
|
|
CurveLine cvLine ;
|
|
if ( cvLine.Set(ptSt, ptEn))
|
|
vLine.emplace_back( cvLine) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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, 10 * EPS_SMALL))
|
|
return false ;
|
|
}
|
|
pLoop->SetExtrusion( plPlane.GetVersN()) ;
|
|
pLoop->MergeCurves( 10 * EPS_SMALL, ANG_TOL_STD_DEG) ;
|
|
// Inserisco la curva composita nella raccolta da ritornare
|
|
vpLoop.emplace_back( Release( pLoop)) ;
|
|
}
|
|
|
|
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( plPlane, b3Zmap) ;
|
|
}
|