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