Files
EgtGeomKernel/IntersLineLine.cpp
T
Dario Sassi 9770d57793 EgtGeomKernel :
- tolta da ChainCurves riduzione tolleranza con dimensione pezzi
- aggiunte DistPointTriangle, IntersPlaneTria, IntersPlaneSurfTm
- correzioni a IntersCrvCompoCrvCompo per topologia intersezioni
- completamente riscritta IntersCoplanarLineTria per robustezza topologica.
2017-10-21 17:01:23 +00:00

352 lines
14 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2014-2014
//----------------------------------------------------------------------------
// File : IntersLineLine.cpp Data : 15.06.14 Versione : 1.5f6
// Contenuto : Implementazione della classe intersezione linea/linea.
//
//
//
// Modifiche : 15.06.14 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "IntersLineLine.h"
#include <algorithm>
using namespace std ;
//----------------------------------------------------------------------------
// Il punto è esterno al FatSegment se dista da questo più di Tol e la sua proiezione sta sul segmento
bool
IsPointOutFatSegment( const Point3d& ptP, const Point3d& ptS, const Vector3d& vtDir, double dLenXY, double dTol)
{
// distanza del punto dalla linea del segmento (con compensazione piccolissimi errori)
if ( fabs( CrossXY( ( ptP - ptS), vtDir)) < ( dTol + EPS_ZERO) * dLenXY)
return false ;
// distanza con segno della proiezione del punto sul segmento dall'inizio per lunghezza segmento
double dDistXY = ScalarXY( ( ptP - ptS), vtDir) ;
// se il punto non si proietta sul segmento entro la tolleranza
if ( dDistXY < - dTol * dLenXY || dDistXY > ( dLenXY + dTol) * dLenXY)
return false ;
// altrimenti
return true ;
}
//----------------------------------------------------------------------------
IntersLineLine::IntersLineLine( const CurveLine& Line1, const CurveLine& Line2, bool bFinite)
{
// Le intersezioni sono calcolate nel piano XY locale.
// nessuna intersezione trovata
m_bOverlaps = false ;
m_nNumInters = 0 ;
// verifico validità linee
if ( ! Line1.IsValid() || ! Line2.IsValid())
return ;
// se sono linee (infinite)
if ( ! bFinite)
IntersInfiniteLines( Line1, Line2) ;
else
IntersFiniteLines( Line1, Line2) ;
}
//----------------------------------------------------------------------------
void
IntersLineLine::IntersInfiniteLines( const ICurveLine& Line1, const ICurveLine& Line2)
{
// linea 1 : Start, End, Direzione e Lunghezza
Point3d ptS1 = Line1.GetStart() ;
Point3d ptE1 = Line1.GetEnd() ;
Vector3d vtDir1 = ptE1 - ptS1 ;
double dLen1XY = vtDir1.LenXY() ;
if ( dLen1XY < EPS_SMALL)
return ;
// linea 2 : Start, Direzione e Lunghezza
Point3d ptS2 = Line2.GetStart() ;
Point3d ptE2 = Line2.GetEnd() ;
Vector3d vtDir2 = ptE2 - ptS2 ;
double dLen2XY = vtDir2.LenXY() ;
if ( dLen2XY < EPS_SMALL)
return ;
// prodotto vettoriale nel piano XY tra le direzioni delle linee
double dCrossXY = CrossXY( vtDir1, vtDir2) ;
// se le linee non sono parallele
if ( fabs( dCrossXY) > SIN_EPS_ANG_ZERO * ( dLen1XY * dLen2XY)) {
// posizioni parametriche dell'intersezione sulle linee
m_Info.IciA[0].dU = CrossXY( ( ptS2 - ptS1), vtDir2) / dCrossXY ;
m_Info.IciB[0].dU = CrossXY( ( ptS2 - ptS1), vtDir1) / dCrossXY ;
// calcolo i punti sulle due linee (possono differire in Z)
m_Info.IciA[0].ptI = ptS1 + m_Info.IciA[0].dU * vtDir1 ;
m_Info.IciB[0].ptI = ptS2 + m_Info.IciB[0].dU * vtDir2 ;
// si intersecano sempre nel mezzo
if ( CrossXY( ( ptS1 - ptS2), vtDir2) > 0) {
m_Info.IciA[0].nPrevTy = ICCT_OUT ;
m_Info.IciA[0].nNextTy = ICCT_IN ;
}
else {
m_Info.IciA[0].nPrevTy = ICCT_IN ;
m_Info.IciA[0].nNextTy = ICCT_OUT ;
}
if ( CrossXY( ( ptS2 - ptS1), vtDir1) > 0) {
m_Info.IciB[0].nPrevTy = ICCT_OUT ;
m_Info.IciB[0].nNextTy = ICCT_IN ;
}
else {
m_Info.IciB[0].nPrevTy = ICCT_IN ;
m_Info.IciB[0].nNextTy = ICCT_OUT ;
}
m_Info.bOverlap = false ;
m_bOverlaps = false ;
m_nNumInters = 1 ; // una intersezione
return ;
}
// se le linee sono parallele e non coincidenti
if ( fabs( CrossXY( ( ptS2 - ptS1), vtDir1)) > EPS_SMALL * dLen1XY)
return ; // non ci sono intersezioni
// le linee sono parallele e coincidenti e sono infinite
m_bOverlaps = true ;
m_nNumInters = 0 ; // non esistono estremi del tratto sovrapposto
}
//----------------------------------------------------------------------------
void
IntersLineLine::IntersFiniteLines( const ICurveLine& Line1, const ICurveLine& Line2)
{
// verifico sovrapposizione box
BBox3d boxL1 ;
if ( ! Line1.GetLocalBBox( boxL1))
return ;
BBox3d boxL2 ;
if ( ! Line2.GetLocalBBox( boxL2))
return ;
if ( ! boxL1.OverlapsXY( boxL2))
return ;
// linea 1 : Start, End, Direzione e Lunghezza
Point3d ptS1 = Line1.GetStart() ;
Point3d ptE1 = Line1.GetEnd() ;
Vector3d vtDir1 = ptE1 - ptS1 ;
double dLen1XY = vtDir1.LenXY() ;
if ( dLen1XY < EPS_SMALL)
return ;
// linea 2 : Start, Direzione e Lunghezza
Point3d ptS2 = Line2.GetStart() ;
Point3d ptE2 = Line2.GetEnd() ;
Vector3d vtDir2 = ptE2 - ptS2 ;
double dLen2XY = vtDir2.LenXY() ;
if ( dLen2XY < EPS_SMALL)
return ;
// prodotto vettoriale nel piano XY tra le direzioni delle linee
double dCrossXY = CrossXY( vtDir1, vtDir2) ;
// flag per linee parallele
bool bParallel = ( fabs( dCrossXY) < SIN_EPS_ANG_ZERO * ( dLen1XY * dLen2XY)) ;
// flag per segmenti che si allontanano significativamente
bool bFarEnds = ( ( fabs( dCrossXY) > SIN_EPS_ANG_SMALL * ( dLen1XY * dLen2XY)) ||
IsPointOutFatSegment( ptS1, ptS2, vtDir2, dLen2XY, EPS_SMALL) ||
IsPointOutFatSegment( ptE1, ptS2, vtDir2, dLen2XY, EPS_SMALL) ||
IsPointOutFatSegment( ptS2, ptS1, vtDir1, dLen1XY, EPS_SMALL) ||
IsPointOutFatSegment( ptE2, ptS1, vtDir1, dLen1XY, EPS_SMALL)) ;
// se non sono paralleli e si allontanano tra loro abbastanza
if ( ! bParallel && bFarEnds) {
// posizioni parametriche dell'intersezione sulle linee
m_Info.IciA[0].dU = CrossXY( ( ptS2 - ptS1), vtDir2) / dCrossXY ;
m_Info.IciB[0].dU = CrossXY( ( ptS2 - ptS1), vtDir1) / dCrossXY ;
// verifica posizione intersezione su prima linea
int nPos1 = ICurve::PP_NULL ; // fuori
if ( abs( m_Info.IciA[0].dU * dLen1XY) < EPS_SMALL)
nPos1 = ICurve::PP_START ; // vicino a inizio
else if ( abs(( 1 - m_Info.IciA[0].dU) * dLen1XY) < EPS_SMALL)
nPos1 = ICurve::PP_END ; // vicino a fine
else if ( m_Info.IciA[0].dU > 0 && m_Info.IciA[0].dU < 1)
nPos1 = ICurve::PP_MID ; // nell'interno
// verifica posizione intersezione su seconda linea
int nPos2 = ICurve::PP_NULL ; // fuori
if ( abs( m_Info.IciB[0].dU * dLen2XY) < EPS_SMALL)
nPos2 = ICurve::PP_START ; // vicino a inizio
else if ( abs(( 1 - m_Info.IciB[0].dU) * dLen2XY) < EPS_SMALL)
nPos2 = ICurve::PP_END ; // vicino a fine
else if ( m_Info.IciB[0].dU > 0 && m_Info.IciB[0].dU < 1)
nPos2 = ICurve::PP_MID ; // nell'interno
// se soluzione non accettata, esco
if ( nPos1 == ICurve::PP_NULL || nPos2 == ICurve::PP_NULL)
return ;
// limito i parametri a stare sui segmenti (0...1)
m_Info.IciA[0].dU = min( max( m_Info.IciA[0].dU, 0.), 1.) ;
m_Info.IciB[0].dU = min( max( m_Info.IciB[0].dU, 0.), 1.) ;
// calcolo i punti sulle due linee (possono differire in Z)
m_Info.IciA[0].ptI = ptS1 + m_Info.IciA[0].dU * vtDir1 ;
m_Info.IciB[0].ptI = ptS2 + m_Info.IciB[0].dU * vtDir2 ;
// calcolo tipo di intersezione
m_Info.IciA[0].nPrevTy = ICCT_NULL ;
m_Info.IciA[0].nNextTy = ICCT_NULL ;
m_Info.IciB[0].nPrevTy = ICCT_NULL ;
m_Info.IciB[0].nNextTy = ICCT_NULL ;
// si incontrano alle estremità, non si può dire alcunché
if ( ( nPos1 == ICurve::PP_START || nPos1 == ICurve::PP_END) &&
( nPos2 == ICurve::PP_START || nPos2 == ICurve::PP_END)) {
; // rimangono tutti NULL
}
// l'inizio di 1 interseca il mezzo di 2
else if ( nPos1 == ICurve::PP_START) {
if ( dCrossXY > 0)
m_Info.IciA[0].nNextTy = ICCT_OUT ; // NULL + OUT
else
m_Info.IciA[0].nNextTy = ICCT_IN ; // NULL + IN
// curva B NULL + NULL
}
// la fine di 1 interseca il mezzo di 2
else if ( nPos1 == ICurve::PP_END) {
if ( dCrossXY < 0)
m_Info.IciA[0].nPrevTy = ICCT_OUT ; // OUT + NULL
else
m_Info.IciA[0].nPrevTy = ICCT_IN ; // IN + NULL
// curva B NULL + NULL
}
// l'inizio di 2 interseca il mezzo di 1
else if ( nPos2 == ICurve::PP_START) {
// curva A NULL + NULL
if ( - dCrossXY > 0)
m_Info.IciB[0].nNextTy = ICCT_OUT ; // NULL + OUT
else
m_Info.IciB[0].nNextTy = ICCT_IN ; // NULL + IN
}
// la fine di 2 interseca il mezzo di 1
else if ( nPos2 == ICurve::PP_END) {
// curva A NULL + NULL
if ( - dCrossXY < 0)
m_Info.IciB[0].nPrevTy = ICCT_OUT ; // OUT + NULL
else
m_Info.IciB[0].nPrevTy = ICCT_IN ; // IN + NULL
}
// si intersecano nel mezzo
else {
if ( CrossXY( ( ptS1 - ptS2), vtDir2) > 0) {
m_Info.IciA[0].nPrevTy = ICCT_OUT ;
m_Info.IciA[0].nNextTy = ICCT_IN ;
}
else {
m_Info.IciA[0].nPrevTy = ICCT_IN ;
m_Info.IciA[0].nNextTy = ICCT_OUT ;
}
if ( CrossXY( ( ptS2 - ptS1), vtDir1) > 0) {
m_Info.IciB[0].nPrevTy = ICCT_OUT ;
m_Info.IciB[0].nNextTy = ICCT_IN ;
}
else {
m_Info.IciB[0].nPrevTy = ICCT_IN ;
m_Info.IciB[0].nNextTy = ICCT_OUT ;
}
}
m_Info.bOverlap = false ;
m_bOverlaps = false ;
m_nNumInters = 1 ;
return ;
}
// se le linee sono parallele e non coincidenti
if ( bParallel && bFarEnds)
return ; // non ci sono intersezioni
// le linee sono parallele e coincidenti, si cercano eventuali sovrapposizioni
// determino se sono equiversi o controversi
bool bEqVers = ( ScalarXY( vtDir1, vtDir2) > 0) ;
// calcolo dei valori parametrici degli estremi del secondo segmento sul primo
double dUmin = ScalarXY( ( ptS2 - ptS1), vtDir1) / vtDir1.SqLenXY() ;
double dUmax = ScalarXY( ( ptE2 - ptS1), vtDir1) / vtDir1.SqLenXY() ;
if ( ! bEqVers)
swap( dUmin, dUmax) ;
// estremo inferiore del primo coincide con superiore del secondo -> un punto estremo
if ( ( dUmax * vtDir1).IsSmall()) {
m_Info.IciA[0].dU = 0 ;
m_Info.IciB[0].dU = ( bEqVers ? 1 : 0) ;
m_Info.IciA[0].ptI = ptS1 + m_Info.IciA[0].dU * vtDir1 ;
m_Info.IciB[0].ptI = ptS2 + m_Info.IciB[0].dU * vtDir2 ;
m_Info.IciA[0].nPrevTy = ICCT_NULL ;
m_Info.IciA[0].nNextTy = ICCT_NULL ;
m_Info.IciB[0].nPrevTy = ICCT_NULL ;
m_Info.IciB[0].nNextTy = ICCT_NULL ;
m_Info.bOverlap = false ;
m_bOverlaps = false ;
m_nNumInters = 1 ;
return ;
}
// estremo superiore del primo coincide con inferiore del secondo -> un punto estremo
else if ( ( ( 1 - dUmin) * vtDir1).IsSmall()) {
m_Info.IciA[0].dU = 1 ;
m_Info.IciB[0].dU = ( bEqVers ? 0 : 1) ;
m_Info.IciA[0].ptI = ptS1 + m_Info.IciA[0].dU * vtDir1 ;
m_Info.IciB[0].ptI = ptS2 + m_Info.IciB[0].dU * vtDir2 ;
m_Info.IciA[0].nPrevTy = ICCT_NULL ;
m_Info.IciA[0].nNextTy = ICCT_NULL ;
m_Info.IciB[0].nPrevTy = ICCT_NULL ;
m_Info.IciB[0].nNextTy = ICCT_NULL ;
m_Info.bOverlap = false ;
m_bOverlaps = false ;
m_nNumInters = 1 ;
return ;
}
// esterni -> nessuna intersezione
else if ( dUmax < 0 || 1 < dUmin) {
return ;
}
// altrimenti si sovrappongono -> tratto comune
else {
// devo prendere il massimo dei minimi
if ( dUmin > 0) {
m_Info.IciA[0].dU = dUmin ;
m_Info.IciB[0].dU = ( bEqVers ? 0 : 1) ;
}
else {
m_Info.IciA[0].dU = 0 ;
m_Info.IciB[0].dU = ScalarXY( ( ptS1 - ptS2), vtDir2) / vtDir2.SqLenXY() ;
}
m_Info.IciA[0].ptI = ptS1 + m_Info.IciA[0].dU * vtDir1 ;
m_Info.IciB[0].ptI = ptS2 + m_Info.IciB[0].dU * vtDir2 ;
m_Info.IciA[0].nPrevTy = ICCT_NULL ;
m_Info.IciA[0].nNextTy = ICCT_ON ;
if ( bEqVers) {
m_Info.IciB[0].nPrevTy = ICCT_NULL ;
m_Info.IciB[0].nNextTy = ICCT_ON ;
}
else {
m_Info.IciB[0].nPrevTy = ICCT_ON ;
m_Info.IciB[0].nNextTy = ICCT_NULL ;
}
// e il minimo dei massimi
if ( dUmax < 1) {
m_Info.IciA[1].dU = dUmax ;
m_Info.IciB[1].dU = ( bEqVers ? 1 : 0) ;
}
else {
m_Info.IciA[1].dU = 1 ;
m_Info.IciB[1].dU = ScalarXY( ( ptS1 + vtDir1 - ptS2), vtDir2) / vtDir2.SqLenXY() ;
}
m_Info.IciA[1].ptI = ptS1 + m_Info.IciA[1].dU * vtDir1 ;
m_Info.IciB[1].ptI = ptS2 + m_Info.IciB[1].dU * vtDir2 ;
m_Info.IciA[1].nPrevTy = ICCT_ON ;
m_Info.IciA[1].nNextTy = ICCT_NULL ;
if ( bEqVers) {
m_Info.IciB[1].nPrevTy = ICCT_ON ;
m_Info.IciB[1].nNextTy = ICCT_NULL ;
}
else {
m_Info.IciB[1].nPrevTy = ICCT_NULL ;
m_Info.IciB[1].nNextTy = ICCT_ON ;
}
m_Info.bOverlap = true ;
m_Info.bCBOverEq = bEqVers ;
m_bOverlaps = true ;
m_nNumInters = 1 ;
return ;
}
}