diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc
index ad44150..1d3afc6 100644
Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ
diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj
index aa3d012..8a8b939 100644
--- a/EgtGeomKernel.vcxproj
+++ b/EgtGeomKernel.vcxproj
@@ -321,6 +321,7 @@ copy $(TargetPath) \EgtProg\Dll64
+
@@ -401,6 +402,7 @@ copy $(TargetPath) \EgtProg\Dll64
+
diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters
index e5563e0..ccbe36b 100644
--- a/EgtGeomKernel.vcxproj.filters
+++ b/EgtGeomKernel.vcxproj.filters
@@ -330,6 +330,9 @@
File di origine\GeoCollision
+
+ File di origine\GeoOffset
+
@@ -737,6 +740,9 @@
File di intestazione\Include
+
+ File di intestazione\Include
+
diff --git a/OffsetCurve.cpp b/OffsetCurve.cpp
index 9ea3da0..32650a9 100644
--- a/OffsetCurve.cpp
+++ b/OffsetCurve.cpp
@@ -1,7 +1,7 @@
//----------------------------------------------------------------------------
// EgalTech 2015-2015
//----------------------------------------------------------------------------
-// File : CurveOffsetAdv.cpp Data : 23.09.15 Versione : 1.6i8
+// File : OffsetCurve.cpp Data : 23.09.15 Versione : 1.6i8
// Contenuto : Classe per offset avanzato di Curve.
//
//
diff --git a/OffsetCurveOnX.cpp b/OffsetCurveOnX.cpp
new file mode 100644
index 0000000..2bd3993
--- /dev/null
+++ b/OffsetCurveOnX.cpp
@@ -0,0 +1,466 @@
+//----------------------------------------------------------------------------
+// EgalTech 2016-2016
+//----------------------------------------------------------------------------
+// File : OffsetCurveOnX.cpp Data : 02.04.16 Versione : 1.6o4
+// Contenuto : Classe per offset di Curve lungo la sola X.
+//
+//
+//
+// Modifiche : 02.04.16 DS Creazione modulo.
+//
+//
+//----------------------------------------------------------------------------
+
+//--------------------------- Include ----------------------------------------
+#include "stdafx.h"
+#include "CurveComposite.h"
+#include "CurveLine.h"
+#include "CurveArc.h"
+#include "GeoConst.h"
+#include "/EgtDev/Include/EgkOffsetCurveOnX.h"
+#include "/EgtDev/Include/EgkIntersCurves.h"
+#include "/EgtDev/Include/EGkDistPointCurve.h"
+#include "/EgtDev/Include/EgtPointerOwner.h"
+#include
+
+using namespace std ;
+
+//----------------------------------------------------------------------------
+static bool SplitLeftRightArcs( CurveComposite& cCompo) ;
+static bool SimpleOffsetOnX( ICurve* pCrv, double dDist) ;
+static bool VerifyAndAdjustSamePoint( ICurve* pCrv1, ICurve* pCrv2) ;
+static bool VerifyAndAdjustInternalAngle( ICurve* pCrv1, ICurve* pCrv2) ;
+static bool SafeDist( double dDist, double dCoeff, ICurve* pCrv1, ICurve* pCrv2) ;
+
+
+//----------------------------------------------------------------------------
+OffsetCurveOnX::~OffsetCurveOnX( void)
+{
+ for ( auto& pCrv : m_CrvLst) {
+ if ( pCrv != nullptr) {
+ delete pCrv ;
+ pCrv = nullptr ;
+ }
+ }
+ m_CrvLst.clear() ;
+}
+
+//----------------------------------------------------------------------------
+bool
+OffsetCurveOnX::Make( const ICurve* pCrv, double dDist)
+{
+ // verifico che la curva esista e sia piana
+ Plane3d plPlane ;
+ if ( pCrv == nullptr || ! pCrv->IsFlat( plPlane))
+ return false ;
+ // se esiste estrusione, verifico sia perpendicolare al piano della curva
+ Vector3d vtExtr ;
+ if ( pCrv->GetExtrusion( vtExtr) && ! vtExtr.IsSmall()) {
+ if ( ! AreSameOrOppositeVectorApprox( plPlane.vtN, vtExtr))
+ return false ;
+ }
+ else
+ vtExtr = plPlane.vtN ;
+
+ // determino se necessario cambiare riferimento ( dal vettore estrusione)
+ bool bNeedRef = ( ! vtExtr.IsZplus()) ;
+
+ // creo una copia della curva
+ CurveComposite ccCopy ;
+ if ( ! ccCopy.CopyFrom( pCrv))
+ return false ;
+ ccCopy.SetExtrusion( vtExtr) ;
+
+ // se necessario cambio il riferimento
+ Frame3d frExtr ;
+ if ( bNeedRef) {
+ // calcolo il riferimento OCS con VtExtr come asse Z
+ if ( ! frExtr.Set( ORIG, vtExtr))
+ return false ;
+ // esprimo la curva in questo riferimento
+ ccCopy.ToLoc( frExtr) ;
+ }
+
+ // verifico che la curva sia fatta solo da rette e archi che giacciono nel piano XY (VtExtr è ora Z+)
+ if ( ! ccCopy.ArcsBezierCurvesToArcsPerpExtr( 10 * EPS_SMALL, ANG_TOL_STD_DEG))
+ return false ;
+
+ // spezzo eventuali archi che cambiano pendenza
+ if ( ! SplitLeftRightArcs( ccCopy))
+ return false ;
+
+ // verifico se curva chiusa
+ bool bClosed = ccCopy.IsClosed() ;
+
+ // Primo passo : estraggo entità dalla copia ed eseguo opportuno offset orizzontale
+ CurveComposite ccCopy2 ;
+ if ( ! ccCopy2.CopyFrom( &ccCopy))
+ return false ;
+ // indice della prima curva (1-based, per poter assegnare un significato al segno)
+ int nInd1 = 1 ;
+ // recupero la prima curva e la processo
+ PtrOwner pCrv1( ccCopy2.RemoveFirstOrLastCurve( false)) ;
+ if ( IsNull( pCrv1))
+ return false ;
+ // eseguo semplice offset orizzontale
+ pCrv1->SetTempProp( nInd1) ;
+ SimpleOffsetOnX( Get( pCrv1), dDist) ;
+ // curve successive
+ PtrOwner pCrv2( ccCopy2.RemoveFirstOrLastCurve( false)) ;
+ while ( ! IsNull( pCrv2)) {
+ // eseguo semplice offset
+ pCrv2->SetTempProp( nInd1 + 1) ;
+ SimpleOffsetOnX( Get( pCrv2), dDist) ;
+ // metto in lista curva precedente
+ m_CrvLst.push_back( Release( pCrv1)) ;
+ // aggiorno curva precedente
+ ++ nInd1 ;
+ pCrv1.Set( Release( pCrv2)) ;
+ // passo alla curva successiva
+ pCrv2.Set( ccCopy2.RemoveFirstOrLastCurve( false)) ;
+ }
+ // Metto in lista l'ultima curva rimasta
+ if ( ! IsNull( pCrv1))
+ m_CrvLst.push_back( Release( pCrv1)) ;
+
+ // Secondo passo : taglio angoli tipo interni
+ ICurve* pPrev = nullptr ;
+ if ( bClosed && ! m_CrvLst.empty())
+ pPrev = m_CrvLst.back() ;
+ for ( auto iIter = m_CrvLst.begin() ; iIter != m_CrvLst.end() ;) {
+ ICurve* pCrv = *iIter ;
+ // gestione e verifica di estremi quasi coincidenti ed angoli interni
+ if ( pPrev != nullptr) {
+ if ( ! VerifyAndAdjustSamePoint( pPrev, pCrv))
+ VerifyAndAdjustInternalAngle( pPrev, pCrv) ;
+ }
+ // passo al successivo
+ pPrev = pCrv ;
+ ++ iIter ;
+ }
+
+ // Terzo passo : conversione in curva composita chiudendo gli eventuali buchi con rette
+ PtrOwner pCrvCompo( CreateBasicCurveComposite()) ;
+ if ( IsNull( pCrvCompo))
+ return false ;
+ Point3d ptPrec ;
+ if ( ! m_CrvLst.empty())
+ m_CrvLst.front()->GetStartPoint( ptPrec) ;
+ for ( auto& pCrv : m_CrvLst) {
+ // se punto iniziale diverso da precedente, inserisco segmento di collegamento
+ Point3d ptStart ;
+ pCrv->GetStartPoint( ptStart) ;
+ if ( ! AreSamePointApprox( ptPrec, ptStart)) {
+ CurveLine crvLine ;
+ crvLine.Set( ptPrec, ptStart) ;
+ pCrvCompo->AddCurve( crvLine) ;
+ }
+ // salvo punto finale come nuovo precedente
+ pCrv->GetEndPoint( ptPrec) ;
+ // aggiungo la curva alla composita
+ pCrvCompo->AddCurve( pCrv) ;
+ pCrv = nullptr ;
+ }
+ m_CrvLst.clear() ;
+ // se curva chiusa, verifico anche gap tra inizio e fine
+ if ( bClosed)
+ pCrvCompo->Close() ;
+ // unisco tutte le curve possibili
+ pCrvCompo->MergeCurves( 10 * EPS_SMALL, ANG_TOL_STD_DEG) ;
+
+ // se non rimasto nulla, esco
+ double dLen ;
+ if ( ! pCrvCompo->IsValid() || ! pCrvCompo->GetLength( dLen) || dLen < 10 * EPS_SMALL)
+ return true ;
+ // inserisco la curva nella lista
+ m_CrvLst.push_back( Release( pCrvCompo)) ;
+ CurveComposite* pCompo1 = GetBasicCurveComposite( m_CrvLst.front()) ;
+
+ // Quarto passo : spezzatura della curva composita negli eventuali punti di auto-intersezione
+ // calcolo le auto-intersezioni
+ SelfIntersCurve sintC( *pCompo1) ;
+ DBLVECTOR vU ;
+ IntCrvCrvInfo iccInfo ;
+ for ( int i = 0 ; sintC.GetIntCrvCrvInfo( i, iccInfo) ; ++ i) {
+ if ( ! iccInfo.bOverlap) {
+ vU.push_back( iccInfo.IciA[0].dU) ;
+ vU.push_back( iccInfo.IciB[0].dU) ;
+ }
+ else {
+ vU.push_back( iccInfo.IciA[0].dU) ;
+ vU.push_back( iccInfo.IciA[1].dU) ;
+ vU.push_back( iccInfo.IciB[0].dU) ;
+ vU.push_back( iccInfo.IciB[1].dU) ;
+ }
+ }
+ // ordino il vettore in senso crescente
+ sort( vU.begin(), vU.end(), less()) ;
+ // calcolo il vettore delle lunghezze di ogni parte di curva
+ DBLVECTOR vLen ;
+ for ( const auto& dU : vU) {
+ double dULen ;
+ pCompo1->GetLengthAtParam( dU, dULen) ;
+ vLen.push_back( dULen) ;
+ }
+ // se ultima parte molto piccola, la elimino
+ if ( ! vU.empty() && ( dLen - vLen.back()) < 2 * EPS_SMALL) {
+ vU.pop_back() ;
+ vLen.pop_back() ;
+ }
+ // eseguo la divisione
+ int nCount = 1 ;
+ double dUPrev = 0 ;
+ double dLenPrev = 0 ;
+ for ( int i = 0 ; i < int( vU.size()) ; ++ i) {
+ // se lunghezza della curva risulta piccola, salto
+ if ( ( vLen[i] - dLenPrev) < 2 * EPS_SMALL)
+ continue ;
+ // copio la curva
+ PtrOwner pCopy( pCompo1->Clone()) ;
+ if ( IsNull( pCopy))
+ return false ;
+ m_CrvLst.push_back( Release( pCopy)) ;
+ ++ nCount ;
+ // trimmo l'originale
+ pCompo1->TrimStartEndAtParam( dUPrev, vU[i]) ;
+ // la copia diventa il nuovo corrente
+ pCompo1 = GetBasicCurveComposite( m_CrvLst.back()) ;
+ dUPrev = vU[i] ;
+ dLenPrev = vLen[i] ;
+ }
+ // se fatta almeno una suddivisione, trimmo l'ultima parte
+ if ( dUPrev > EPS_PARAM)
+ pCompo1->TrimStartAtParam( dUPrev) ;
+
+ // Quinto passo : elimino le parti che sono troppo vicine al percorso originale
+ for ( auto iIter = m_CrvLst.begin() ; iIter != m_CrvLst.end() ;) {
+ ICurve* pCrv = *iIter ;
+ // distanza minima di alcuni punti interni della curva dalla curva originale
+ if ( ! SafeDist( dDist, 0.5, pCrv, &ccCopy) ||
+ ! SafeDist( dDist, 0.25, pCrv, &ccCopy) ||
+ ! SafeDist( dDist, 0.75, pCrv, &ccCopy)) {
+ delete pCrv ;
+ iIter = m_CrvLst.erase( iIter) ;
+ continue ;
+ }
+ // passo alla successiva
+ ++ iIter ;
+ }
+
+ // Sesto passo : concateno i percorsi risultanti (senza cambiare verso)
+ for ( auto iIter = m_CrvLst.begin() ; iIter != m_CrvLst.end() ;) {
+ CurveComposite* pCrvCo = GetBasicCurveComposite( *iIter) ;
+ // recupero punti iniziale e finale della curva
+ Point3d ptStart, ptEnd ;
+ pCrvCo->GetStartPoint( ptStart) ;
+ pCrvCo->GetEndPoint( ptEnd) ;
+ // ciclo sulle curve successive per verificare se possibile concatenamento
+ for ( auto iIter2 = next( iIter) ; iIter2 != m_CrvLst.end() ;) {
+ CurveComposite* pCrvCo2 = GetBasicCurveComposite( *iIter2) ;
+ // recupero punti iniziale e finale della curva
+ Point3d ptStart2, ptEnd2 ;
+ pCrvCo2->GetStartPoint( ptStart2) ;
+ pCrvCo2->GetEndPoint( ptEnd2) ;
+ // verifiche di concatenamento
+ if ( AreSamePointEpsilon( ptEnd, ptStart2, 10 * EPS_SMALL)) {
+ pCrvCo->AddCurve( pCrvCo2, true, 10 * EPS_SMALL) ;
+ m_CrvLst.erase( iIter2) ;
+ ptEnd = ptEnd2 ;
+ iIter2 = next( iIter) ;
+ }
+ else if ( AreSamePointEpsilon( ptEnd2, ptStart, 10 * EPS_SMALL)) {
+ pCrvCo->AddCurve( pCrvCo2, false, 10 * EPS_SMALL) ;
+ m_CrvLst.erase( iIter2) ;
+ ptStart = ptStart2 ;
+ iIter2 = next( iIter) ;
+ }
+ else
+ ++ iIter2 ;
+ }
+ ++ iIter ;
+ }
+
+ // riporto il risultato nel riferimento originale
+ if ( bNeedRef) {
+ for ( auto pCrv : m_CrvLst)
+ pCrv->ToGlob( frExtr) ;
+ }
+
+ return true ;
+}
+
+//----------------------------------------------------------------------------
+ICurve*
+OffsetCurveOnX::GetCurve( void)
+{
+ if ( m_CrvLst.empty())
+ return nullptr ;
+ ICurve* pCrv = m_CrvLst.front() ;
+ m_CrvLst.pop_front() ;
+ return pCrv ;
+}
+
+//----------------------------------------------------------------------------
+ICurve*
+OffsetCurveOnX::GetLongerCurve( void)
+{
+ if ( m_CrvLst.empty())
+ return nullptr ;
+ // cerco la curva più lunga
+ double dMaxLen = 0 ;
+ auto iMaxIter = m_CrvLst.end() ;
+ for ( auto iIter = m_CrvLst.begin() ; iIter != m_CrvLst.end() ; ++ iIter) {
+ double dLen ;
+ if ( (*iIter)->GetLength( dLen) && dLen > dMaxLen) {
+ dMaxLen = dLen ;
+ iMaxIter = iIter ;
+ }
+ }
+ // se trovata
+ if ( iMaxIter != m_CrvLst.end()) {
+ ICurve* pCrv = (*iMaxIter) ;
+ m_CrvLst.erase( iMaxIter) ;
+ return pCrv ;
+ }
+
+ return nullptr ;
+}
+
+//----------------------------------------------------------------------------
+bool
+SplitLeftRightArcs( CurveComposite& cCompo)
+{
+ int i = 0 ;
+ const ICurve* pCrv = cCompo.GetCurve( i) ;
+ while ( pCrv != nullptr) {
+ if ( pCrv->GetType() == CRV_ARC) {
+ const CurveArc* pArc = GetBasicCurveArc( pCrv) ;
+ // determino la rotazione angolare dall'inizio alle direzioni su e giù
+ double dAng1, dAng2 ;
+ bool bDet ;
+ pArc->GetStartVersor().GetRotation( Y_AX, Z_AX, dAng1, bDet) ;
+ pArc->GetStartVersor().GetRotation( - Y_AX, Z_AX, dAng2, bDet) ;
+ // oriento queste rotazioni come l'angolo al centro dell'arco
+ if ( pArc->GetAngCenter() > 0) {
+ if ( dAng1 < 0)
+ dAng1 += ANG_FULL ;
+ if ( dAng2 < 0)
+ dAng2 += ANG_FULL ;
+ }
+ else {
+ if ( dAng1 > 0)
+ dAng1 -= ANG_FULL ;
+ if ( dAng2 > 0)
+ dAng2 -= ANG_FULL ;
+ }
+ // le ordino in senso crescente di ampiezza assoluta
+ if ( abs( dAng1) > abs( dAng2))
+ swap( dAng1, dAng2) ;
+ // verifico se la prima di queste rotazioni è compresa nell'arco
+ if ( abs( dAng1) > EPS_ANG_SMALL && abs( dAng1) < abs( pArc->GetAngCenter()) - EPS_ANG_SMALL) {
+ cCompo.AddJoint( i + dAng1 / pArc->GetAngCenter()) ;
+ }
+ // verifico la seconda
+ else if ( abs( dAng2) > EPS_ANG_SMALL && abs( dAng2) < abs( pArc->GetAngCenter()) - EPS_ANG_SMALL) {
+ cCompo.AddJoint( i + dAng2 / pArc->GetAngCenter()) ;
+ }
+ }
+ // passo alla successiva
+ pCrv = cCompo.GetCurve( ++i) ;
+ }
+ return true ;
+}
+
+//----------------------------------------------------------------------------
+bool
+SimpleOffsetOnX( ICurve* pCrv, double dDist)
+{
+ Point3d ptStart, ptEnd ;
+ pCrv->GetStartPoint( ptStart) ;
+ pCrv->GetEndPoint( ptEnd) ;
+ if ( abs( ptStart.y - ptEnd.y) < EPS_SMALL)
+ ;
+ else if ( ptStart.y < ptEnd.y)
+ pCrv->Translate( Vector3d( dDist, 0, 0)) ;
+ else
+ pCrv->Translate( Vector3d( - dDist, 0, 0)) ;
+ return true ;
+}
+
+
+
+
+//----------------------------------------------------------------------------
+bool
+VerifyAndAdjustSamePoint( ICurve* pCrv1, ICurve* pCrv2)
+{
+ // verifica dei puntatori
+ if ( pCrv1 == nullptr || pCrv2 == nullptr)
+ return false ;
+
+ // calcolo dei punti estremi (finale per prima curva, iniziale per seconda)
+ Point3d ptP1, ptP2 ;
+ if ( ! pCrv1->GetEndPoint( ptP1) || ! pCrv2->GetStartPoint( ptP2))
+ return false ;
+ // verifica distanza tra estremi
+ if ( ! AreSamePointXYEpsilon( ptP1, ptP2, 10 * EPS_SMALL))
+ return false ;
+ // se coincidono esattamente, va bene così
+ if ( AreSamePointExact( ptP1, ptP2))
+ return true ;
+ // sono in tolleranza, ma devo ricongiungere gli estremi
+ Point3d ptMid = 0.5 * ( ptP1 + ptP2) ;
+ return ( pCrv1->ModifyEnd( ptMid) && pCrv2->ModifyStart( ptMid)) ;
+}
+
+//----------------------------------------------------------------------------
+bool
+VerifyAndAdjustInternalAngle( ICurve* pCrv1, ICurve* pCrv2)
+{
+ // verifica dei puntatori
+ if ( pCrv1 == nullptr || pCrv2 == nullptr)
+ return false ;
+
+ // calcolo l'intersezione tra le due curve
+ IntersCurveCurve intCC( *pCrv1, *pCrv2) ;
+ if ( intCC.GetIntersCount() == 0)
+ return false ;
+ // prendo l'intersezione più vicina al punto medio tra gli estremi delle curve
+ Point3d ptP1, ptP2 ;
+ if ( ! pCrv1->GetEndPoint( ptP1) || ! pCrv2->GetStartPoint( ptP2))
+ return false ;
+ Point3d ptMid = 0.5 * ( ptP1 + ptP2) ;
+ Point3d ptNew1, ptNew2 ;
+ if ( ! intCC.GetIntersPointNearTo( 0, ptMid, ptNew1) ||
+ ! intCC.GetIntersPointNearTo( 1, ptMid, ptNew2))
+ return false ;
+ // modifico le due curve sul punto medio di intersezione
+ Point3d ptNew = 0.5 * ( ptNew1 + ptNew2) ;
+ return ( pCrv1->ModifyEnd( ptNew) && pCrv2->ModifyStart( ptNew)) ;
+}
+
+//----------------------------------------------------------------------------
+bool
+SafeDist( double dDist, double dCoeff, ICurve* pCrv1, ICurve* pCrv2)
+{
+ // calcolo il punto e due vicini
+ double dUStart, dUEnd ;
+ pCrv1->GetDomain( dUStart, dUEnd) ;
+ double dU = dCoeff * dUStart + ( 1 - dCoeff) * dUEnd ;
+ Point3d ptP ;
+ pCrv1->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP) ;
+ Point3d ptPrev, ptNext ;
+ Vector3d vtPrev, vtNext ;
+ pCrv1->GetPointTang( dU - 100 * EPS_PARAM, ICurve::FROM_MINUS, ptPrev, vtPrev) ;
+ pCrv1->GetPointTang( dU + 100 * EPS_PARAM, ICurve::FROM_PLUS, ptNext, vtNext) ;
+ // non si considerano i tratti orizzontali
+ if ( abs( vtPrev.y) < EPS_SMALL || abs( vtNext.y) < EPS_SMALL)
+ return true ;
+ // segmento orizzontale di prova centrato sul punto e lungo dDist + dDist
+ Vector3d vtDelta( abs(dDist) - 5 * EPS_SMALL, 0, 0) ;
+ CurveLine Line ;
+ Line.Set( ptP - vtDelta, ptP + vtDelta) ;
+ // interseco il segmento di test con la curva originale
+ IntersCurveCurve IntCC( Line, *pCrv2) ;
+ return ( IntCC.GetIntersCount() == 0) ;
+}