From e3b4f5bd2db3739a5abbc42a9668188b80cca2d8 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 11 Nov 2025 11:53:13 +0100 Subject: [PATCH] EgtGeomKernel : - aggiunta la classe per l'intersezione curva-piano. --- EgtGeomKernel.vcxproj | 1 + EgtGeomKernel.vcxproj.filters | 3 + IntersCurvePlane.cpp | 445 ++++++++++++++++++++++++++++++++++ 3 files changed, 449 insertions(+) create mode 100644 IntersCurvePlane.cpp diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index 1ea9170..5fe8537 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -312,6 +312,7 @@ copy $(TargetPath) \EgtProg\Dll64 + false false diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index 2a98ac7..e07bdb6 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -558,6 +558,9 @@ File di origine\GeoDist + + File di origine\GeoInters + diff --git a/IntersCurvePlane.cpp b/IntersCurvePlane.cpp new file mode 100644 index 0000000..a3aaeb7 --- /dev/null +++ b/IntersCurvePlane.cpp @@ -0,0 +1,445 @@ +//---------------------------------------------------------------------------- +// 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 + +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 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, *pCalcCrv, 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() +{ + if( m_Info.size() < 2) + return ; + // 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 ; + // 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) ; + } + // 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) ; + } + } + if ( 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 ; + } + } + } +} + + +//---------------------------------------------------------------------------- +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::GetIntersPointNearTo( int nCrv, const Point3d& ptNear, Point3d& ptI) +{ + if ( m_nIntersCount == 0 || nCrv < 0 || nCrv > 1) + 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 ; + 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 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 ; + 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 ; +} \ No newline at end of file