1f47402215
- piccola correzione.
280 lines
9.9 KiB
C++
280 lines
9.9 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2023-2023
|
|
//----------------------------------------------------------------------------
|
|
// File : IntersLineCyl.cpp Data : 16.05.23 Versione : 2.5e3
|
|
// Contenuto : Implementazione della intersezione linea/cilindro.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 16.05.23 DS Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
#include "stdafx.h"
|
|
#include "IntersLineCyl.h"
|
|
#include "/EgtDev/Include/EGkFrame3d.h"
|
|
#include "/EgtDev/Include/EGkIntersLineCylinder.h"
|
|
#include "/EgtDev/Include/ENkPolynomialRoots.h"
|
|
|
|
using namespace std ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Linea e cilindro sono nel medesimo riferimento.
|
|
// Il cilindro è centrato sull'asse Z e appoggiato sul piano XY.
|
|
// In caso di intersezione viene restituito true e i parametri in dU1 e dU2.
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
IntersLineCyl( const Point3d& ptP, const Vector3d& vtV, double dH, double dRad, bool bTapLow, bool bTapUp,
|
|
double& dU1, Point3d& ptInt1, Vector3d& vtN1, double& dU2, Point3d& ptInt2, Vector3d& vtN2, bool bIgnoreTap, bool bInvertNormals)
|
|
{
|
|
dU1 = NAN ;
|
|
dU2 = NAN ;
|
|
|
|
// Verifico il versore
|
|
if ( vtV.IsSmall())
|
|
return false ;
|
|
|
|
// Verifico il cilindro
|
|
if ( dRad < EPS_SMALL || dH < EPS_SMALL)
|
|
return false ;
|
|
|
|
// 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 dEpsRad = ( vtV.IsZeroXY() ? - EPS_SMALL : EPS_SMALL) ;
|
|
if ( bIgnoreTap)
|
|
dEpsRad = 0. ;
|
|
ptInt1 = ptP + ( ( 0 - ptP.z) / vtV.z) * vtV ;
|
|
if ( ptInt1.x * ptInt1.x + ptInt1.y * ptInt1.y < dRad * dRad + 2 * dRad * dEpsRad) {
|
|
nBasInt += 1 ;
|
|
vtN1 = - Z_AX ;
|
|
dU1 = ( ( 0 - ptP.z) / vtV.z) ;
|
|
}
|
|
ptInt2 = ptP + ( ( dH - ptP.z) / vtV.z) * vtV ;
|
|
if ( ptInt2.x * ptInt2.x + ptInt2.y * ptInt2.y < dRad * dRad + 2 * dRad * dEpsRad) {
|
|
nBasInt += 2 ;
|
|
vtN2 = Z_AX ;
|
|
dU2 = ( ( dH - ptP.z) / vtV.z) ;
|
|
}
|
|
}
|
|
|
|
// Se la linea interseca entrambe le basi, si sono trovate le due intersezioni
|
|
if ( nBasInt == 3) {
|
|
if ( dU1 > dU2) {
|
|
swap( dU1, dU2) ;
|
|
swap( ptInt1, ptInt2) ;
|
|
swap( vtN1, vtN2) ;
|
|
}
|
|
if ( bInvertNormals) {
|
|
vtN1 *= - 1 ;
|
|
vtN2 *= - 1 ;
|
|
}
|
|
// Trovate intersezioni
|
|
return true ;
|
|
}
|
|
|
|
// Determino le intersezioni con la superficie laterale del cilindro
|
|
DBLVECTOR vdCoeff{ ptP.x * ptP.x + ptP.y * ptP.y - dRad * dRad,
|
|
2 * ( ptP.x * vtV.x + ptP.y * vtV.y),
|
|
vtV.x * vtV.x + vtV.y * vtV.y} ;
|
|
DBLVECTOR vdRoots ;
|
|
int nRoot = PolynomialRoots( 2, vdCoeff, vdRoots) ;
|
|
|
|
// Epsilon per piani di tappo
|
|
double dEpsLow = ( bTapLow ? - EPS_SMALL : EPS_SMALL) ;
|
|
double dEpsUp = ( bTapUp ? EPS_SMALL : - EPS_SMALL) ;
|
|
if ( bIgnoreTap) {
|
|
dEpsLow = 0. ;
|
|
dEpsUp = 0. ;
|
|
}
|
|
|
|
// 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 ;
|
|
}
|
|
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 ;
|
|
dU1 = vdRoots[0] ;
|
|
dU2 = vdRoots[1] ;
|
|
// Determino le normali
|
|
vtN1.Set( ptInt1.x, ptInt1.y, 0) ;
|
|
vtN1.Normalize() ;
|
|
vtN2.Set( ptInt2.x, ptInt2.y, 0) ;
|
|
vtN2.Normalize() ;
|
|
if ( dU1 > dU2) {
|
|
swap( dU1, dU2) ;
|
|
swap( ptInt1, ptInt2) ;
|
|
swap( vtN1, vtN2) ;
|
|
}
|
|
if ( bInvertNormals) {
|
|
vtN1 *= - 1 ;
|
|
vtN2 *= - 1 ;
|
|
}
|
|
// 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
|
|
dU1 = vdRoots[0] ;
|
|
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
|
|
dU2 = vdRoots[0] ;
|
|
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 ;
|
|
if ( dU1 > dU2) {
|
|
swap( dU1, dU2) ;
|
|
swap( ptInt1, ptInt2) ;
|
|
swap( vtN1, vtN2) ;
|
|
}
|
|
if ( bInvertNormals) {
|
|
vtN1 *= - 1 ;
|
|
vtN2 *= - 1 ;
|
|
}
|
|
// Trovate intersezioni
|
|
return true ;
|
|
}
|
|
|
|
// Nessuna soluzione : nessuna intersezione
|
|
else
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// 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
|
|
IntersLineCyl( const Point3d& ptLineSt, const Vector3d& vtLineDir,
|
|
const Frame3d& CylFrame, double dH, double dRad, bool bTapLow, bool bTapUp,
|
|
double& dU1, Point3d& ptInt1, Vector3d& vtN1, double& dU2, Point3d& ptInt2, Vector3d& vtN2, bool bIgnoreTap, bool bInvertNormals)
|
|
{
|
|
// Porto la linea nel riferimento del cilindro
|
|
Point3d ptP = GetToLoc( ptLineSt, CylFrame) ;
|
|
Vector3d vtV = GetToLoc( vtLineDir, CylFrame) ;
|
|
if ( IntersLineCyl( ptP, vtV, dH, dRad, bTapLow, bTapUp,
|
|
dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, bIgnoreTap, bInvertNormals))
|
|
{
|
|
ptInt1.ToGlob( CylFrame) ;
|
|
vtN1.ToGlob( CylFrame) ;
|
|
ptInt2.ToGlob( CylFrame) ;
|
|
vtN2.ToGlob( CylFrame) ;
|
|
return true ;
|
|
}
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Linea e cilindro sono nel medesimo riferimento.
|
|
// Il cilindro è definito con centro della base, asse, raggio e altezza.
|
|
// In caso di intersezione viene restituito true e i parametri in dU1 e dU2.
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
IntersLineCyl( const Point3d& ptL, const Vector3d& vtL,
|
|
const Point3d& ptCyl, const Vector3d& vtCyl, double dRad, double dHeight,
|
|
double& dU1, double& dU2)
|
|
{
|
|
// Riferimento intrinseco del cilindro
|
|
Frame3d frCyl ;
|
|
if ( ! frCyl.Set( ptCyl, vtCyl))
|
|
return false ;
|
|
// Ora eseguo i conti nel riferimento intrinseco
|
|
bool bTapLow = false ;
|
|
bool bTapUp = false ;
|
|
bool bIgnoreTap = true ;
|
|
Point3d ptInt1, ptInt2 ;
|
|
Vector3d vtN1, vtN2 ;
|
|
return IntersLineCyl( ptL, vtL, frCyl, dHeight, dRad, bTapLow, bTapUp,
|
|
dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, bIgnoreTap) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Linea e cilindro sono nel medesimo riferimento.
|
|
// Il cilindro è definito con centri delle due basi, e raggio.
|
|
// In caso di intersezione viene restituito true e i parametri in dU1 e dU2.
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
IntersLineCyl( const Point3d& ptL, const Vector3d& vtL,
|
|
const Point3d& ptCyl1, const Point3d& ptCyl2, double dRad,
|
|
double& dU1, double& dU2)
|
|
{
|
|
// Determino asse ed altezza del cilindro
|
|
Vector3d vtCyl = ptCyl2 - ptCyl1 ;
|
|
double dHeight = vtCyl.Len() ;
|
|
if ( dHeight < EPS_SMALL)
|
|
return false ;
|
|
vtCyl /= dHeight ;
|
|
// Riferimento intrinseco del cilindro
|
|
Frame3d frCyl ;
|
|
if ( ! frCyl.Set( ptCyl1, vtCyl))
|
|
return false ;
|
|
// Ora eseguo i conti nel riferimento intrinseco
|
|
bool bTapLow = false ;
|
|
bool bTapUp = false ;
|
|
bool bIgnoreTap = true ;
|
|
Point3d ptInt1, ptInt2 ;
|
|
Vector3d vtN1, vtN2 ;
|
|
return IntersLineCyl( ptL, vtL, frCyl, dHeight, dRad, bTapLow, bTapUp,
|
|
dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, bIgnoreTap) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// linea già nel riferimento intrinseco del cilindro
|
|
//----------------------------------------------------------------------------
|
|
bool IntersLineCyl( const Point3d& ptL, const Vector3d& vtL,
|
|
double dRad, double dHeight,
|
|
double& dU1, double& dU2)
|
|
{
|
|
Point3d ptInt1, ptInt2 ;
|
|
Vector3d vtN1, vtN2 ;
|
|
bool bTapLow = false, bTapUp = false ;
|
|
bool bIgnoreTap = true ;
|
|
return IntersLineCyl( ptL, vtL, dHeight, dRad, bTapLow, bTapUp,
|
|
dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, bIgnoreTap) ;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// funzione esposta per altre dll
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
IntersLineCyl( const Point3d& ptLineSt, const Vector3d& vtLineDir,
|
|
const Frame3d& CylFrame, double dH, double dRad,
|
|
double& dU1, Point3d& ptInt1, Vector3d& vtN1, double& dU2, Point3d& ptInt2, Vector3d& vtN2)
|
|
{
|
|
return IntersLineCyl( ptLineSt, vtLineDir, CylFrame, dH, dRad, false, false,
|
|
dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, true, false) ;
|
|
}
|