951d3781d6
- in IntersCurvePlane aggiunta implementazione funzione GetIntCrvPlnInfo.
459 lines
17 KiB
C++
459 lines
17 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2025
|
|
//----------------------------------------------------------------------------
|
|
// File : IntersCurvePlane.cpp Data : 07.11.25 Versione : 2.7k1
|
|
// Contenuto : Implementazione della classe intersezione curva-piano.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 07.11.25 DB Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
#include "stdafx.h"
|
|
#include "GeoConst.h"
|
|
#include "CurveLine.h"
|
|
#include "CurveComposite.h"
|
|
#include "IntersLineLine.h"
|
|
#include "IntersLineArc.h"
|
|
#include "IntersArcArc.h"
|
|
#include "IntersCrvCompoCrvCompo.h"
|
|
#include "/EgtDev/Include/EGkIntersCurves.h"
|
|
#include "/EgtDev/Include/EGkIntersLinePlane.h"
|
|
#include "/EgtDev/Include/EGkIntersCurvePlane.h"
|
|
#include "/EgtDev/Include/EGkDistPointCurve.h"
|
|
#include "/EgtDev/Include/EGkPlane3d.h"
|
|
#include "/EgtDev/Include/EgtPointerOwner.h"
|
|
#include <algorithm>
|
|
|
|
using namespace std ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
IntersCurvePlane::IntersCurvePlane( const ICurve& Curve, const Point3d& ptOrig, const Vector3d& vtN)
|
|
{
|
|
// Le intersezioni sono calcolate nel piano XY locale.
|
|
// Il flag bAreSegments vale solo per intersezione tra due linee e riguarda entrambe.
|
|
|
|
// inizializzazioni
|
|
m_nIntersCount = 0 ;
|
|
m_pCurve = &Curve ;
|
|
m_plPlane.Set( ptOrig, vtN) ;
|
|
|
|
// puntatore alla curva usata nei calcoli (originali o temporanee)
|
|
const ICurve* pCalcCrv ;
|
|
// per eventuale esplosione temporanea delle curve
|
|
PtrOwner<ICurve> pTmpCrv ;
|
|
|
|
// se curva è arco da approssimare oppure è curva di Bezier
|
|
if ( m_pCurve->GetType() == CRV_ARC || m_pCurve->GetType() == CRV_BEZIER || m_pCurve->GetType() == CRV_COMPO) {
|
|
// approssimo con rette
|
|
PolyLine PL ;
|
|
if ( ! m_pCurve->ApproxWithLines( EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL))
|
|
return ;
|
|
pTmpCrv.Set( CreateBasicCurveComposite()) ;
|
|
if ( IsNull( pTmpCrv))
|
|
return ;
|
|
if ( ! GetBasicCurveComposite( pTmpCrv)->FromPolyLine( PL))
|
|
return ;
|
|
pCalcCrv = pTmpCrv ;
|
|
}
|
|
else
|
|
pCalcCrv = m_pCurve ;
|
|
|
|
m_Info.clear() ;
|
|
if ( pCalcCrv->GetType() == CRV_LINE) {
|
|
CalcIntersLinePlane( m_plPlane, *pCalcCrv) ;
|
|
}
|
|
else if ( pCalcCrv->GetType() == CRV_COMPO){
|
|
for ( int i = 0 ; i < GetBasicCurveComposite( pCalcCrv)->GetCurveCount(); ++i) {
|
|
const ICurve& subCurve = *GetBasicCurveComposite( pCalcCrv)->GetCurve( i) ;
|
|
CalcIntersLinePlane( m_plPlane, subCurve, i) ;
|
|
}
|
|
OrderAndCompleteIntersections() ;
|
|
}
|
|
|
|
// per curve approssimate, sistemo...
|
|
AdjustIntersParams( pCalcCrv != m_pCurve) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
IntersCurvePlane::CalcIntersLinePlane( const Plane3d& plPlane, const ICurve& Curve, int nCrv)
|
|
{
|
|
if ( Curve.GetType() != CRV_LINE)
|
|
return false ;
|
|
Point3d ptStart ; Curve.GetStartPoint( ptStart) ;
|
|
Point3d ptEnd ; Curve.GetEndPoint( ptEnd) ;
|
|
Point3d ptInt ;
|
|
double dLen = 0 ; Curve.GetLength( dLen) ;
|
|
int nIntersType = IntersLinePlane( ptStart, ptEnd, m_plPlane, ptInt, true) ;
|
|
// intersezione con attraversamento
|
|
if ( nIntersType == ILPT_YES) {
|
|
IntCrvPlnInfo icpi ;
|
|
icpi.Ici[0].ptI = ptInt ;
|
|
icpi.Ici[0].dU = Dist( ptInt, ptStart) / dLen + nCrv ;
|
|
Vector3d vtPos = ptStart - m_plPlane.GetPoint() ;
|
|
icpi.Ici[0].nPrevTy = vtPos * m_plPlane.GetVersN() > 0 ? ICPT_OUT : ICPT_IN ;
|
|
icpi.Ici[0].nNextTy = icpi.Ici[0].nPrevTy == ICPT_IN ? ICPT_OUT : ICPT_IN ;
|
|
m_Info.push_back( icpi) ;
|
|
}
|
|
// intersezione con tocco
|
|
else if ( nIntersType == ILPT_START || nIntersType == ILPT_END) {
|
|
IntCrvPlnInfo icpi ;
|
|
icpi.Ici[0].ptI = ptInt ;
|
|
icpi.Ici[0].dU = nIntersType == ILPT_START ? 0 : 1 + nCrv ;
|
|
|
|
if ( nIntersType == ILPT_START) {
|
|
Vector3d vtPos = ptEnd - m_plPlane.GetPoint() ;
|
|
icpi.Ici[0].nNextTy = vtPos * m_plPlane.GetVersN() > 0 ? ICPT_OUT : ICPT_IN ;
|
|
icpi.Ici[0].nPrevTy = ICPT_NULL ;
|
|
}
|
|
else {
|
|
Vector3d vtPos = ptStart - m_plPlane.GetPoint() ;
|
|
icpi.Ici[0].nPrevTy = vtPos * m_plPlane.GetVersN() > 0 ? ICPT_OUT : ICPT_IN ;
|
|
icpi.Ici[0].nNextTy = ICPT_NULL ;
|
|
}
|
|
m_Info.push_back( icpi) ;
|
|
}
|
|
// intersezione con sovrapposizione
|
|
else if ( nIntersType == ILPT_INPLANE) {
|
|
IntCrvPlnInfo icpi ;
|
|
icpi.bOverlap = true ;
|
|
icpi.Ici[0].ptI = ptStart ;
|
|
icpi.Ici[0].dU = 0 + nCrv;
|
|
icpi.Ici[1].ptI = ptEnd ;
|
|
icpi.Ici[1].dU = 1 + nCrv ;
|
|
icpi.Ici[0].nPrevTy = ICPT_NULL ;
|
|
icpi.Ici[0].nNextTy = ICPT_ON ;
|
|
icpi.Ici[1].nPrevTy = ICPT_ON ;
|
|
icpi.Ici[1].nNextTy = ICPT_NULL ;
|
|
m_Info.push_back( icpi) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
IntersCurvePlane::OrderAndCompleteIntersections()
|
|
{
|
|
// cancello le interesezioni puntuali adiacenti a tratti di sovrapposizione
|
|
// riempio le info PrevTy e NexyTy
|
|
sort( m_Info.begin(), m_Info.end(), []( IntCrvPlnInfo& icpA, IntCrvPlnInfo& icpB) { return icpA.Ici[0].dU < icpA.Ici[0].dU ;}) ;
|
|
for ( int curr = m_Info.size() - 1 ; curr > - 1 ; --curr) {
|
|
int prev = curr == 0 ? m_Info.size() - 1 : curr - 1 ;
|
|
int next = curr == m_Info.size() - 1 ? 0 : curr + 1 ;
|
|
bool bErasedCurr = false ;
|
|
// solo le intersezioni di sovrapposizione o puntuali sullo start o end delle curve possono avere il PrevTy o NextTy non definito
|
|
if ( ! m_Info[curr].bOverlap) {
|
|
if ( m_Info[curr].Ici[0].nPrevTy == ICPT_NULL) {
|
|
if ( ! m_Info[prev].bOverlap) {
|
|
m_Info[curr].Ici[0].nPrevTy = m_Info[prev].Ici[0].nNextTy ;
|
|
// se ho due puntuali che coincidono cancello il successivo tra i due ( corrente)
|
|
if ( AreSamePointApprox( m_Info[curr].Ici[0].ptI, m_Info[prev].Ici[0].ptI)) {
|
|
m_Info.erase(m_Info.begin() + curr) ;
|
|
bErasedCurr = true ;
|
|
}
|
|
}
|
|
// se ho un'intersezione puntuale che in realtà è la fine di un tratto di sovrapposizione, la cancello
|
|
else {
|
|
m_Info[prev].Ici[1].nNextTy = m_Info[curr].Ici[0].nNextTy ;
|
|
m_Info.erase(m_Info.begin() + curr) ;
|
|
bErasedCurr = true ;
|
|
}
|
|
}
|
|
if ( ! bErasedCurr && m_Info[curr].Ici[0].nNextTy == ICPT_NULL){
|
|
if ( ! m_Info[prev].bOverlap)
|
|
m_Info[curr].Ici[0].nNextTy = m_Info[next].Ici[0].nPrevTy ;
|
|
// se ho un'intersezione puntuale che in realtà è la fine di un tratto di sovrapposizione, la cancello
|
|
else {
|
|
m_Info[next].Ici[0].nPrevTy = m_Info[curr].Ici[0].nPrevTy ;
|
|
m_Info.erase(m_Info.begin() + curr) ;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if ( m_Info[curr].Ici[0].nPrevTy == ICPT_NULL) {
|
|
if ( ! m_Info[prev].bOverlap)
|
|
m_Info[curr].Ici[0].nPrevTy = m_Info[prev].Ici[0].nNextTy ;
|
|
else
|
|
m_Info[curr].Ici[0].nPrevTy = m_Info[prev].Ici[1].nNextTy ;
|
|
}
|
|
if ( m_Info[curr].Ici[1].nNextTy == ICPT_NULL) {
|
|
if ( ! m_Info[next].bOverlap)
|
|
m_Info[curr].Ici[0].nNextTy = m_Info[prev].Ici[0].nPrevTy ;
|
|
else
|
|
m_Info[curr].Ici[0].nNextTy = m_Info[prev].Ici[1].nPrevTy ;
|
|
}
|
|
}
|
|
}
|
|
m_nIntersCount = m_Info.size() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
IntersCurvePlane::IsArcToApprox( const ICurve& Curve)
|
|
{
|
|
// recupero l'arco
|
|
const CurveArc* pArc = GetBasicCurveArc( &Curve) ;
|
|
if ( pArc == nullptr)
|
|
return false ;
|
|
// verifico se non è nel piano XY o ha più di un giro al centro
|
|
return ( ( ! pArc->GetNormVersor().IsZplus() && ! pArc->GetNormVersor().IsZminus()) ||
|
|
abs( pArc->GetAngCenter()) > ANG_FULL + EPS_ANG_ZERO) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
IntersCurvePlane::AdjustIntersParams( bool bAdjCrv)
|
|
{
|
|
// se non ci sono intersezioni, non va fatto alcunché
|
|
if ( m_Info.empty())
|
|
return true ;
|
|
// se le curve originali non sono state approssimate, non va fatto alcunché
|
|
if ( ! bAdjCrv)
|
|
return true ;
|
|
// procedo ad aggiustare
|
|
for ( auto& aInfo : m_Info) {
|
|
// se curve originali approssimate, devo ricalcolare i parametri dei punti di intersezione
|
|
if ( bAdjCrv) {
|
|
if ( ! m_pCurve->GetParamAtPoint( aInfo.Ici[0].ptI, aInfo.Ici[0].dU, 10 * EPS_SMALL))
|
|
return false ;
|
|
if ( aInfo.bOverlap && ! m_pCurve->GetParamAtPoint( aInfo.Ici[1].ptI, aInfo.Ici[1].dU, 10 * EPS_SMALL))
|
|
return false ;
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int
|
|
IntersCurvePlane::GetIntersCount( void)
|
|
{
|
|
return m_nIntersCount ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
IntersCurvePlane::GetIntCrvPlnInfo( int nInd, IntCrvPlnInfo& aInfo)
|
|
{
|
|
if ( nInd < 0 || nInd >= m_nIntersCount)
|
|
return false ;
|
|
aInfo = m_Info[nInd] ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
IntersCurvePlane::GetIntersPointNearTo( const Point3d& ptNear, Point3d& ptI, double& dParam)
|
|
{
|
|
if ( m_nIntersCount == 0)
|
|
return false ;
|
|
|
|
// ricerca del punto più vicino tra le intersezioni singole
|
|
bool bFound = false ;
|
|
double dMinSqDist = SQ_INFINITO ;
|
|
for ( int i = 0 ; i < m_nIntersCount ; ++ i) {
|
|
// se è un'intersezione singola
|
|
if ( ! m_Info[i].bOverlap) {
|
|
// faccio la verifica sul punto
|
|
Point3d ptP = m_Info[i].Ici[0].ptI ;
|
|
double dSqDist = SqDist( ptNear, ptP) ;
|
|
if ( dSqDist < dMinSqDist) {
|
|
dMinSqDist = dSqDist ;
|
|
ptI = ptP ;
|
|
dParam = m_Info[i].Ici[0].dU ;
|
|
bFound = true ;
|
|
}
|
|
}
|
|
// altrimenti
|
|
else {
|
|
// recupero il tratto di sovrapposizione
|
|
double dUStartTrim, dUEndTrim ;
|
|
dUStartTrim = m_Info[i].Ici[0].dU ;
|
|
dUEndTrim = m_Info[i].Ici[1].dU ;
|
|
PtrOwner<ICurve> pCrv( m_pCurve->CopyParamRange( dUStartTrim, dUEndTrim)) ;
|
|
if ( IsNull( pCrv))
|
|
continue ;
|
|
// cerco il punto
|
|
int nFlag ;
|
|
Point3d ptP ;
|
|
if ( DistPointCurve( ptNear, *pCrv).GetMinDistPoint( 0.5, ptP, nFlag)) {
|
|
// faccio la verifica
|
|
double dSqDist = SqDist( ptNear, ptP) ;
|
|
if ( dSqDist < dMinSqDist) {
|
|
dMinSqDist = dSqDist ;
|
|
ptI = ptP ;
|
|
m_pCurve->GetParamAtPoint( ptP, dParam) ;
|
|
bFound = true ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return bFound ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
IntersCurvePlane::GetCurveClassification( double dLenMin, CRVPLNCVECTOR& ccClass)
|
|
{
|
|
// pulisco vettore classificazioni
|
|
ccClass.clear() ;
|
|
|
|
// verifico definizione della curva
|
|
if ( m_pCurve == nullptr)
|
|
return false ;
|
|
|
|
// se esiste almeno una intersezione
|
|
if ( m_nIntersCount >= 1)
|
|
return CalcCurveClassification( m_pCurve, m_Info, dLenMin, ccClass) ;
|
|
// altrimenti la curva è completamente interna oppure completamente esterna
|
|
else
|
|
return CalcCurveInOrOut( m_pCurve, ccClass) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
IntersCurvePlane::CalcCurveClassification( const ICurve* pCurve, const ICPIVECTOR& Info, double dLenMin, CRVPLNCVECTOR& ccClass)
|
|
{
|
|
// numero intersezioni
|
|
int nNumInters = int( Info.size()) ;
|
|
if ( nNumInters < 1)
|
|
return false ;
|
|
// recupero il dominio parametrico della curva in esame
|
|
double dStartPar, dEndPar ;
|
|
if ( pCurve == nullptr || ! pCurve->GetDomain( dStartPar, dEndPar))
|
|
return false ;
|
|
// limito lunghezza minima
|
|
dLenMin = max( dLenMin, EPS_ZERO) ;
|
|
// elimino intersezioni senza attraversamento che giacciono in intervalli di sovrapposizione
|
|
ICPIVECTOR InfoCorr ;
|
|
InfoCorr.reserve( Info.size()) ;
|
|
for ( size_t i = 0 ; i < Info.size() ; ++ i) {
|
|
// se intersezione puntuale senza attraversamento
|
|
if ( ! Info[i].bOverlap && Info[i].Ici[0].nPrevTy == Info[i].Ici[0].nNextTy) {
|
|
// confronto con le intersezioni con sovrapposizione
|
|
bool bToSkip = false ;
|
|
for ( size_t j = 0 ; j < Info.size() ; ++ j) {
|
|
// se coincide o puntuale
|
|
if ( j == i || ! Info[j].bOverlap)
|
|
continue ;
|
|
// determino l'intervallo parametrico tenendo conto di eventuale avvolgimento attorno all'inizio
|
|
double dU1 = Info[j].Ici[0].dU ;
|
|
double dU2 = Info[j].Ici[1].dU ;
|
|
if ( dU2 < dU1 && pCurve->IsClosed())
|
|
dU2 += dEndPar ;
|
|
// se cade nell'intervallo è da saltare
|
|
if ( Info[i].Ici[0].dU >= dU1 && Info[i].Ici[0].dU <= dU2) {
|
|
bToSkip = true ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( bToSkip)
|
|
continue ;
|
|
}
|
|
// salvo dati intersezione
|
|
InfoCorr.emplace_back( Info[i]) ;
|
|
}
|
|
// aggiorno numero di intersezioni da considerare
|
|
nNumInters = int( InfoCorr.size()) ;
|
|
// recupero la classificazione all'inizio della curva
|
|
int nLastTy = ICCT_NULL ;
|
|
double dCurrPar = dStartPar ;
|
|
double dCurrLen = 0 ;
|
|
double dEndLen ; pCurve->GetLength( dEndLen) ;
|
|
// se è chiusa, recupero come finisce
|
|
if ( pCurve->IsClosed()) {
|
|
if ( ! InfoCorr[nNumInters-1].bOverlap)
|
|
nLastTy = InfoCorr[nNumInters-1].Ici[0].nNextTy ;
|
|
else {
|
|
nLastTy = InfoCorr[nNumInters-1].Ici[1].nNextTy ;
|
|
// se attraversa il punto di giunzione (parametro di fine minore di quello di inizio)
|
|
if ( InfoCorr[nNumInters-1].Ici[1].dU < InfoCorr[nNumInters-1].Ici[0].dU) {
|
|
dCurrPar = InfoCorr[nNumInters-1].Ici[1].dU ;
|
|
double dTmpLen ; pCurve->GetLengthAtParam( dCurrPar, dTmpLen) ;
|
|
dCurrLen = dTmpLen - dEndLen ;
|
|
dEndPar = dCurrPar ;
|
|
dEndLen = dTmpLen ;
|
|
}
|
|
}
|
|
}
|
|
// costruisco il vettore delle classificazioni
|
|
for ( int i = 0 ; i < nNumInters ; ++ i) {
|
|
// se è definito un tratto precedente
|
|
double dLenU ; pCurve->GetLengthAtParam( InfoCorr[i].Ici[0].dU, dLenU) ;
|
|
if ( InfoCorr[i].Ici[0].dU > dCurrPar + EPS_PARAM && dLenU - dCurrLen > dLenMin) {
|
|
// verifico che la definizione sul tratto sia omogenea e valida
|
|
int nPrevTy = InfoCorr[i].Ici[0].nPrevTy ;
|
|
if ( ( nLastTy != ICCT_NULL && nPrevTy != nLastTy) ||
|
|
nPrevTy == ICCT_NULL || nPrevTy == ICCT_ON)
|
|
return false ;
|
|
// assegno i dati
|
|
CrvPlaneClass segClass ;
|
|
segClass.dParS = dCurrPar ;
|
|
segClass.dParE = InfoCorr[i].Ici[0].dU ;
|
|
segClass.nClass = (( nPrevTy == ICCT_IN) ? CRVC_IN : CRVC_OUT) ;
|
|
ccClass.push_back( segClass) ;
|
|
// salvo dati correnti
|
|
dCurrPar = InfoCorr[i].Ici[0].dU ;
|
|
dCurrLen = dLenU ;
|
|
nLastTy = InfoCorr[i].Ici[0].nNextTy ;
|
|
}
|
|
// altrimenti, salvo il tipo
|
|
else
|
|
nLastTy = InfoCorr[i].Ici[0].nNextTy ;
|
|
// se è definito un tratto in sovrapposizione
|
|
if ( InfoCorr[i].bOverlap) {
|
|
// assegno i dati
|
|
CrvPlaneClass segClass ;
|
|
segClass.dParS = dCurrPar ;
|
|
segClass.dParE = InfoCorr[i].Ici[1].dU ;
|
|
segClass.nClass = CRVPLN_ON ;
|
|
ccClass.push_back( segClass) ;
|
|
// salvo dati correnti
|
|
dCurrPar = InfoCorr[i].Ici[1].dU ;
|
|
dCurrLen = dLenU ;
|
|
nLastTy = InfoCorr[i].Ici[1].nNextTy ;
|
|
}
|
|
}
|
|
// eventuale tratto finale rimasto
|
|
if ( dCurrPar < dEndPar - EPS_PARAM && dEndLen - dCurrLen > dLenMin) {
|
|
// verifico che la definizione sul tratto sia valida
|
|
if ( nLastTy == ICCT_NULL || nLastTy == ICCT_ON)
|
|
return false ;
|
|
// assegno i dati
|
|
CrvPlaneClass segClass ;
|
|
segClass.dParS = dCurrPar ;
|
|
segClass.dParE = dEndPar ;
|
|
segClass.nClass = (( nLastTy == ICCT_IN) ? CRVC_IN : CRVC_OUT) ;
|
|
ccClass.push_back( segClass) ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
IntersCurvePlane::CalcCurveInOrOut( const ICurve* pCurve, CRVPLNCVECTOR& ccClass)
|
|
{
|
|
// controllo di non avere intersezioni
|
|
int nNumInters = int( m_Info.size()) ;
|
|
if ( nNumInters > 0)
|
|
return false ;
|
|
|
|
// se non ho intersezioni tra curva e piano devo solo capire da che parte del piano sta la curva
|
|
CrvPlaneClass cpClass ;
|
|
double dStartPar, dEndPar ;
|
|
if ( pCurve == nullptr || ! pCurve->GetDomain( dStartPar, dEndPar))
|
|
return false ;
|
|
Point3d ptStart ; pCurve->GetStartPoint( ptStart) ;
|
|
Vector3d vtCrv = ptStart - m_plPlane.GetPoint() ;
|
|
CrvPlaneClass segClass ;
|
|
segClass.dParS = dStartPar ;
|
|
segClass.dParE = dEndPar ;
|
|
segClass.nClass = ( (vtCrv * m_plPlane.GetVersN() < 0) ? CRVC_IN : CRVC_OUT) ;
|
|
ccClass.push_back( segClass) ;
|
|
return true ;
|
|
} |