Files
EgtGeomKernel/IntersLineSurfStd.cpp
Dario Sassi cd48e2de3b EgtGeomKernel :
- varie correzioni ortografiche.
2025-11-15 11:00:21 +01:00

2158 lines
74 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2017-2022
//----------------------------------------------------------------------------
// File : IntersLineSurfStd.cpp Data : 08.01.22 Versione : 2.4a3
// Contenuto : Implementazione delle funzioni di intersezione
// componente lineare e superficie standard.
//
//
// Modifiche : 22.01.15 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
#include "stdafx.h"
#include "IntersLineSurfStd.h"
#include "IntersLineBox.h"
#include "/EgtDev/Include/EGkIntersLinePlane.h"
#include "/EgtDev/Include/EGkFrame3d.h"
#include "/EgtDev/Include/ENkPolynomialRoots.h"
#include "/EgtDev/Include/EgtNumUtils.h"
#include <algorithm>
using namespace std ;
//----------------------------------------------------------------------------
int
LineDisc( const Point3d& ptPLine, const Vector3d& vtVLine,
const Point3d& ptPDisc, const Vector3d& vtVDisc, double dRad,
double& dU1, double& dU2)
{
// Il raggio del disco deve essere non nullo.
if ( dRad < EPS_SMALL)
return D_ERROR_INT ;
// Si richiede che i vettori siano normalizzati
if ( ! vtVDisc.IsNormalized() || ! vtVLine.IsNormalized())
return D_ERROR_INT ;
// Intersezione con il piano del disco
Point3d ptInt ;
Plane3d plDisc ; plDisc.Set( ptPDisc, vtVDisc) ;
int nLpInt = IntersLinePlane( ptPLine, vtVLine, 1, plDisc, ptInt, false) ;
if ( nLpInt == ILPT_NO)
return D_NO_INTERS ;
// Un punto di intersezione con il piano
if ( nLpInt == ILPT_YES) {
double dDistCdP = Dist( ptInt, ptPDisc) ;
// Se distanza uguale al raggio, intersezione sul bordo
if ( abs( dDistCdP - dRad) < EPS_SMALL) {
dU1 = ( ptInt - ptPLine) * vtVLine ;
dU2 = dU1 ;
return D_BOUNDARY_INT_LINE_NOT_IN_PLANE ;
}
// Se distanza superiore al raggio, nessuna intersezione
if ( dDistCdP > dRad)
return D_NO_INTERS ;
// Distanza inferiore al raggio, intersezione interna
dU1 = ( ptInt - ptPLine) * vtVLine ;
dU2 = dU1 ;
return D_INNER_INT_LINE_NOT_IN_PLANE ;
}
// La linea giace nel piano
{
// Proiezione del centro del disco sulla linea
Point3d ptP = ptPLine + (( ptPDisc - ptPLine) * vtVLine) * vtVLine ;
// Distanza di questo punto di proiezione dal centro del disco
double dDist = Dist( ptPDisc, ptP) ;
// Se distanza uguale al raggio, intersezione tangente
if ( abs( dDist - dRad) < EPS_SMALL) {
dU1 = ( ptP - ptPLine) * vtVLine ;
dU2 = dU1 ;
return D_ONE_INT_LINE_ON_PLANE ;
}
// Se distanza superiore al raggio, nessuna intersezione
if ( dDist > dRad)
return D_NO_INTERS ;
// Distanza inferiore al raggio, due intersezioni secanti
double dDist2 = sqrt( dRad * dRad - dDist * dDist) ;
Point3d ptI1 = ptP - dDist2 * vtVLine ;
dU1 = ( ptI1 - ptPLine) * vtVLine ;
Point3d ptI2 = ptP + dDist2 * vtVLine ;
dU2 = ( ptI2 - ptPLine) * vtVLine ;
return D_INFINITE_INT_LINE_ON_PLANE ;
}
}
//----------------------------------------------------------------------------
int
RayDisc( const Point3d& ptPLine, const Vector3d& vtVLine,
const Point3d& ptPDisc, const Vector3d& vtVDisc, double dRad,
double& dU1, double& dU2)
{
int nIntType = LineDisc( ptPLine, vtVLine, ptPDisc, vtVDisc, dRad, dU1, dU2) ;
if ( nIntType == D_ERROR_INT)
return nIntType ;
// La retta corrispondente al raggio è nel
// piano e attraversa la circonferenza.
if ( nIntType == D_INFINITE_INT_LINE_ON_PLANE) {
// Poiché dU2 > dU1, se dU2 < 0 allora dU1 < 0.
// La semiretta non interferisce col disco.
if ( dU2 < - EPS_SMALL)
nIntType = D_NO_INTERS ;
// Se solo dU1 < 0, c'è intersezione e la
// semi-retta parte dall'interno del disco
else if ( dU1 < - EPS_SMALL) {
dU1 = 0 ;
nIntType = D_INFINITE_INT_LINE_ON_PLANE ;
}
}
// In tutti gli altri casi c'è un solo punto
// di contatto fra retta e disco.
else {
// Se tale punto avviene a un parametro negativo,
// la semi-retta non interseca il disco.
if ( dU1 < - EPS_SMALL)
nIntType = D_NO_INTERS ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
SegmentDisc( const Point3d& ptPLine, const Vector3d& vtVLine, double dLen,
const Point3d& ptPDisc, const Vector3d& vtVDisc, double dRad,
double& dU1, double& dU2)
{
int nIntType = LineDisc( ptPLine, vtVLine, ptPDisc, vtVDisc, dRad, dU1, dU2) ;
if ( nIntType == D_ERROR_INT)
return nIntType ;
// La retta corrispondente al segmento è nel
// piano e attraversa la circonferenza.
if ( nIntType == D_INFINITE_INT_LINE_ON_PLANE) {
// Interferenza
if ( dU1 < dLen + EPS_SMALL && dU2 > - EPS_SMALL) {
if ( dU1 > dLen - EPS_SMALL)
nIntType = D_ONE_INT_LINE_ON_PLANE ;
else if ( dU2 < EPS_SMALL) {
dU1 = 0 ;
nIntType = D_ONE_INT_LINE_ON_PLANE ;
}
else {
Clamp( dU1, 0., dLen) ;
Clamp( dU2, 0., dLen) ;
}
}
// Il segmento non interagisce
else
nIntType = D_NO_INTERS ;
}
// Negli altri casi c'è una sola intersezione
else if ( dU1 < - EPS_SMALL || dU1 > dLen + EPS_SMALL)
nIntType = D_NO_INTERS ;
return nIntType ;
}
//----------------------------------------------------------------------------
int
LineSphere( const Point3d& ptPLine, const Vector3d& vtVLine,
const Point3d& ptSphC, double dRad,
double& dU1, double& dU2)
{
// Il raggio della sfera deve essere non nullo.
if ( dRad < EPS_SMALL)
return S_ERROR_INT ;
// Si richiede che il vettore sia normalizzato
if ( ! vtVLine.IsNormalized())
return S_ERROR_INT ;
// Vettore congiungente il punto della retta con il centro della sfera
Vector3d vtR = ( ptSphC - ptPLine) - ( ptSphC - ptPLine) * vtVLine * vtVLine ;
// Quadrato del raggio della sfera
double dSqRad = dRad * dRad ;
// Quadrato della distanza punto retta
double dSqDist = vtR * vtR ;
// Studio delle soluzioni
int nIntType ;
// Retta esterna
if ( dSqDist > dSqRad + 2 * dRad * EPS_SMALL)
nIntType = S_NO_INTERS ;
// Retta tangente
else if ( dSqDist > dSqRad - 2 * dRad * EPS_SMALL) {
dU1 = ( ptSphC - ptPLine) * vtVLine ;
nIntType = S_ONE_INT_TAN ;
}
// Retta secante
else {
double dSemiDistSol = sqrt( dSqRad - dSqDist) ;
dU1 = ( ptSphC - ptPLine) * vtVLine - dSemiDistSol ;
dU2 = ( ptSphC - ptPLine) * vtVLine + dSemiDistSol ;
nIntType = S_TWO_INT ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
RaySphere( const Point3d& ptPLine, const Vector3d& vtVLine,
const Point3d& ptSphC, double dRad,
double& dU1, double& dU2)
{
int nIntType = LineSphere( ptPLine, vtVLine, ptSphC, dRad, dU1, dU2) ;
if ( nIntType == S_ERROR_INT)
return nIntType ;
// Caso in cui retta associata al raggio è tangente
if ( nIntType == S_ONE_INT_TAN) {
// Se la soluzione è negativa, il raggio
// non interferisce con la sfera.
if ( dU1 < - EPS_SMALL)
nIntType = S_NO_INTERS ;
}
// Caso in cui la retta associata al raggio è secante
else if ( nIntType == S_TWO_INT) {
// Se dU1 è negativo, vi è solo una soluzione,
// e in questo caso il raggio non è tangente.
if ( dU1 < - EPS_SMALL) {
dU1 = dU2 ;
nIntType = S_ONE_INT_SEC ;
}
// Se anche dU2 è negativo il raggio,
// non interferisce.
if ( dU2 < - EPS_SMALL)
nIntType = S_NO_INTERS ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
SegmentSphere( const Point3d& ptPLine, const Vector3d& vtVLine, double dLen,
const Point3d& ptSphC, double dRad,
double& dU1, double& dU2)
{
int nIntType = LineSphere( ptPLine, vtVLine, ptSphC, dRad, dU1, dU2) ;
if ( nIntType == S_ERROR_INT)
return nIntType ;
// La retta associata al segmento è tangente
if ( nIntType == S_ONE_INT_TAN) {
// Se il punto è fuori dal segmento,
// non vi sono soluzioni
if ( dU1 < - EPS_SMALL || dU1 > dLen + EPS_SMALL)
nIntType = S_NO_INTERS ;
}
// La retta associata al segmento è secante
else if ( nIntType == S_TWO_INT) {
// Segmento esterno
if ( dU1 > dLen + EPS_SMALL)
nIntType = S_NO_INTERS ;
else if ( dU1 > - EPS_SMALL) {
// Segmento secante con una intersezione
// In questo caso è valida dU1
if ( dU2 > dLen + EPS_SMALL)
nIntType = S_ONE_INT_SEC ;
}
else {
// Il segmento non interferisce
if ( dU2 > dLen + EPS_SMALL) {
nIntType = S_NO_INTERS ;
}
// Segmento secante con una intersezione
// In questo caso è valida dU2, quindi
// assegnamo dU2 a dU1
else if ( dU2 > - EPS_SMALL) {
dU1 = dU2 ;
nIntType = S_ONE_INT_SEC ;
}
// Il segmento non interferisce
else
nIntType = S_NO_INTERS ;
}
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
LineSemiSphere( const Point3d& ptPLine, const Vector3d& vtVLine,
const Point3d& ptSphC, const Vector3d& vtSSphOrient, double dRad,
double& dU1, double& dU2)
{
int nIntType = LineSphere( ptPLine, vtVLine, ptSphC, dRad, dU1, dU2) ;
if ( nIntType == S_ERROR_INT || ! vtSSphOrient.IsNormalized())
return S_ERROR_INT ;
// Un punto di tangenza
if ( nIntType == S_ONE_INT_TAN) {
Point3d ptInt = ptPLine + dU1 * vtVLine ;
Vector3d vtInt = ptInt - ptSphC ;
vtInt.Normalize() ;
// Se il punto di contatto è nella calotta superiore : scarto la soluzione
if ( vtInt * vtSSphOrient > EPS_ZERO)
nIntType = S_NO_INTERS ;
}
// Due punti di secanza
else if ( nIntType == S_TWO_INT) {
Point3d ptInt1 = ptPLine + dU1 * vtVLine ;
Point3d ptInt2 = ptPLine + dU1 * vtVLine ;
Vector3d vtInt1 = ptInt1 - ptSphC ;
Vector3d vtInt2 = ptInt2 - ptSphC ;
vtInt1.Normalize() ;
vtInt2.Normalize() ;
int nInt = 2 ;
// Scarto le soluzioni sulla calotta superiore
if ( vtInt1 * vtSSphOrient > EPS_ZERO) {
dU1 = dU2 ;
-- nInt ;
}
if ( vtInt2 * vtSSphOrient > EPS_ZERO)
-- nInt ;
// In base al numero di soluzioni valide
// aggiorno la tipologia di intersezione.
if ( nInt == 1)
nIntType = S_ONE_INT_SEC ;
else if ( nInt == 0)
nIntType = S_NO_INTERS ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
RaySemiSphere( const Point3d& ptPLine, const Vector3d& vtVLine,
const Point3d& ptSphC, const Vector3d& vtSSphOrient, double dRad,
double& dU1, double& dU2)
{
int nIntType = RaySphere( ptPLine, vtVLine, ptSphC, dRad, dU1, dU2) ;
if ( nIntType == S_ERROR_INT || ( ! vtSSphOrient.IsNormalized()))
return S_ERROR_INT ;
// Un Punto in cui la semi-retta interferisce con la semi-sfera
if ( nIntType == S_ONE_INT_SEC || nIntType == S_ONE_INT_TAN) {
Point3d ptInt = ptPLine + dU1 * vtVLine ;
Vector3d vtInt = ptInt - ptSphC ;
vtInt.Normalize() ;
// Se il punto di contatto è nella calotta superiore
// Scarto la soluzione
if ( vtInt * vtSSphOrient > EPS_ZERO)
nIntType = S_NO_INTERS ;
}
// Due punti in cui la semi-retta è secante
else if ( nIntType == S_TWO_INT) {
Point3d ptInt1 = ptPLine + dU1 * vtVLine ;
Point3d ptInt2 = ptPLine + dU1 * vtVLine ;
Vector3d vtInt1 = ptInt1 - ptSphC ;
Vector3d vtInt2 = ptInt2 - ptSphC ;
vtInt1.Normalize() ;
vtInt2.Normalize() ;
int nInt = 2 ;
// Scarto le soluzioni sulla calotta superiore
if ( vtInt1 * vtSSphOrient > EPS_ZERO) {
dU1 = dU2 ;
-- nInt ;
}
if ( vtInt2 * vtSSphOrient > EPS_ZERO)
-- nInt ;
// In base al numero di soluzioni valide
// aggiorno la tipologia di intersezione.
if ( nInt == 1)
nIntType = S_ONE_INT_SEC ;
else if ( nInt == 0)
nIntType = S_NO_INTERS ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
SegmentSemiSphere( const Point3d& ptPLine, const Vector3d& vtVLine, double dLen,
const Point3d& ptSphC, const Vector3d& vtSSphOrient, double dRad,
double& dU1, double& dU2)
{
int nIntType = SegmentSphere( ptPLine, vtVLine, dLen, ptSphC, dRad, dU1, dU2) ;
if ( nIntType == S_ERROR_INT || ( ! vtSSphOrient.IsNormalized()))
return S_ERROR_INT ;
// Un Punto in cui il segmento interferisce con la semi-sfera
if ( nIntType == S_ONE_INT_SEC || nIntType == S_ONE_INT_TAN) {
Point3d ptInt = ptPLine + dU1 * vtVLine ;
Vector3d vtInt = ptInt - ptSphC ;
vtInt.IsNormalized() ;
// Se il punto di contatto è nella calotta superiore
// Scarto la soluzione
if ( vtInt * vtSSphOrient > EPS_ZERO)
nIntType = S_NO_INTERS ;
}
// Due punti in cui il segmento è secante
else if ( nIntType == S_TWO_INT) {
Point3d ptInt1 = ptPLine + dU1 * vtVLine ;
Point3d ptInt2 = ptPLine + dU1 * vtVLine ;
Vector3d vtInt1 = ptInt1 - ptSphC ;
Vector3d vtInt2 = ptInt2 - ptSphC ;
vtInt1.Normalize() ;
vtInt2.Normalize() ;
int nInt = 2 ;
// Scarto le soluzioni sulla calotta superiore
if ( vtInt1 * vtSSphOrient > EPS_ZERO) {
dU1 = dU2 ;
-- nInt ;
}
if ( vtInt2 * vtSSphOrient > EPS_ZERO)
-- nInt ;
// In base al numero di soluzioni valide
// aggiorno la tipologia di intersezione.
if ( nInt == 1)
nIntType = S_ONE_INT_SEC ;
else if ( nInt == 0)
nIntType = S_NO_INTERS ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
LinCompSemiSphere( const Point3d& ptPLine, const Vector3d& vtVLine, double dLen, int nLinType,
const Point3d& ptSphC, const Vector3d& vtSSphOrient, double dRad,
double& dU1, double& dU2)
{
int nIntType ;
// Retta
if ( nLinType == Line)
nIntType = LineSphere( ptPLine, vtVLine, ptSphC, dRad, dU1, dU2) ;
// Semi-retta
else if ( nLinType == Ray)
nIntType = RaySphere( ptPLine, vtVLine, ptSphC, dRad, dU1, dU2) ;
// Segmento
else if ( nLinType == Segment)
nIntType = SegmentSphere( ptPLine, vtVLine, dLen, ptSphC, dRad, dU1, dU2) ;
// Errore
else
nIntType = S_ERROR_INT ;
// Ancora errore
if ( nIntType == S_ERROR_INT || ( ! vtSSphOrient.IsNormalized()))
return S_ERROR_INT ;
// Un Punto in cui il segmento interferisce con la semi-sfera
if ( nIntType == S_ONE_INT_SEC || nIntType == S_ONE_INT_TAN) {
Point3d ptInt = ptPLine + dU1 * vtVLine ;
Vector3d vtInt = ptInt - ptSphC ;
vtInt.IsNormalized() ;
// Se il punto di contatto è nella calotta superiore
// Scarto la soluzione
if ( vtInt * vtSSphOrient > EPS_ZERO)
nIntType = S_NO_INTERS ;
}
// Due punti in cui il segmento è secante
else if ( nIntType == S_TWO_INT) {
Point3d ptInt1 = ptPLine + dU1 * vtVLine ;
Point3d ptInt2 = ptPLine + dU1 * vtVLine ;
Vector3d vtInt1 = ptInt1 - ptSphC ;
Vector3d vtInt2 = ptInt2 - ptSphC ;
vtInt1.Normalize() ;
vtInt2.Normalize() ;
int nInt = 2 ;
// Scarto le soluzioni sulla calotta superiore
if ( vtInt1 * vtSSphOrient > EPS_ZERO) {
dU1 = dU2 ;
-- nInt ;
}
if ( vtInt2 * vtSSphOrient > EPS_ZERO)
-- nInt ;
// In base al numero di soluzioni valide
// aggiorno la tipologia di intersezione.
if ( nInt == 1)
nIntType = S_ONE_INT_SEC ;
else if ( nInt == 0)
nIntType = S_NO_INTERS ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
IntersLineInfiniteCylinder( const Point3d& ptPLine, const Vector3d& vtVLine,
const Point3d& ptPCyl, const Vector3d& vtVCyl, double dCylRad,
double& dU1, double& dU2)
{
// Se il raggio non è significativamente maggiore di zero, vi è un errore.
if ( dCylRad < EPS_SMALL)
return CC_ERROR_INT ;
// Si richiede che i vettori siano normalizzati
if ( ! vtVCyl.IsNormalized() || ! vtVLine.IsNormalized())
return CC_ERROR_INT ;
// La retta e l'asse del cilindro sono paralleli
if ( AreSameOrOppositeVectorExact( vtVLine, vtVCyl)) {
double dRadialDist = ( ( ptPLine - ptPCyl) - ( ( ptPLine - ptPCyl) * vtVCyl) * vtVCyl).Len() ;
// La retta appartiene al cilindro
if ( abs( dRadialDist - dCylRad) < EPS_SMALL) {
dU1 = - INFINITO ;
dU2 = INFINITO ;
return CC_INF_INT ;
}
// non vi è intersezione
else
return CC_NO_INTERS ;
}
// Setto i coefficienti dell'equazione
DBLVECTOR vdCoef( 3) ;
vdCoef[0] = ( ptPLine - ptPCyl).SqLen() - ( ( ptPLine - ptPCyl) * vtVCyl) * ( ( ptPLine - ptPCyl) * vtVCyl)
- dCylRad * dCylRad ;
vdCoef[1] = 2 * ( ( ptPLine - ptPCyl) * vtVLine - ( ( ptPLine - ptPCyl) * vtVCyl) * ( vtVCyl * vtVLine) ) ;
vdCoef[2] = 1 - ( vtVCyl * vtVLine) * ( vtVCyl * vtVLine) ;
// Risolvo l'equazione
DBLVECTOR vdRoots ;
int nRoot = PolynomialRoots( 2, vdCoef, vdRoots) ;
// Studio delle soluzioni
int nIntType = CC_NO_INTERS ;
// C'è un punto di tangenza
if ( nRoot == 1) {
dU1 = vdRoots[0] ;
nIntType = CC_ONE_INT_TAN ;
}
// L'equazione ha due soluzioni, bisogna valutare se sono ben distinte.
else if ( nRoot == 2) {
dU1 = vdRoots[0] ;
dU2 = vdRoots[1] ;
if ( dU1 > dU2)
swap( dU1, dU2) ;
// Soluzioni sufficientemente lontane: ci sono due intersezioni
if ( dU2 - dU1 > EPS_SMALL)
nIntType = CC_TWO_INT ;
// Soluzioni non sufficientemente lontane: c'è un punto di tangenza.
else
nIntType = CC_ONE_INT_TAN ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
IntersRayInfiniteCylinder( const Point3d& ptPLine, const Vector3d& vtVLine,
const Point3d& ptPCyl, const Vector3d& vtVCyl, double dCylRad,
double& dU1, double& dU2)
{
int nIntType = IntersLineInfiniteCylinder( ptPLine, vtVLine, ptPCyl, vtVCyl, dCylRad, dU1, dU2) ;
if ( nIntType == CC_ERROR_INT)
return nIntType ;
// Se la retta associata appartiene al
// cilindro, solo il parametro di inizio
// deve essere modificato
if ( nIntType == CC_INF_INT)
dU1 = 0 ;
// La retta associata è tangente: se la tangenza
// ha parametro negativo, la semi-retta non interferisce
else if ( nIntType == CC_ONE_INT_TAN) {
if ( dU1 < - EPS_SMALL)
nIntType = CC_NO_INTERS ;
}
// La retta associata è secante
else if ( nIntType == CC_TWO_INT) {
// Se dU1 è negativo, solo dU2 è accettabile
// assegno dU2 a dU1
if ( dU1 < - EPS_SMALL) {
dU1 = dU2 ;
nIntType = CC_ONE_INT_SEC ;
}
// Se anche dU2 è negativo la
// la semi-retta non interferisce
if ( dU2 < - EPS_SMALL)
nIntType = CC_NO_INTERS ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
IntersSegmentInfiniteCylinder( const Point3d& ptPLine, const Vector3d& vtVLine, double dLen,
const Point3d& ptPCyl, const Vector3d& vtVCyl, double dCylRad,
double& dU1, double& dU2)
{
int nIntType = IntersLineInfiniteCylinder( ptPLine, vtVLine, ptPCyl, vtVCyl, dCylRad, dU1, dU2) ;
if ( nIntType == CC_ERROR_INT)
return nIntType ;
// La retta associata al segmento
// appartiene al cilindro.
if ( nIntType == CC_INF_INT) {
dU1 = 0 ;
dU2 = dLen ;
}
// La retta associata al segmento
// è tangente al cilindro.
else if ( nIntType == CC_ONE_INT_TAN) {
// Sel il parametro è fuori intervallo il
// segmento non interferisce con il cilindro.
if ( dU1 < - EPS_SMALL || dU1 > dLen + EPS_SMALL)
nIntType = CC_NO_INTERS ;
}
// La retta associata al segmento è
// secante al cilindro
else if ( nIntType == CC_TWO_INT) {
// Segmento non interagente
if ( dU1 > dLen + EPS_SMALL)
nIntType = CC_NO_INTERS ;
else if ( dU1 > - EPS_SMALL) {
// Segmento secante in dU1
if ( dU2 > dLen + EPS_SMALL)
nIntType = CC_ONE_INT_SEC ;
}
else {
// Segmento non interagente
if ( dU2 > dLen + EPS_SMALL) {
nIntType = CC_NO_INTERS ;
}
// Segmento secante in dU2
else if ( dU2 > - EPS_SMALL) {
dU1 = dU2 ;
nIntType = CC_ONE_INT_SEC ;
}
// Segmento non interagente
else
nIntType = CC_NO_INTERS ;
}
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
IntersLineSemiFiniteCylinder( const Point3d& ptPLine, const Vector3d& vtVLine,
const Point3d& ptPCyl, const Vector3d& vtVCyl, double dCylRad,
double& dU1, double& dU2)
{
int nIntType = IntersLineInfiniteCylinder( ptPLine, vtVLine, ptPCyl, vtVCyl, dCylRad, dU1, dU2) ;
if ( nIntType == CC_ERROR_INT)
return nIntType ;
// Caso parte della retta appartenente al cilindro
if ( nIntType == CC_INF_INT) {
// Retta e cilindro equiversi
if ( vtVCyl * vtVLine > 0)
dU1 = ( ptPLine - ptPCyl) * vtVCyl ;
// Retta e cilindro controversi
else {
dU1 = - INFINITO ;
dU2 = ( ptPLine - ptPCyl) * vtVCyl ;
}
}
// Caso retta tangente
else if ( nIntType == CC_ONE_INT_TAN) {
// Se il punto di tangenza è fuori dalla parte
// ammissibile del cilindro, rigetto la soluzione
Point3d ptInt = ptPLine + dU1 * vtVLine ;
if ( ( ptInt - ptPCyl) * vtVCyl < 0)
nIntType = CC_NO_INTERS ;
}
// Caso di due intersezioni
else if ( nIntType == CC_TWO_INT) {
// Rigetto le soluzioni fuori dalla
// regione ammissibile del cilindro.
Point3d ptInt1 = ptPLine + dU1 * vtVLine ;
Point3d ptInt2 = ptPLine + dU2 * vtVLine ;
int nSolNum = 2 ;
if ( ( ptInt1 - ptPCyl) * vtVCyl < 0) {
-- nSolNum ;
dU1 = dU2 ;
}
if ( ( ptInt2 - ptPCyl) * vtVCyl < 0)
-- nSolNum ;
// Dal numero di soluzioni rimaste
// aggiorno la tipologia di interferenza.
if ( nSolNum == 1)
nIntType = CC_ONE_INT_SEC ;
else if ( nSolNum == 0)
nIntType = CC_NO_INTERS ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
RaySemiFiniteCylinder( const Point3d& ptPLine, const Vector3d& vtVLine,
const Point3d& ptPCyl, const Vector3d& vtVCyl, double dCylRad,
double& dU1, double& dU2)
{
int nIntType = IntersLineSemiFiniteCylinder( ptPLine, vtVLine, ptPCyl, vtVCyl, dCylRad, dU1, dU2) ;
if ( nIntType == CC_ERROR_INT)
return nIntType ;
// Parte della semi-retta appartiene al cilindro
if ( nIntType == CC_INF_INT) {
// La semi-retta non interferisce
if ( dU2 < - EPS_SMALL)
nIntType = CC_NO_INTERS ;
// La semi-retta incomincia nel cilindro
else if ( dU1 < - EPS_SMALL)
dU1 = 0 ;
}
// La retta associata è tangente
// o secante in un punto.
else if ( nIntType == CC_ONE_INT_SEC ||
nIntType == CC_ONE_INT_TAN) {
// Se il parametro è negativo,
// scarto la soluzione.
if ( dU1 < - EPS_SMALL)
nIntType = CC_NO_INTERS ;
}
// Retta associata secante
else if ( nIntType == CC_TWO_INT) {
int nSolNum = 2 ;
if ( dU1 < - EPS_SMALL) {
dU1 = dU2 ;
-- nSolNum ;
}
if ( dU2 < - EPS_SMALL)
-- nSolNum ;
// Dal numero di soluzioni rimaste
// aggiorno la tipologia di interferenza.
if ( nSolNum == 1)
nIntType = CC_ONE_INT_SEC ;
else if ( nSolNum == 0)
nIntType = CC_NO_INTERS ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
SegmentSemiFiniteCylinder( const Point3d& ptPLine, const Vector3d& vtVLine, double dLen,
const Point3d& ptPCyl, const Vector3d& vtVCyl, double dCylRad,
double& dU1, double& dU2)
{
int nIntType = IntersLineSemiFiniteCylinder( ptPLine, vtVLine, ptPCyl, vtVCyl, dCylRad, dU1, dU2) ;
if ( nIntType == CC_ERROR_INT)
return nIntType ;
// Parte della retta associata
// appartiene al cilindro.
if ( nIntType == CC_INF_INT) {
// Il segmento non interferisce
if ( dU1 > dLen + EPS_SMALL)
nIntType = CC_NO_INTERS ;
else if ( dU1 > - EPS_SMALL) {
// Il segmento termina nel cilindro
if ( dU2 > dLen + EPS_SMALL)
dU2 = dLen ;
}
else {
// Il segmento contenuto totalmente
if ( dU2 > dLen + EPS_SMALL) {
dU1 = 0 ;
dU2 = dLen ;
}
// Il segmento comincia nel cilindro
else if ( dU2 > - EPS_SMALL)
dU1 = 0 ;
// Il segmeno non interferisce
else
nIntType = CC_NO_INTERS ;
}
}
// La retta associata è tangente
// o secante in un punto.
else if ( nIntType == CC_ONE_INT_SEC ||
nIntType == CC_ONE_INT_TAN) {
// Il sgmento non interferisce
if ( dU1 < 0 || dU1 > dLen)
nIntType = CC_NO_INTERS ;
}
// La retta associata è secante
else if ( nIntType == CC_TWO_INT) {
// Il segmento non interferisce
if ( dU1 > dLen + EPS_SMALL)
nIntType = CC_NO_INTERS ;
else if ( dU1 > - EPS_SMALL) {
// Segmento secante in dU1
if ( dU2 > dLen + EPS_SMALL)
nIntType = CC_ONE_INT_SEC ;
}
else {
// Il segmento non interagisce
if ( dU2 > dLen + EPS_SMALL) {
nIntType = CC_NO_INTERS ;
}
// Il segmento è secante in dU2,
// assegno dU2 a dU1.
else if ( dU2 > - EPS_SMALL) {
dU1 = dU2 ;
nIntType = CC_ONE_INT_SEC ;
}
// Il segmento non interferisce
else
nIntType = CC_NO_INTERS ;
}
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
IntersLineCylinder( const Point3d& ptPLine, const Vector3d& vtVLine,
const Point3d& ptPCyl, const Vector3d& vtVCyl, double dCylRad, double dCylHeigth,
double& dU1, double& dU2)
{
int nIntType = IntersLineInfiniteCylinder( ptPLine, vtVLine, ptPCyl, vtVCyl, dCylRad, dU1, dU2) ;
if ( nIntType == CC_ERROR_INT)
return nIntType ;
// Parte della retta appartenente al cilindro
if ( nIntType == CC_INF_INT) {
dU1 = ( ptPCyl - ptPLine) * vtVLine ;
// Retta e cilindro equiversi
if ( vtVCyl * vtVLine > 0)
dU2 = dU1 + dCylHeigth ;
// Retta e cilindro controversi
else
dU2 = dU1 - dCylHeigth ;
}
// Caso di un punto di tangenza
else if ( nIntType == CC_ONE_INT_TAN) {
// Se il punto di tangenza è fuori dalla parte
// ammissibile del cilindro, rigetto la soluzione
Point3d ptInt = ptPLine + dU1 * vtVLine ;
if ( ( ptInt - ptPCyl) * vtVCyl < 0 ||
( ptInt - ptPCyl) * vtVCyl > dCylHeigth)
nIntType = CC_NO_INTERS ;
}
// Caso di due intersezioni
else if ( nIntType == CC_TWO_INT) {
// Elimino le soluzioni fuori dal cilindro finito
Point3d ptInt1 = ptPLine + dU1 * vtVLine ;
Point3d ptInt2 = ptPLine + dU2 * vtVLine ;
int nSolNum = 2 ;
if ( ( ptInt1 - ptPCyl) * vtVCyl < 0 ||
( ptInt1 - ptPCyl) * vtVCyl > dCylHeigth) {
-- nSolNum ;
dU1 = dU2 ;
}
if ( ( ptInt2 - ptPCyl) * vtVCyl < 0 ||
( ptInt2 - ptPCyl) * vtVCyl > dCylHeigth)
-- nSolNum ;
// Aggiorno il tipo di intersezione
if ( nSolNum == 1)
nIntType = CC_ONE_INT_SEC ;
else if ( nSolNum == 0)
nIntType = CC_NO_INTERS ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
RayCylinder( const Point3d& ptPLine, const Vector3d& vtVLine,
const Point3d& ptPCyl, const Vector3d& vtVCyl, double dCylRad, double dCylHeigth,
double& dU1, double& dU2)
{
int nIntType = IntersLineCylinder( ptPLine, vtVLine, ptPCyl, vtVCyl, dCylRad, dCylHeigth, dU1, dU2) ;
if ( nIntType == CC_ERROR_INT)
return nIntType ;
// Parte della retta associata
// appartiene al cilindro
if ( nIntType == CC_INF_INT) {
// Semi-retta non interferisce
if ( dU2 < - EPS_SMALL)
nIntType = CC_NO_INTERS ;
// La semi-retta comincia nel cilindro
else if ( dU1 < - EPS_SMALL)
dU1 = 0 ;
}
// Retta associata tangente
else if ( nIntType == CC_ONE_INT_TAN) {
if ( dU1 < - EPS_SMALL)
nIntType = CC_NO_INTERS ;
}
else if ( nIntType == CC_TWO_INT) {
// Scarto soluzioni con parametro negativo
int nSolNum = 2 ;
if ( dU1 < - EPS_SMALL) {
dU1 = dU2 ;
-- nSolNum ;
}
if ( dU2 < - EPS_SMALL)
-- nSolNum ;
// Dal numero di soluzioni rimaste
// aggiorno la tipologia di interferenza.
if ( nSolNum == 1)
nIntType = CC_ONE_INT_SEC ;
else if ( nSolNum == 0)
nIntType = CC_NO_INTERS ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
IntersSegmentCylinder( const Point3d& ptPLine, const Vector3d& vtVLine, double dLen,
const Point3d& ptPCyl, const Vector3d& vtVCyl, double dCylRad, double dCylHeigth,
double& dU1, double& dU2)
{
int nIntType = IntersLineCylinder( ptPLine, vtVLine, ptPCyl, vtVCyl, dCylRad, dCylHeigth, dU1, dU2) ;
if ( nIntType == CC_ERROR_INT)
return nIntType ;
// Parte della retta associata appartiene al cilindro
if ( nIntType == CC_INF_INT) {
// Segmento non interferisce
if ( dU1 > dLen + EPS_SMALL)
nIntType = CC_NO_INTERS ;
else if ( dU1 > - EPS_SMALL) {
if ( dU2 > dLen + EPS_SMALL)
dU2 = dLen ;
}
else {
// Segmento non interferisce
if ( dU2 < - EPS_SMALL)
nIntType = CC_NO_INTERS ;
// Il segmento comincia nel cilindro
else {
dU1 = 0 ;
// Il segmento termina nel cilindro
if ( dU2 > dLen + EPS_SMALL)
dU2 = dLen ;
}
}
}
// La retta associata è tangente al cilindro
else if ( nIntType == CC_ONE_INT_TAN) {
// Segmento non interferisce
if ( dU1 < - EPS_SMALL || dU1 > dLen + EPS_SMALL)
nIntType = CC_NO_INTERS ;
}
// Retta associata è secante con due punti di intersezione
else if ( nIntType == CC_TWO_INT) {
// Il segmento non interferisce
if ( dU1 > dLen + EPS_SMALL)
nIntType = CC_NO_INTERS ;
else if ( dU1 > - EPS_SMALL) {
// Segmento secante in dU1
if ( dU2 > dLen + EPS_SMALL)
nIntType = CC_ONE_INT_SEC ;
}
else {
// Il segmento non interagisce
if ( dU2 > dLen + EPS_SMALL) {
nIntType = CC_NO_INTERS ;
}
// Il segmento è secante in dU2,
// assegno dU2 a dU1.
else if ( dU2 > - EPS_SMALL) {
dU1 = dU2 ;
nIntType = CC_ONE_INT_SEC ;
}
// Il segmento non interferisce
else
nIntType = CC_NO_INTERS ;
}
}
// Retta associata è secante con un punto di intersezione
else if ( nIntType == CC_ONE_INT_SEC) {
if ( dU1 < -EPS_SMALL || dU1 > dLen + EPS_SMALL)
nIntType = CC_NO_INTERS ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
LineInfiniteCone( const Point3d& ptPLine, const Vector3d& vtDLine,
const Point3d& ptVCone, const Vector3d& vtDCone, double dConeRad, double dConeHeigth,
double& dU1, double& dU2)
{
// Raggio e altezza del cono devono essere maggiori di zero
if ( dConeRad < EPS_SMALL || dConeHeigth < EPS_SMALL)
return CC_ERROR_INT ;
// Si richiede che i vettori siano normalizzati
if ( ! vtDCone.IsNormalized() || ! vtDLine.IsNormalized())
return CC_ERROR_INT ;
// Tangente dell'angolo semi-apertura del cono
double dTanTheta = dConeRad / dConeHeigth ;
// Lunghezze delle componenti parallela e ortogonale del
// vettore della retta rispetto all'asse del cilindro.
double dDLong = vtDLine * vtDCone ;
double dDOrt = (vtDLine - dDLong * vtDCone).Len() ;
// Flag parallelismo fra la retta e una retta generatrice del cono.
bool bSameAngle = abs( dDLong) > EPS_ZERO && abs( dDOrt / abs( dDLong) - dTanTheta) < EPS_ZERO ;
if ( bSameAngle) {
// Valuto se parte della retta appartiene al cono.
Vector3d vtOO = ptVCone - ptPLine ;
Vector3d vtOOPerp = vtOO - ( vtOO * vtDLine) * vtDLine ;
// Caso in cui la retta appartiene al cono
if ( vtOOPerp.SqLen() < EPS_SMALL * EPS_SMALL) {
// Calcolo il parametro a cui si trova il
// vertice del cono lungo la retta.
if ( vtDLine * vtDCone > 0) {
dU1 = vtOO * vtDLine ;
dU2 = INFINITO ;
}
else {
dU1 = - INFINITO ;
dU2 = vtOO * vtDLine ;
}
return CC_INF_INT ;
}
// Vertice del cono non sta sulla retta
else {
double dC0 = ( ptPLine - ptVCone) * ( ptPLine - ptVCone) -
( 1 + dTanTheta * dTanTheta) * ( ( ptPLine - ptVCone) * vtDCone) * ( ( ptPLine - ptVCone) * vtDCone) ;
double dC1 = 2 * ( vtDLine * ( ptPLine - ptVCone) -
( 1 + dTanTheta * dTanTheta) * ( vtDCone * vtDLine) * ( ptPLine - ptVCone) * vtDCone) ;
if ( abs( dC1) > EPS_ZERO) {
dU1 = - dC0 / dC1 ;
Point3d ptInt = ptPLine + dU1 * vtDLine ;
// Se la soluzione è sulla falda negativa deve essere eliminata.
if ( ( ptInt - ptVCone) * vtDCone < 0)
return CC_NO_INTERS ;
return CC_ONE_INT_SEC ;
}
else if ( abs( dC0) > EPS_SMALL)
return CC_NO_INTERS ;
}
}
// Setto i coefficienti dell'equazione
DBLVECTOR vdCoef( 3) ;
double dDiffDiff = ( ptPLine - ptVCone) * ( ptPLine - ptVCone) ;
double dDiffDC = ( ptPLine - ptVCone) * vtDCone ;
double dDiffDL = ( ptPLine - ptVCone) * vtDLine ;
double dDCDL = vtDCone * vtDLine ;
double dInvSqCosTheta = 1 + dTanTheta * dTanTheta ;
vdCoef[0] = dDiffDiff - dInvSqCosTheta * dDiffDC * dDiffDC ;
vdCoef[1] = 2 * ( dDiffDL - dInvSqCosTheta * dDCDL * dDiffDC) ;
vdCoef[2] = 1 - dInvSqCosTheta * dDCDL * dDCDL ;
// Risolvo l'equazione
DBLVECTOR vdRoots ;
int nRoot = PolynomialRoots( 2, vdCoef, vdRoots) ;
// Studio le soluzioni
int nIntType = CC_NO_INTERS ;
if ( nRoot == 1) {
dU1 = vdRoots[0] ;
Point3d ptInt = ptPLine + dU1 * vtDLine ;
// Soluzione sul cono negativo
if ( ( ptInt - ptVCone) * vtDCone < 0)
nIntType = CC_NO_INTERS ;
// Soluzione sul vertice
else if ( SqDist( ptInt, ptVCone) < EPS_SMALL * EPS_SMALL)
nIntType = CC_ON_VERT ;
// Retta parallela e secante in un punto
else if ( bSameAngle)
nIntType = CC_ONE_INT_SEC ;
// Retta tangente al cono
else
nIntType = CC_ONE_INT_TAN ;
}
else if ( nRoot == 2) {
dU1 = vdRoots[0] ;
dU2 = vdRoots[1] ;
if ( dU1 > dU2)
swap( dU1, dU2) ;
// Se le soluzioni non sono sufficientemente lontane,
// la soluzione è di tangenza
if ( dU2 - dU1 < EPS_SMALL * EPS_SMALL) {
Point3d ptInt1 = ptPLine + dU1 * vtDLine ;
// Soluzione sul cono negativo
if ( ( ptInt1 - ptVCone) * vtDCone < 0)
nIntType = CC_NO_INTERS ;
// Soluzione sul vertice
else if ( SqDist( ptInt1, ptVCone) < EPS_SMALL * EPS_SMALL)
nIntType = CC_ON_VERT ;
// Retta parallela e secante in un punto
else if ( bSameAngle)
nIntType = CC_ONE_INT_SEC ;
// Retta tangente al cono
else
nIntType = CC_ONE_INT_TAN ;
}
// Soluzioni ben distinte
else {
Point3d ptInt1 = ptPLine + dU1 * vtDLine ;
Point3d ptInt2 = ptPLine + dU2 * vtDLine ;
// Elimino le soluzioni sul cono negativo
int nNumSol = 2 ;
if ( ( ptInt2 - ptVCone) * vtDCone < 0)
-- nNumSol ;
if ( ( ptInt1 - ptVCone) * vtDCone < 0) {
-- nNumSol ;
dU1 = dU2 ;
}
// Dal numero di soluzioni rimaste
// aggiorno la tipologia di interferenza.
if ( nNumSol == 0)
nIntType = CC_NO_INTERS ;
else if ( nNumSol == 1)
nIntType = CC_ONE_INT_SEC ;
else if ( nNumSol == 2)
nIntType = CC_TWO_INT ;
}
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
RayInfiniteCone( const Point3d& ptPLine, const Vector3d& vtDLine,
const Point3d& ptVCone, const Vector3d& vtDCone, double dConeRad, double dConeHeigth,
double& dU1, double& dU2)
{
int nIntType = LineInfiniteCone( ptPLine, vtDLine, ptVCone, vtDCone, dConeRad, dConeHeigth, dU1, dU2) ;
if ( nIntType == CC_ERROR_INT)
return nIntType ;
// Parte della retta associata
// appartiene al cono.
if ( nIntType == CC_INF_INT) {
if ( vtDLine * vtDCone > 0) {
// Semi-retta comincia nel cono
if ( dU1 < 0)
dU1 = 0 ;
}
else {
// Semiretta non interferisce
// con il cono.
if ( dU2 < 0)
nIntType = CC_NO_INTERS ;
// Semi-retta comincia nel cono
else
dU1 = 0 ;
}
}
// Retta associata interferisce in un punto
else if ( nIntType == CC_ONE_INT_TAN ||
nIntType == CC_ONE_INT_SEC ||
nIntType == CC_ON_VERT) {
// Semi-retta non interferisce
if ( dU1 < - EPS_SMALL)
nIntType = CC_NO_INTERS ;
}
// Retta associata interferisce in due punti.
else if ( nIntType == CC_TWO_INT) {
// Semi-retta non interferisce
if ( dU2 < - EPS_SMALL)
nIntType = CC_NO_INTERS ;
// Semi-retta secante in un punto
else if ( dU1 < - EPS_SMALL)
nIntType = CC_ONE_INT_SEC ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
SegmentInfiniteCone( const Point3d& ptPLine, const Vector3d& vtDLine, double dSgLen,
const Point3d& ptVCone, const Vector3d& vtDCone, double dConeRad, double dConeHeigth,
double& dU1, double& dU2)
{
int nIntType = LineInfiniteCone( ptPLine, vtDLine, ptVCone, vtDCone, dConeRad, dConeHeigth, dU1, dU2) ;
if ( nIntType == CC_ERROR_INT)
return nIntType ;
// Parte della retta associata
// appartiene al cono
if ( nIntType == CC_INF_INT) {
// Il segmento non interferisce
if ( dU1 > dSgLen + EPS_SMALL)
nIntType = CC_NO_INTERS ;
else if ( dU1 > - EPS_SMALL) {
// Il segmento termina nel cono
if ( dU2 > dSgLen + EPS_SMALL)
dU2 = dSgLen ;
}
else {
// Il segmento contenuto totalmente
if ( dU2 > dSgLen + EPS_SMALL) {
dU1 = 0 ;
dU2 = dSgLen ;
}
// Il segmento comincia nel cono
else if ( dU2 > - EPS_SMALL)
dU1 = 0 ;
// Il segmeno non interferisce
else
nIntType = CC_NO_INTERS ;
}
}
// Retta associata interferisce in un punto
else if ( nIntType == CC_ONE_INT_TAN ||
nIntType == CC_ONE_INT_SEC ||
nIntType == CC_ON_VERT) {
// Segmento non interagente
if ( dU1 < - EPS_SMALL || dU1 > dSgLen + EPS_SMALL)
nIntType = CC_NO_INTERS ;
}
// Retta associata interferisce in due punti.
else if ( nIntType == CC_TWO_INT) {
// Il segmento non interferisce
if ( dU1 > dSgLen + EPS_SMALL)
nIntType = CC_NO_INTERS ;
else if ( dU1 > - EPS_SMALL) {
// Segmento secante in dU1
if ( dU2 > dSgLen + EPS_SMALL)
nIntType = CC_ONE_INT_SEC ;
}
else {
// Il segmento non interagisce
if ( dU2 > dSgLen + EPS_SMALL) {
nIntType = CC_NO_INTERS ;
}
// Il segmento è secante in dU2,
// assegno dU2 a dU1.
else if ( dU2 > - EPS_SMALL) {
dU1 = dU2 ;
nIntType = CC_ONE_INT_SEC ;
}
// Il segmento non interferisce
else
nIntType = CC_NO_INTERS ;
}
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
LineCone( const Point3d& ptPLine, const Vector3d& vtDLine,
const Point3d& ptVCone, const Vector3d& vtDCone, double dConeRad, double dConeHeigth,
double& dU1, double& dU2)
{
int nIntType = LineInfiniteCone( ptPLine, vtDLine, ptVCone, vtDCone, dConeRad, dConeHeigth, dU1, dU2) ;
if ( nIntType == CC_ERROR_INT)
return nIntType ;
// Tangente dell'angolo semi-apertura del cono
double dTanTheta = dConeRad / dConeHeigth ;
// Parte della retta associata giace sul cono
if ( nIntType == CC_INF_INT) {
double dApothem = dConeHeigth * sqrt( 1 + dTanTheta * dTanTheta) ;
// Retta e asse del cono equiversi
if ( vtDLine * vtDCone > 0)
dU2 = dU1 + dApothem ;
// Retta e asse del cono controversi
else
dU1 = dU2 - dApothem ;
}
// Retta e il cono infinito interagiscono in un punto
else if ( nIntType == CC_ONE_INT_TAN ||
nIntType == CC_ONE_INT_SEC ||
nIntType == CC_ON_VERT) {
// Se la soluzione è fuori dal cono la rigetto
Point3d ptInt = ptPLine + dU1 * vtDLine ;
if ( ( ptInt - ptVCone) * vtDCone > dConeHeigth)
nIntType = CC_NO_INTERS ; ;
}
// Retta e il cono infinito interagiscono in due punti
else if ( nIntType == CC_TWO_INT) {
// Rigetto le soluzioni fuori dal cono
Point3d ptInt1 = ptPLine + dU1 * vtDLine ;
Point3d ptInt2 = ptPLine + dU2 * vtDLine ;
int nNumSol = 2 ;
if ( ( ptInt2 - ptVCone) * vtDCone > dConeHeigth)
-- nNumSol ;
if ( ( ptInt1 - ptVCone) * vtDCone > dConeHeigth) {
-- nNumSol ;
dU1 = dU2 ;
}
// Dal numero di soluzioni rimaste
// aggiorno la tipologia di interferenza.
if ( nNumSol == 0)
nIntType = CC_NO_INTERS ;
else if ( nNumSol == 1)
nIntType = CC_ONE_INT_SEC ;
else if ( nNumSol == 2)
nIntType = CC_TWO_INT ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
RayCone( const Point3d& ptPLine, const Vector3d& vtDLine,
const Point3d& ptVCone, const Vector3d& vtDCone, double dConeRad, double dConeHeigth,
double& dU1, double& dU2)
{
int nIntType = LineCone( ptPLine, vtDLine, ptVCone, vtDCone, dConeRad, dConeHeigth, dU1, dU2) ;
if ( nIntType == CC_ERROR_INT)
return nIntType ;
// Parte della retta associata
// giace sul cono
if ( nIntType == CC_INF_INT) {
double dApothem = sqrt( dConeRad * dConeRad + dConeHeigth * dConeHeigth) ;
// Semi-retta esterna
if ( dU2 < - EPS_SMALL)
nIntType = CC_NO_INTERS ;
// Una soluzione tangente
else if ( dU2 < EPS_SMALL) {
dU1 = 0 ;
nIntType = CC_ONE_INT_TAN ;
}
// Semi-retta comincia nel cono
else if ( dU2 < dApothem)
dU1 = 0 ;
}
// Retta associata interagisce in un punto
else if ( nIntType == CC_ONE_INT_TAN ||
nIntType == CC_ONE_INT_SEC ||
nIntType == CC_ON_VERT) {
// Semi-retta esterna
if ( dU1 < - EPS_SMALL)
nIntType = CC_NO_INTERS ;
}
// Retta associata interagisce in due punti
else if ( nIntType == CC_TWO_INT) {
// Se dU1 è negativo, solo dU2 è accettabile
// assegno dU2 a dU1
if ( dU1 < - EPS_SMALL) {
dU1 = dU2 ;
nIntType = CC_ONE_INT_SEC ;
}
// Se anche dU2 è negativo la
// la semi-retta non interferisce
if ( dU2 < - EPS_SMALL)
nIntType = CC_NO_INTERS ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
SegmentCone( const Point3d& ptPLine, const Vector3d& vtDLine, double dSgLen,
const Point3d& ptVCone, const Vector3d& vtDCone, double dConeRad, double dConeHeigth,
double& dU1, double& dU2)
{
// Verifico se il segmento interseca un insieme di box impilati che includono il cono
Frame3d frCone ; frCone.Set( ptVCone, vtDCone) ;
Point3d ptLineL = ptPLine ; ptLineL.ToLoc( frCone) ;
Vector3d vtLineL = vtDLine ; vtLineL.ToLoc( frCone) ;
const int N_SLABS = 4 ;
double dH = dConeHeigth / N_SLABS ;
double dR = dConeRad / N_SLABS ;
int nMiss = 0 ;
for ( int i = 1 ; i <= N_SLABS ; ++ i) {
double dPar1, dPar2 ;
ptLineL.z -= ( i - 1) * dH ;
double dCurrR = i * dR ;
if ( ! IntersLineBox( ptLineL, vtLineL, Point3d( -dCurrR, -dCurrR, 0), Point3d( dCurrR, dCurrR, dH), dPar1, dPar2) ||
dPar2 < -EPS_SMALL || dPar1 > dSgLen + EPS_SMALL)
++ nMiss ;
}
if ( nMiss == N_SLABS)
return CC_NO_INTERS ;
// Calcolo l'intersezione con la linea illimitata
int nIntType = LineCone( ptPLine, vtDLine, ptVCone, vtDCone, dConeRad, dConeHeigth, dU1, dU2) ;
if ( nIntType == CC_ERROR_INT)
return nIntType ;
if ( nIntType == CC_INF_INT) {
// Segmento non interferisce
if ( dU1 > dSgLen + EPS_SMALL)
nIntType = CC_NO_INTERS ;
else if ( dU1 > - EPS_SMALL) {
if ( dU2 > dSgLen + EPS_SMALL)
dU2 = dSgLen ;
}
else {
// Segmento non interferisce
if ( dU2 < - EPS_SMALL)
nIntType = CC_NO_INTERS ;
// Il segmento comincia nel cono
else {
dU1 = 0 ;
// Il segmento termina nel cono
if ( dU2 > dSgLen + EPS_SMALL)
dU2 = dSgLen ;
}
}
}
// Retta associata interagisce in un punto
else if ( nIntType == CC_ONE_INT_TAN ||
nIntType == CC_ONE_INT_SEC ||
nIntType == CC_ON_VERT) {
// Segmento non interferisce
if ( dU1 < - EPS_SMALL || dU1 > dSgLen + EPS_SMALL)
nIntType = CC_NO_INTERS ;
}
// Retta associata interagisce in due punti
else if ( nIntType == CC_TWO_INT) {
// Il segmento non interferisce
if ( dU1 > dSgLen + EPS_SMALL)
nIntType = CC_NO_INTERS ;
else if ( dU1 > - EPS_SMALL) {
// Segmento secante in dU1
if ( dU2 > dSgLen + EPS_SMALL)
nIntType = CC_ONE_INT_SEC ;
}
else {
// Il segmento non interagisce
if ( dU2 > dSgLen + EPS_SMALL) {
nIntType = CC_NO_INTERS ;
}
// Il segmento è secante in dU2,
// assegno dU2 a dU1.
else if ( dU2 > - EPS_SMALL) {
dU1 = dU2 ;
nIntType = CC_ONE_INT_SEC ;
}
// Il segmento non interferisce
else
nIntType = CC_NO_INTERS ;
}
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
LineConeFrustum( const Point3d& ptPLine, const Vector3d& vtDLine,
const Point3d& ptMinBase, const Vector3d& vtDCone, double dMinRad, double dMaxRad, double dHeigth,
double& dU1, double& dU2)
{
// Controlli sull'ammissibilità del tronco di cono
if ( ! ( dMinRad > EPS_SMALL && dMaxRad > EPS_SMALL && dHeigth > EPS_SMALL))
return CC_ERROR_INT ;
double dDeltaH = dMinRad * dHeigth / ( dMaxRad - dMinRad) ;
Point3d ptVCone = ptMinBase - dDeltaH * vtDCone ;
int nIntType = LineInfiniteCone( ptPLine, vtDLine, ptVCone, vtDCone, dMinRad, dDeltaH, dU1, dU2) ;
if ( nIntType == CC_ERROR_INT)
return nIntType ;
// Parte della retta associata giace sul cono
if ( nIntType == CC_INF_INT) {
double dMinApo = sqrt( dDeltaH * dDeltaH + dMinRad * dMinRad) ;
double dMaxApo = sqrt( ( dDeltaH + dHeigth) * ( dDeltaH + dHeigth) + dMaxRad * dMaxRad) ;
// Retta e vettore cono equiversi
if ( vtDLine * vtDCone > 0) {
double dSignedLenOO = ( ptPLine - ptVCone) * vtDLine ;
dU1 = dMinApo - dSignedLenOO ;
dU2 = dMaxApo - dSignedLenOO ;
}
// Retta e vettore cono controversi
else {
double dSignedLenOO = ( ptPLine - ptVCone) * vtDLine ;
dU1 = - dMaxApo - dSignedLenOO ;
dU2 = - dMinApo - dSignedLenOO ;
}
}
// Retta associata interagisce in un punto
else if ( nIntType == CC_ONE_INT_TAN ||
nIntType == CC_ONE_INT_SEC ||
nIntType == CC_ON_VERT) {
Point3d ptInt = ptPLine + dU1 * vtDLine ;
if ( ( ptInt - ptVCone) * vtDCone < dDeltaH - EPS_SMALL ||
( ptInt - ptVCone) * vtDCone > dDeltaH + dHeigth + EPS_SMALL)
nIntType = CC_NO_INTERS ;
}
// Retta associata interagisce in due punti
else if ( nIntType == CC_TWO_INT) {
// Elimino le soluzioni da fuori dal tronco
Point3d ptInt1 = ptPLine + dU1 * vtDLine ;
Point3d ptInt2 = ptPLine + dU2 * vtDLine ;
int nNumSol = 2 ;
if ( ( ptInt2 - ptVCone) * vtDCone < dDeltaH ||
( ptInt2 - ptVCone) * vtDCone > dDeltaH + dHeigth)
-- nNumSol ;
if ( ( ptInt1 - ptVCone) * vtDCone < dDeltaH ||
( ptInt1 - ptVCone) * vtDCone > dDeltaH + dHeigth) {
-- nNumSol ;
dU1 = dU2 ;
}
// Dal numero di soluzioni rimaste
// aggiorno la tipologia di interferenza.
if ( nNumSol == 0)
nIntType = CC_NO_INTERS ;
else if ( nNumSol == 1)
nIntType = CC_ONE_INT_SEC ;
else if ( nNumSol == 2)
nIntType = CC_TWO_INT ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
RayConeFrustum( const Point3d& ptPLine, const Vector3d& vtDLine,
const Point3d& ptMinBase, const Vector3d& vtDCone, double dMinRad, double dMaxRad, double dHeigth,
double& dU1, double& dU2)
{
int nIntType = LineConeFrustum( ptPLine, vtDLine, ptMinBase, vtDCone, dMinRad, dMaxRad, dHeigth, dU1, dU2) ;
if ( nIntType == CC_ERROR_INT)
return nIntType ;
// Parte della retta associata giace sul tronco di cono
if ( nIntType == CC_INF_INT) {
double dDeltaH = dMinRad * dHeigth / ( dMaxRad - dMinRad) ;
double dMinApo = sqrt( dDeltaH * dDeltaH + dMinRad * dMinRad) ;
double dMaxApo = sqrt( ( dDeltaH + dHeigth) * ( dDeltaH + dHeigth) + dMaxRad * dMaxRad) ;
// Semi-retta non interagisce
if ( dU2 < - EPS_SMALL)
nIntType = CC_NO_INTERS ;
// Semi-retta parte sul bordo del tronco
else if ( dU2 < EPS_SMALL) {
dU1 = 0 ;
nIntType = CC_ONE_INT_TAN ;
}
// Semi-retta comincia nel tronco
else if ( dU2 < dMaxApo - dMinApo)
dU1 = 0 ;
}
// Retta associata interagisce in un punto
else if ( nIntType == CC_ONE_INT_TAN ||
nIntType == CC_ONE_INT_SEC ||
nIntType == CC_ON_VERT) {
// Semi-retta non interagisce
if ( dU1 < - EPS_SMALL)
nIntType = CC_NO_INTERS ;
}
// Retta associata interagisce in un punto
else if ( nIntType == CC_TWO_INT) {
// Se dU1 è negativo, solo dU2 è accettabile
// assegno dU2 a dU1
if ( dU1 < - EPS_SMALL) {
dU1 = dU2 ;
nIntType = CC_ONE_INT_SEC ;
}
// Se anche dU2 è negativo la
// la semi-retta non interferisce
if ( dU2 < - EPS_SMALL)
nIntType = CC_NO_INTERS ;
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
SegmentConeFrustum( const Point3d& ptPLine, const Vector3d& vtDLine, double dSgLen,
const Point3d& ptMinBase, const Vector3d& vtDCone, double dMinRad, double dMaxRad, double dHeigth,
double& dU1, double& dU2)
{
// Verifico se il segmento interseca un insieme di box impilati che includono il tronco cono
Frame3d frCone ; frCone.Set( ptMinBase, vtDCone) ;
Point3d ptLineL = ptPLine ; ptLineL.ToLoc( frCone) ;
Vector3d vtLineL = vtDLine ; vtLineL.ToLoc( frCone) ;
const int N_SLABS = 4 ;
double dH = dHeigth / N_SLABS ;
double dR = ( dMaxRad - dMinRad) / N_SLABS ;
int nMiss = 0 ;
for ( int i = 1 ; i <= N_SLABS ; ++ i) {
double dPar1, dPar2 ;
ptLineL.z -= ( i - 1) * dH ;
double dCurrR = dMinRad + i * dR ;
if ( ! IntersLineBox( ptLineL, vtLineL, Point3d( -dCurrR, -dCurrR, 0), Point3d( dCurrR, dCurrR, dH), dPar1, dPar2) ||
dPar2 < -EPS_SMALL || dPar1 > dSgLen + EPS_SMALL)
++ nMiss ;
}
if ( nMiss == N_SLABS)
return CC_NO_INTERS ;
// Calcolo l'intersezione con la linea illimitata
int nIntType = LineConeFrustum( ptPLine, vtDLine, ptMinBase, vtDCone, dMinRad, dMaxRad, dHeigth, dU1, dU2) ;
if ( nIntType == CC_ERROR_INT)
return nIntType ;
// Parte della retta associata giace sul tronco
if ( nIntType == CC_INF_INT) {
// Segmento non interferisce
if ( dU1 > dSgLen + EPS_SMALL)
nIntType = CC_NO_INTERS ;
else if ( dU1 > - EPS_SMALL) {
if ( dU2 > dSgLen + EPS_SMALL)
dU2 = dSgLen ;
}
else {
// Segmento non interferisce
if ( dU2 < - EPS_SMALL)
nIntType = CC_NO_INTERS ;
// Il segmento comincia nel cilindro
else {
dU1 = 0 ;
// Il segmento termina nel cilindro
if ( dU2 > dSgLen + EPS_SMALL)
dU2 = dSgLen ;
}
}
}
// Retta associata interagisce in un punto
else if ( nIntType == CC_ONE_INT_TAN ||
nIntType == CC_ONE_INT_SEC ||
nIntType == CC_ON_VERT) {
// Segmento non interferisce
if ( dU1 < - EPS_SMALL || dU1 > dSgLen + EPS_SMALL)
nIntType = CC_NO_INTERS ;
}
// Retta associata interagisce in due punti
else if ( nIntType == CC_TWO_INT) {
// Il segmento non interferisce
if ( dU1 > dSgLen + EPS_SMALL)
nIntType = CC_NO_INTERS ;
else if ( dU1 > - EPS_SMALL) {
// Segmento secante in dU1
if ( dU2 > dSgLen + EPS_SMALL)
nIntType = CC_ONE_INT_SEC ;
}
else {
// Il segmento non interagisce
if ( dU2 > dSgLen + EPS_SMALL) {
nIntType = CC_NO_INTERS ;
}
// Il segmento è secante in dU2,
// assegno dU2 a dU1.
else if ( dU2 > - EPS_SMALL) {
dU1 = dU2 ;
nIntType = CC_ONE_INT_SEC ;
}
// Il segmento non interferisce
else
nIntType = CC_NO_INTERS ;
}
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
LineTorus( const Point3d& ptLine, const Vector3d& vtLine,
const Point3d& ptOTorus, const Vector3d& vtAxTorus, double dMinRad, double dMaxRad,
BOOLVECTOR& vbType, DBLVECTOR& vdPar)
{
// I Raggi devono essere positiv
if ( dMinRad < EPS_SMALL || dMaxRad < EPS_SMALL)
return T_ERROR ;
// Si richiede che i vettori siano normalizzati
if ( ! vtAxTorus.IsNormalized() || ! vtLine.IsNormalized())
return T_ERROR ;
// Sistema di riferimento del toro
Frame3d frTorusFrame ;
frTorusFrame.Set( ptOTorus, vtAxTorus) ;
// Porto la retta nel sistema di riferimento del toro
Point3d ptLn = ptLine ;
ptLn.ToLoc( frTorusFrame) ;
Vector3d vtLn = vtLine ;
vtLn.ToLoc( frTorusFrame) ;
// Setto i coefficienti dell'equazione
DBLVECTOR vdCoef( 5) ;
double dSqDistPO = ptLn.x * ptLn.x + ptLn.y * ptLn.y + ptLn.z * ptLn.z ;
double dPtVt = ptLn.x * vtLn.x + ptLn.y * vtLn.y + ptLn.z * vtLn.z ;
double dSqMaxR = dMaxRad * dMaxRad ;
double dDeltaSqR = dSqMaxR - dMinRad * dMinRad ;
double dB = 2 * dDeltaSqR - 4 * dSqMaxR ;
vdCoef[0] = dSqDistPO * dSqDistPO + dB * ( dSqDistPO - ptLn.z * ptLn.z) +
2 * dDeltaSqR * ptLn.z * ptLn.z + dDeltaSqR * dDeltaSqR ;
vdCoef[1] = 4 * dPtVt * dSqDistPO + 2 * dB * ( dPtVt - ptLn.z * vtLn.z) + 4 * dDeltaSqR * ptLn.z * vtLn.z ;
vdCoef[2] = 4 * dPtVt * dPtVt + dB * ( 1 - vtLn.z * vtLn.z) + 2 * ( dSqDistPO + dDeltaSqR * vtLn.z * vtLn.z) ;
vdCoef[3] = 4 * dPtVt ;
vdCoef[4] = 1 ;
// Risolvo l'equazione e ridimensiono il vettore dei parametri
DBLVECTOR vdRoots ;
PolynomialRoots( 4, vdCoef, vdRoots) ;
vdPar = vdRoots ;
// Riordino le soluzioni
for ( int ni = 0 ; ni < int( vdPar.size()) - 1 ; ++ ni) {
for ( int nj = ni ; nj < int( vdPar.size()) ; ++ nj) {
if ( vdPar[ni] > vdPar[nj]) {
swap( vdPar[ni], vdPar[nj]) ;
}
}
}
// Studio le soluzioni
int nIntType = T_ERROR ;
if ( vdPar.empty())
nIntType = T_NO_INT ;
else if ( vdPar.size() == 1) {
nIntType = T_ONE_TAN ;
vbType.push_back( false) ;
}
else if ( vdPar.size() == 2) {
// Soluzioni sufficientemente distinte
if ( vdPar[1] - vdPar[0] > EPS_SMALL) {
nIntType = T_TWO_SEC ;
vbType.push_back( true) ;
vbType.push_back( true) ;
}
// Soluzioni coincidenti
else {
vdPar.resize( 1) ;
nIntType = T_ONE_TAN ;
vbType.push_back( false) ;
}
}
else if ( vdPar.size() == 3) {
nIntType = T_THREE_ONE_TAN_TWO_SEC ;
}
else if ( vdPar.size() == 4) {
// Prime due soluzioni distinte
if ( vdPar[1] - vdPar[0] > EPS_SMALL) {
// Seconda e terza soluzione distinta
if ( vdPar[2] - vdPar[1] > EPS_SMALL) {
// Quarta e terza soluzione distinte
// Qauttro secanti
if ( vdPar[3] - vdPar[2] > EPS_SMALL) {
nIntType = T_FOUR_SEC ;
vbType.push_back( true) ;
vbType.push_back( true) ;
vbType.push_back( true) ;
vbType.push_back( true) ;
}
// Quarta e terza soluzione coincidenti
// Secante secante tangente
else {
nIntType = T_THREE_ONE_TAN_TWO_SEC ;
vdPar.resize( 3) ;
vbType.push_back( true) ;
vbType.push_back( true) ;
vbType.push_back( false) ;
}
}
// Seconda e terza soluzione coincidenti
else {
// Secante tangente secante
if ( vdPar[3] - vdPar[2] > EPS_SMALL) {
nIntType = T_THREE_ONE_TAN_TWO_SEC ;
vdPar[2] = vdPar[3] ;
vdPar.resize( 3) ;
vbType.push_back( true) ;
vbType.push_back( false) ;
vbType.push_back( true) ;
}
}
}
// Prime due soluzioni conicidenti
else {
// Terza e quarta soluzione distinte
// Tangente secante secante
if ( vdPar[3] - vdPar[2] > EPS_SMALL) {
nIntType = T_THREE_ONE_TAN_TWO_SEC ;
vdPar[1] = vdPar[2] ;
vdPar[2] = vdPar[3] ;
vdPar.resize( 3) ;
vbType.push_back( false) ;
vbType.push_back( true) ;
vbType.push_back( true) ;
}
// Terza e quarta soluzione distinte
else {
// Secona e terza soluzione distinte
// Tanbente tangente
if ( vdPar[2] - vdPar[1] > EPS_SMALL) {
nIntType = T_TWO_TAN ;
vdPar[1] = vdPar[2] ;
vdPar.resize( 2) ;
vbType.push_back( false) ;
vbType.push_back( false) ;
}
// Seconda e terza soluzione coincidenti
// Una soluzione tangente
else {
nIntType = T_ONE_TAN ;
vdPar[0] = 0.5 * ( vdPar[0] + vdPar[3]) ;
vdPar.resize( 1) ;
vbType.push_back( false) ;
}
}
}
}
return nIntType ;
}
//----------------------------------------------------------------------------
int
RayTorus( const Point3d& ptLine, const Vector3d& vtLine,
const Point3d& ptOTorus, const Vector3d& vtAxTorus, double dMinRad, double dMaxRad,
BOOLVECTOR& vbType, DBLVECTOR& vdPar)
{
int nIntType = LineTorus( ptLine, vtLine, ptOTorus, vtAxTorus, dMinRad, dMaxRad, vbType, vdPar) ;
if ( nIntType == T_ERROR || nIntType == T_NO_INT)
return nIntType ;
int nSize = int( vdPar.size()) ;
// Ciclo sui parametri
for ( int n = 0 ; n < nSize ; ++ n) {
// Se il parametro è negativo lo elimino
if ( vdPar[n] < - EPS_SMALL) {
for ( int m = n ; m < nSize - 1 ; ++ m) {
vdPar[m] = vdPar[m+1] ;
vbType[m] = vbType[m+1] ;
}
// Ridimensiono
-- nSize ;
vdPar.resize( nSize) ;
vbType.resize( nSize) ;
// Aggiorno l'indice
-- n ;
}
}
int nSecNum = 0 ;
// Ciclo sui parametri
for ( int n= 0 ; n < nSize ; ++ n) {
// Se secante ne aumento il numero
if ( vbType[n])
++ nSecNum ;
}
// Numero di puti di tangenza
int nNumTan = nSize - nSecNum ;
// Nessun contatto
if ( nSize == 0)
nIntType = T_NO_INT ;
else if ( nSize == 1) {
// Semi-retta secante in un punto
if ( vbType[0])
nIntType = T_ONE_SEC ;
else
// Semi-retta tangente in un punto
nIntType = T_ONE_TAN ;
}
else if ( nSize == 2) {
// Semi-retta secante in due punti
if ( nNumTan == 0)
nIntType = T_TWO_SEC ;
// Semi-retta secante in un punto e tangente in un altro
else if ( nNumTan == 1)
nIntType = T_TWO_TAN_SEC ;
// Semi-retta tangente in due punti
else
nIntType = T_TWO_TAN ;
}
else if ( nSize == 3) {
// Semi-retta secante in tre punti
if ( nNumTan == 0)
nIntType = T_THREE_SEC ;
// Semi-retta secante in due punti e tangente in un punto
else if ( nNumTan == 1)
nIntType = T_THREE_ONE_TAN_TWO_SEC ;
// Errore
else
nIntType = T_ERROR ;
}
else if ( nSize == 4) {
// Semi-retta secante in quattro punti
if ( nNumTan == 0)
nIntType = T_FOUR_SEC ;
// Errore
else
nIntType = T_ERROR ;
}
// Errore
else
nIntType = T_ERROR ;
return nIntType ;
}
//----------------------------------------------------------------------------
int
SegmentTorus( const Point3d& ptLine, const Vector3d& vtLine, double dSgLen,
const Point3d& ptOTorus, const Vector3d& vtAxTorus, double dMinRad, double dMaxRad,
BOOLVECTOR& vbType, DBLVECTOR& vdPar)
{
// Verifico se il segmento interseca il box del toro
Frame3d frTorus ; frTorus.Set( ptOTorus, vtAxTorus) ;
Point3d ptLineL = ptLine ; ptLineL.ToLoc( frTorus) ;
Vector3d vtLineL = vtLine ; vtLineL.ToLoc( frTorus) ;
double dTotRad = dMaxRad + dMinRad ;
double dU1, dU2 ;
if ( ! IntersLineBox( ptLineL, vtLineL, Point3d( -dTotRad, -dTotRad, -dMinRad), Point3d( dTotRad, dTotRad, dMinRad), dU1, dU2) ||
dU2 < -EPS_SMALL || dU1 > dSgLen + EPS_SMALL)
return T_NO_INT ;
// Calcolo l'intersezione con la linea illimitata
int nIntType = LineTorus( ptLine, vtLine, ptOTorus, vtAxTorus, dMinRad, dMaxRad, vbType, vdPar) ;
if ( nIntType == T_ERROR || nIntType == T_NO_INT)
return nIntType ;
// Elimino le intersezioni fuori dal segmento
int nSize = int( vdPar.size()) ;
for ( int n = 0 ; n < nSize ; ++ n) {
if ( vdPar[n] < -EPS_SMALL || vdPar[n] > dSgLen + EPS_SMALL) {
// tolgo l'intersezione dai vettori delle intersezioni
vdPar.erase( vdPar.begin() + n) ;
vbType.erase( vbType.begin() + n) ;
// aggiorno la dimensione dei vettori
-- nSize ;
// aggiorno l'indice
-- n ;
}
}
// Determino il numero delle intersezioni secanti
int nSecNum = 0 ;
for ( int n = 0 ; n < nSize ; ++ n) {
if ( vbType[n])
++ nSecNum ;
}
// Numero di punti di tangenza
int nNumTan = nSize - nSecNum ;
// Nessun contatto
if ( nSize == 0)
nIntType = T_NO_INT ;
else if ( nSize == 1) {
// Segmento secante in un punto
if ( vbType[0])
nIntType = T_ONE_SEC ;
else
// Segmento tangente in un punto
nIntType = T_ONE_TAN ;
}
else if ( nSize == 2) {
// Segmento secante in due punti
if ( nNumTan == 0)
nIntType = T_TWO_SEC ;
// Segmento secante in un punto e tangente in un altro
else if ( nNumTan == 1)
nIntType = T_TWO_TAN_SEC ;
// Segmento tangente in due punti
else
nIntType = T_TWO_TAN ;
}
else if ( nSize == 3) {
// Segmento secante in tre punti
if ( nNumTan == 0)
nIntType = T_THREE_SEC ;
// Segmento secante in due punti e tangente in un punto
else if ( nNumTan == 1)
nIntType = T_THREE_ONE_TAN_TWO_SEC ;
// Errore
else
nIntType = T_ERROR ;
}
else if ( nSize == 4) {
// Segmento secante in quattro punti
if ( nNumTan == 0)
nIntType = T_FOUR_SEC ;
// Errore
else
nIntType = T_ERROR ;
}
// Errore
else
nIntType = T_ERROR ;
return nIntType ;
}
//----------------------------------------------------------------------------
// Valuta la posizione reciproca fra un componente lineare e la parte inferiore
// ed esterna rispetto al centro di una superficie torica.
int
LinCompTorusExtInt( const Point3d& ptLine, const Vector3d& vtLine, double dSgLen, int nLinType,
const Point3d& ptOTorus, const Vector3d& vtAxTorus, double dMinRad, double dMaxRad,
BOOLVECTOR& vbType, DBLVECTOR& vdPar)
{
int nIntType ;
// Retta
if ( nLinType == Line)
nIntType = LineTorus( ptLine, vtLine, ptOTorus, vtAxTorus, dMinRad, dMaxRad, vbType, vdPar) ;
// Semi-retta
else if ( nLinType == Ray)
nIntType = RayTorus( ptLine, vtLine, ptOTorus, vtAxTorus, dMinRad, dMaxRad, vbType, vdPar) ;
// Segmento
else if ( nLinType == Segment)
nIntType = SegmentTorus( ptLine, vtLine, dSgLen, ptOTorus, vtAxTorus, dMinRad, dMaxRad, vbType, vdPar) ;
// Errore
else
nIntType = T_ERROR ;
// Ritorno errore
if ( nIntType == T_ERROR)
return nIntType ;
int nSize = int( vdPar.size()) ;
// Ciclo sui punti di contatto
for ( int n = 0 ; n < nSize ; ++ n) {
Vector3d vtInt = ptLine + vdPar[n] * vtLine - ptOTorus ;
Vector3d vtIntPlane = vtInt - vtInt * vtAxTorus * vtAxTorus ;
vtInt.Normalize() ;
// Se il punto di contatto è fuori dalla regione ammissibile lo elimino
if ( vtIntPlane.Len() < dMaxRad - EPS_SMALL ||
vtInt * vtAxTorus > EPS_ZERO) {
for ( int m = n ; m < nSize - 1 ; ++ m) {
vdPar[m] = vdPar[m+1] ;
vbType[m] = vbType[m+1] ;
}
// Ridimensiono
-- nSize ;
vdPar.resize( nSize) ;
vbType.resize( nSize) ;
// Aggiorno l'indice
-- n ;
}
}
int nSecNum = 0 ;
// Ciclo sui parametri
for ( int n = 0 ; n < nSize ; ++ n) {
// Se secante ne aumento il numero
if ( vbType[n])
++ nSecNum ;
}
// Numero di puti di tangenza
int nNumTan = nSize - nSecNum ;
// Nessun contatto
if ( nSize == 0)
nIntType = T_NO_INT ;
else if ( nSize == 1) {
// Segmento secante in un punto
if ( vbType[0])
nIntType = T_ONE_SEC ;
else
// Segmento tangente in un punto
nIntType = T_ONE_TAN ;
}
else if ( nSize == 2) {
// Segmento secante in due punti
if ( nNumTan == 0)
nIntType = T_TWO_SEC ;
// Segmento secante in un punto e tangente in un altro
else if ( nNumTan == 1)
nIntType = T_TWO_TAN_SEC ;
// Segmento tangente in due punti
else
nIntType = T_TWO_TAN ;
}
else if ( nSize == 3) {
// Segmento secante in tre punti
if ( nNumTan == 0)
nIntType = T_THREE_SEC ;
// Segmento secante in due punti e tangente in un punto
else if ( nNumTan == 1)
nIntType = T_THREE_ONE_TAN_TWO_SEC ;
// Errore
else
nIntType = T_ERROR ;
}
else if ( nSize == 4) {
// Segmento secante in quattro punti
if ( nNumTan == 0)
nIntType = T_FOUR_SEC ;
// Errore
else
nIntType = T_ERROR ;
}
// Errore
else
nIntType = T_ERROR ;
return nIntType ;
}
//----------------------------------------------------------------------------
// Valuta la posizione reciproca fra un componente lineare e la parte superiore
// ed interna di una superficie torica.
int
LinCompTorusInnUpInt( const Point3d& ptLine, const Vector3d& vtLine, double dSgLen, int nLinType,
const Point3d& ptOTorus, const Vector3d& vtAxTorus, double dMinRad, double dMaxRad,
BOOLVECTOR& vbType, DBLVECTOR& vdPar)
{
int nIntType ;
// Retta
if ( nLinType == Line)
nIntType = LineTorus( ptLine, vtLine, ptOTorus, vtAxTorus, dMinRad, dMaxRad, vbType, vdPar) ;
// Semi-retta
else if ( nLinType == Ray)
nIntType = RayTorus( ptLine, vtLine, ptOTorus, vtAxTorus, dMinRad, dMaxRad, vbType, vdPar) ;
// Segmento
else if ( nLinType == Segment)
nIntType = SegmentTorus( ptLine, vtLine, dSgLen, ptOTorus, vtAxTorus, dMinRad, dMaxRad, vbType, vdPar) ;
// Errore
else
nIntType = S_ERROR_INT ;
// Ritorno errore
if ( nIntType == S_ERROR_INT)
return nIntType ;
int nSize = int( vdPar.size()) ;
// Ciclo sui punti di contatto
for ( int n = 0 ; n < nSize ; ++ n) {
Vector3d vtInt = ptLine + vdPar[n] * vtLine - ptOTorus ;
Vector3d vtIntPlane = vtInt - vtInt * vtAxTorus * vtAxTorus ;
vtInt.Normalize() ;
// Se il punto di contatto è fuori dalla regione ammissibile lo elimino
if ( vtIntPlane.Len() > dMaxRad + EPS_SMALL ||
vtInt * vtAxTorus < - EPS_ZERO) {
for ( int m = n ; m < nSize - 1 ; ++ m) {
vdPar[m] = vdPar[m+1] ;
vbType[m] = vbType[m+1] ;
}
// Ridimensiono
-- nSize ;
vdPar.resize( nSize) ;
vbType.resize( nSize) ;
// Aggiorno l'indice
-- n ;
}
}
int nSecNum = 0 ;
// Ciclo sui parametri
for ( int n = 0 ; n < nSize ; ++ n) {
// Se secante ne aumento il numero
if ( vbType[n])
++ nSecNum ;
}
// Numero di puti di tangenza
int nNumTan = nSize - nSecNum ;
// Nessun contatto
if ( nSize == 0)
nIntType = T_NO_INT ;
else if ( nSize == 1) {
// Segmento secante in un punto
if ( vbType[0])
nIntType = T_ONE_SEC ;
else
// Segmento tangente in un punto
nIntType = T_ONE_TAN ;
}
else if ( nSize == 2) {
// Segmento secante in due punti
if ( nNumTan == 0)
nIntType = T_TWO_SEC ;
// Segmento secante in un punto e tangente in un altro
else if ( nNumTan == 1)
nIntType = T_TWO_TAN_SEC ;
// Segmento tangente in due punti
else
nIntType = T_TWO_TAN ;
}
else if ( nSize == 3) {
// Segmento secante in tre punti
if ( nNumTan == 0)
nIntType = T_THREE_SEC ;
// Segmento secante in due punti e tangente in un punto
else if ( nNumTan == 1)
nIntType = T_THREE_ONE_TAN_TWO_SEC ;
// Errore
else
nIntType = T_ERROR ;
}
else if ( nSize == 4) {
// Segmento secante in quattro punti
if ( nNumTan == 0)
nIntType = T_FOUR_SEC ;
// Errore
else
nIntType = T_ERROR ;
}
// Errore
else
nIntType = T_ERROR ;
return nIntType ;
}