Files
EgtGeomKernel/IntersLineArc.cpp
Dario Sassi 906aa6188a EgtGeomKernel :
- migliorata gestione segmento arco con tangenza su punto estremo dell'arco
- migliorata gestione triangoli praticamente complanari.
2020-03-10 18:21:48 +00:00

283 lines
11 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2014-2014
//----------------------------------------------------------------------------
// File : IntersLineArc.cpp Data : 07.07.14 Versione : 1.5g2
// Contenuto : Implementazione della classe intersezione linea/arco.
//
//
//
// Modifiche : 07.07.14 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "IntersLineArc.h"
using namespace std ;
//----------------------------------------------------------------------------
IntersLineArc::IntersLineArc( const CurveLine& Line, const CurveArc& Arc)
{
// Le intersezioni sono calcolate nel piano XY locale.
// nessuna intersezione trovata
m_nNumInters = 0 ;
// verifico validità linea e arco
if ( ! Line.IsValid() || ! Arc.IsValid())
return ;
// l'arco deve avere il piano coincidente con XY
if ( ! Arc.GetNormVersor().IsZplus() && ! Arc.GetNormVersor().IsZminus())
return ;
// verifico che l'angolo al centro non superi il giro
if ( abs( Arc.GetAngCenter()) > ANG_FULL + EPS_ANG_ZERO)
return ;
// verifico sovrapposizione box
BBox3d boxLine ;
if ( ! Line.GetLocalBBox( boxLine))
return ;
BBox3d boxArc ;
if ( ! Arc.GetLocalBBox( boxArc))
return ;
if ( ! boxLine.OverlapsXY( boxArc))
return ;
// linea : copia e Direzione
m_Line.CopyFrom( &Line) ;
m_vtDirL = m_Line.GetEnd() - m_Line.GetStart() ;
Vector3d vtDirLXY = m_vtDirL ;
vtDirLXY.z = 0 ;
if ( m_vtDirL.IsSmallXY())
return ;
// arco : copia
m_Arc.CopyFrom( &Arc) ;
// punto proiezione del centro arco sulla linea
double dU = (( m_Arc.GetCenter() - m_Line.GetStart()) * vtDirLXY) / vtDirLXY.SqLenXY() ;
Point3d ptPrjCen = m_Line.GetStart() + m_vtDirL * dU ;
// quadrato della distanza tra centro e punto proiezione
double dSqDist = ( ptPrjCen - m_Arc.GetCenter()).SqLenXY() ;
// differenza tra quadrato del raggio e quadrato della distanza
double dSqDelta = m_Arc.GetRadius() * m_Arc.GetRadius() - dSqDist ;
// se distanza maggiore del raggio -> nessuna intersezione
if ( dSqDelta < - 2 * m_Arc.GetRadius() * EPS_SMALL)
return ;
// se punto proiettato approssima uno degli estremi dell'arco, annullo dSqDelta
Point3d ptArcStart, ptArcEnd ;
if ( m_Arc.GetStartPoint( ptArcStart) && AreSamePointXYApprox( ptPrjCen, ptArcStart))
dSqDelta = 0 ;
else if ( m_Arc.GetEndPoint( ptArcEnd) && AreSamePointXYApprox( ptPrjCen, ptArcEnd))
dSqDelta = 0 ;
// se distanza uguale al raggio -> una intersezione tangente, è la proiezione
// (corrisponde a una differenza max di EPS_SMALL tra le intersezioni)
if ( dSqDelta < EPS_SMALL * EPS_SMALL) {
// determinazione geometrica dell'intersezione tra le due curve
int nPosL, nPosA ;
if ( ! CalcIntersGeomData( 0, ptPrjCen, nPosL, nPosA))
return ;
// determinazione topologica dell'intersezione tra le due curve
if ( ! CalcTgIntersTopolData( 0, nPosL, nPosA))
return ;
// aggiorno dati generali di intersezione
m_Info[0].bOverlap = false ;
m_nNumInters = 1 ;
return ;
}
// distanza minore del raggio -> due intersezioni
double dDelta = sqrt( dSqDelta) ;
Vector3d vtDelta = m_vtDirL * dDelta / m_vtDirL.LenXY() ;
int nPosL, nPosA ;
// ---> prima intersezione
// determinazione geometrica e topologica dell'intersezione tra le due curve
if ( CalcIntersGeomData( 0, ptPrjCen - vtDelta, nPosL, nPosA) &&
CalcSecIntersTopolData( 0, nPosL, nPosA)) {
// aggiorno dati generali di intersezione
m_Info[0].bOverlap = false ;
++ m_nNumInters ;
}
// ---> seconda intersezione
// determinazione geometrica e topologica dell'intersezione tra le due curve
if ( CalcIntersGeomData( m_nNumInters, ptPrjCen + vtDelta, nPosL, nPosA) &&
CalcSecIntersTopolData( m_nNumInters, nPosL, nPosA)) {
// aggiorno dati generali di intersezione
m_Info[m_nNumInters].bOverlap = false ;
++ m_nNumInters ;
}
}
//----------------------------------------------------------------------------
bool
IntersLineArc::CalcIntersGeomData( int nInt, const Point3d& ptInt, int& nPosL, int& nPosA)
{
// posizione parametrica dell'intersezione sulla linea
if ( ! m_Line.CalcPointParamPosiz( ptInt, true, m_Info[nInt].IciA[0].dU, nPosL))
return false ;
// posizione parametrica dell'intersezione sull'arco
if ( ! m_Arc.CalcPointParamPosiz( ptInt, m_Info[nInt].IciB[0].dU, nPosA))
return false ;
// se soluzione non accettata, esco
if ( nPosL == ICurve::PP_NULL || nPosA == ICurve::PP_NULL)
return false ;
// calcolo i punti sulle due curve (possono differire in Z)
m_Info[nInt].IciA[0].ptI = m_Line.GetStart() + m_Info[nInt].IciA[0].dU * m_vtDirL ;
m_Arc.GetPointD1D2( m_Info[nInt].IciB[0].dU, ICurve::FROM_MINUS, m_Info[nInt].IciB[0].ptI) ;
return true ;
}
//----------------------------------------------------------------------------
bool
IntersLineArc::CalcTgIntersTopolData( int nInt, int nPosL, int nPosA)
{
// calcolo dati ausiliari
bool bCCW = (( m_Arc.GetAngCenter() > 0 && m_Arc.GetNormVersor().IsZplus()) ||
( m_Arc.GetAngCenter() < 0 && m_Arc.GetNormVersor().IsZminus())) ;
double dCrossXY = CrossXY( m_vtDirL, ( m_Arc.GetCenter() - m_Info[nInt].IciB[0].ptI)) ;
// calcolo tipo di intersezione
m_Info[nInt].IciA[0].nPrevTy = ICCT_NULL ;
m_Info[nInt].IciA[0].nNextTy = ICCT_NULL ;
m_Info[nInt].IciB[0].nPrevTy = ICCT_NULL ;
m_Info[nInt].IciB[0].nNextTy = ICCT_NULL ;
// si incontrano alle estremità, non si può dire alcunché
if ( ( nPosL == ICurve::PP_START || nPosL == ICurve::PP_END) &&
( nPosA == ICurve::PP_START || nPosA == ICurve::PP_END)) {
; // rimangono tutti NULL
}
// l'inizio di L interseca il mezzo di A
else if ( nPosL == ICurve::PP_START) {
if ( bCCW)
m_Info[nInt].IciA[0].nNextTy = ICCT_OUT ; // NULL + OUT
else
m_Info[nInt].IciA[0].nNextTy = ICCT_IN ; // NULL + IN
// curva B NULL + NULL
}
// la fine di L interseca il mezzo di A
else if ( nPosL == ICurve::PP_END) {
if ( bCCW)
m_Info[nInt].IciA[0].nPrevTy = ICCT_OUT ; // OUT + NULL
else
m_Info[nInt].IciA[0].nPrevTy = ICCT_IN ; // IN + NULL
// curva B NULL + NULL
}
// l'inizio di A interseca il mezzo di L
else if ( nPosA == ICurve::PP_START) {
// curva A NULL + NULL
if ( - dCrossXY > 0)
m_Info[nInt].IciB[0].nNextTy = ICCT_OUT ; // NULL + OUT
else
m_Info[nInt].IciB[0].nNextTy = ICCT_IN ; // NULL + IN
}
// la fine di A interseca il mezzo di L
else if ( nPosA == ICurve::PP_END) {
// curva A NULL + NULL
if ( - dCrossXY > 0)
m_Info[nInt].IciB[0].nPrevTy = ICCT_OUT ; // OUT + NULL
else
m_Info[nInt].IciB[0].nPrevTy = ICCT_IN ; // IN + NULL
}
// si intersecano nel mezzo
else {
if ( bCCW) { // OUT + OUT
m_Info[nInt].IciA[0].nPrevTy = ICCT_OUT ;
m_Info[nInt].IciA[0].nNextTy = ICCT_OUT ;
}
else { // IN + IN
m_Info[nInt].IciA[0].nPrevTy = ICCT_IN ;
m_Info[nInt].IciA[0].nNextTy = ICCT_IN ;
}
if ( - dCrossXY > 0) { // OUT + OUT
m_Info[nInt].IciB[0].nPrevTy = ICCT_OUT ;
m_Info[nInt].IciB[0].nNextTy = ICCT_OUT ;
}
else { // IN + IN
m_Info[nInt].IciB[0].nPrevTy = ICCT_IN ;
m_Info[nInt].IciB[0].nNextTy = ICCT_IN ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
IntersLineArc::CalcSecIntersTopolData( int nInt, int nPosL, int nPosA)
{
// calcolo dati ausiliari
Point3d ptIntA ;
Vector3d vtDirA ;
m_Arc.GetPointD1D2( m_Info[nInt].IciB[0].dU, ICurve::FROM_MINUS, ptIntA, &vtDirA) ;
double dCrossXY = CrossXY( m_vtDirL, vtDirA) ;
// calcolo tipo di intersezione
m_Info[nInt].IciA[0].nPrevTy = ICCT_NULL ;
m_Info[nInt].IciA[0].nNextTy = ICCT_NULL ;
m_Info[nInt].IciB[0].nPrevTy = ICCT_NULL ;
m_Info[nInt].IciB[0].nNextTy = ICCT_NULL ;
// si incontrano alle estremità, non si può dire alcunché
if ( ( nPosL == ICurve::PP_START || nPosL == ICurve::PP_END) &&
( nPosA == ICurve::PP_START || nPosA == ICurve::PP_END)) {
; // rimangono tutti NULL
}
// l'inizio di 1 interseca il mezzo di 2
else if ( nPosL == ICurve::PP_START) {
if ( dCrossXY > 0)
m_Info[nInt].IciA[0].nNextTy = ICCT_OUT ; // NULL + OUT
else
m_Info[nInt].IciA[0].nNextTy = ICCT_IN ; // NULL + IN
// curva B NULL + NULL
}
// la fine di 1 interseca il mezzo di 2
else if ( nPosL == ICurve::PP_END) {
if ( dCrossXY < 0)
m_Info[nInt].IciA[0].nPrevTy = ICCT_OUT ; // OUT + NULL
else
m_Info[nInt].IciA[0].nPrevTy = ICCT_IN ; // IN + NULL
// curva B NULL + NULL
}
// l'inizio di 2 interseca il mezzo di 1
else if ( nPosA == ICurve::PP_START) {
// curva A NULL + NULL
if ( - dCrossXY > 0)
m_Info[nInt].IciB[0].nNextTy = ICCT_OUT ; // NULL + OUT
else
m_Info[nInt].IciB[0].nNextTy = ICCT_IN ; // NULL + IN
}
// la fine di 2 interseca il mezzo di 1
else if ( nPosA == ICurve::PP_END) {
// curva A NULL + NULL
if ( - dCrossXY < 0)
m_Info[nInt].IciB[0].nPrevTy = ICCT_OUT ; // OUT + NULL
else
m_Info[nInt].IciB[0].nPrevTy = ICCT_IN ; // IN + NULL
}
// si intersecano nel mezzo
else {
if ( CrossXY( ( m_Line.GetStart() - ( ptIntA - vtDirA)), vtDirA) > 0) {
m_Info[nInt].IciA[0].nPrevTy = ICCT_OUT ;
m_Info[nInt].IciA[0].nNextTy = ICCT_IN ;
}
else {
m_Info[nInt].IciA[0].nPrevTy = ICCT_IN ;
m_Info[nInt].IciA[0].nNextTy = ICCT_OUT ;
}
if ( CrossXY( ( ( ptIntA - vtDirA) - m_Line.GetStart()), m_vtDirL) > 0) {
m_Info[nInt].IciB[0].nPrevTy = ICCT_OUT ;
m_Info[nInt].IciB[0].nNextTy = ICCT_IN ;
}
else {
m_Info[nInt].IciB[0].nPrevTy = ICCT_IN ;
m_Info[nInt].IciB[0].nNextTy = ICCT_OUT ;
}
}
return true ;
}