From 3c1a7ff1bb547b6d99f3f3611d1bed1a4ac6924d Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Fri, 20 Feb 2026 16:47:42 +0100 Subject: [PATCH 1/2] EgtGeomKernel 3.1b2 : - in Trimming aggiunta prima versione di interpolazione per le curve di sincronizzazione. --- EgtGeomKernel.rc | Bin 11710 -> 11710 bytes Trimming.cpp | 245 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 241 insertions(+), 4 deletions(-) diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 116749ecfa5e7a64090f08e5c66f16f7df1421e5..22fffabed78535e2b7b1c2a4a298b640af2d20bf 100644 GIT binary patch delta 81 zcmdlNy)SyhH#SD2&FAG5nSs @@ -53,6 +54,7 @@ #define DEBUG_BRK 0 #define DEBUG_BORDERS_BY_NORMALS 0 #define DEBUG_SYNC_POINTS 0 +#define DEBUG_SYNC_INTERPOLATION 0 #define DEBUG_BEZIER_RULED 0 #define DEBUG_CURVATURE 0 #define DEBUG_SIMPLE_PATCHES 0 @@ -63,9 +65,9 @@ #define DEBUG_HOLES 0 #if DEBUG_BASIC_BORDERS || DEBUG_CHAIN_CURVES || DEBUG_ANG_APPROX || DEBUG_BEZIER_INTERP || \ DEBUG_FACE_SEARCH || DEBUG_FACE_SEARCH_TRIA_MODIF || DEBUG_BRK_POINTS || DEBUG_BRK_THICK || \ - DEBUG_BRK || DEBUG_BORDERS_BY_NORMALS || DEBUG_SYNC_POINTS || DEBUG_BEZIER_RULED || DEBUG_CURVATURE || \ - DEBUG_SIMPLE_PATCHES || DEBUG_SURF_PATCHES || DEBUG_RAW_EDGES || DEBUG_EDGES || DEBUG_SHAPE_STM || \ - DEBUG_HOLES || DEBUG + DEBUG_BRK || DEBUG_BORDERS_BY_NORMALS || DEBUG_SYNC_POINTS || DEBUG_SYNC_INTERPOLATION || \ + DEBUG_BEZIER_RULED || DEBUG_CURVATURE || DEBUG_SIMPLE_PATCHES || DEBUG_SURF_PATCHES || \ + DEBUG_RAW_EDGES || DEBUG_EDGES || DEBUG_SHAPE_STM || DEBUG_HOLES || DEBUG #include "CurveLine.h" #include "/EgtDev/Include/EGkGeoObjSave.h" #include "/EgtDev/Include/EgtPerfCounter.h" @@ -3468,6 +3470,95 @@ IsBorderAButtonHole( const PolyLine& PL, double dLinTol, double dAngTol, Frame3d return false ; } +//----------------------------------------------------------------------------- +//-------------------------------- Interpolazioni ----------------------------- +//----------------------------------------------------------------------------- +static bool +InterpolateSyncCurvesOnEndGuidePoints( const ICurveComposite* pGuide, const ICurveComposite* pOtherGuide, + const Plane3d& plStart, const Plane3d& plEnd, double dLinTol, + BIPNTVECTOR& vBiPts) +{ + vBiPts.clear() ; + + // Verifico che le curve siano valide + if ( pGuide == nullptr || ! pGuide->IsValid() || + pOtherGuide == nullptr || ! pOtherGuide->IsValid()) + return false ; + + // Recupero la sua lunghezza + double dGuideLen = 0. ; + if ( ! pGuide->GetLength( dGuideLen) || dGuideLen < dLinTol) + return false ; + + // Scorro le curve da restituire + double dProgLen = 0. ; + vBiPts.reserve( pGuide->GetCurveCount() - 1) ; + for ( int i = 0 ; i < pGuide->GetCurveCount() - 1 ; ++ i) { + // Recupero la curva corrente + const ICurve* pCrv = pGuide->GetCurve( i) ; + if ( pCrv == nullptr || ! pCrv->IsValid()) + return false ; + // Ne recupero la lunghezza e aggiorno la lunghezza progressiva + double dLen = 0. ; + if ( ! pCrv->GetLength( dLen)) + return false ; + dProgLen += dLen ; + // Recupero la percentuale di interpolazione rispetto alla lunghezze + double dInterPar = dProgLen / dGuideLen ; + // Interpolo le normali dei piani rispetto a tale valore + Vector3d vtN = Media( plStart.GetVersN(), plEnd.GetVersN(), dInterPar) ; + vtN.Normalize() ; + // Definisco il piano di intersezione + Point3d ptCurr ; + if ( ! pCrv->GetEndPoint( ptCurr)) + return false ; + #if DEBUG_SYNC_INTERPOLATION + Frame3d frPl ; frPl.Set( ptCurr, vtN) ; + PtrOwner frCurr( CreateGeoFrame3d()) ; frCurr->Set( frPl) ; + VT.emplace_back( Release( frCurr)) ; + VC.emplace_back( WHITE) ; + SaveGeoObj( VT, VC, "C:\\Temp\\SyncLinesPlanes.nge") ; + #endif + // Recupero il parametro di intersezione tra la curva e il piano + #if 0 + VT.clear() ; VC.clear() ; + PtrOwner PT( CreateGeoPoint3d()) ; PT->Set( ptCurr) ; + VT.emplace_back( Release( PT)) ; + VC.emplace_back( AQUA) ; + PtrOwner VECT( CreateGeoVector3d()) ; VECT->Set( vtN) ; + VECT->ChangeBase( ptCurr) ; + PtrOwner pArc( CreateCurveArc()) ; pArc->Set( ptCurr, vtN, 1000.) ; + PtrOwner pSfrPlane( CreateSurfFlatRegion()) ; + pSfrPlane->AddExtLoop( Release( pArc)) ; + VT.emplace_back( Release( pSfrPlane)) ; + VC.emplace_back( Color( 0., 0., 0., .5)) ; + VT.emplace_back( Release( VECT)) ; + VC.emplace_back( BLUE) ; + VT.emplace_back( pOtherGuide->Clone()) ; + VC.emplace_back( WHITE) ; + SaveGeoObj( VT, VC, "C:\\Temp\\SyncLinesPlanes.nge") ; + #endif + IntersCurvePlane IntCP( *pOtherGuide, ptCurr, vtN) ; + if ( IntCP.GetIntersCount() == 0) + return false ; // ambiguità + // Recupero il punto della prima intersezione trovata + Point3d ptInt ; + double dPar ; + if ( ! IntCP.GetIntersPointNearTo( ptCurr, ptInt, dPar)) + return false ; + #if DEBUG_SYNC_INTERPOLATION + PtrOwner ptG( CreateGeoPoint3d()) ; ptG->Set( ptInt) ; + VT.emplace_back( Release( ptG)) ; + VC.emplace_back( WHITE) ; + SaveGeoObj( VT, VC, "C:\\Temp\\SyncLinesPlanes.nge") ; + #endif + // Memorizzo tale punto + vBiPts.emplace_back( make_pair( ptCurr, ptInt)) ; + } + + return true ; +} + //----------------------------------------------------------------------------- //-------------------------------- Funzioni Export ---------------------------- //----------------------------------------------------------------------------- @@ -3738,10 +3829,14 @@ bool GetTrimmingSurfBzSyncPoints( const ICurve* pCrvEdge1, const ICurve* pCrvEdge2, double dLinTol, BIPNTVECTOR& vSyncPoints) { + vSyncPoints.clear() ; + // Verifica validità delle curve per la creazione della Bezier rigata PtrOwner pCompoEdge1( ConvertCurveToComposite( pCrvEdge1->Clone())) ; PtrOwner pCompoEdge2( ConvertCurveToComposite( pCrvEdge2->Clone())) ; - vSyncPoints.clear() ; + if ( IsNull( pCompoEdge1) || IsNull( pCompoEdge2) || + ! pCompoEdge1->IsValid() || ! pCompoEdge2->IsValid()) + return false ; // Controllo sulla tolleranza lineare double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ; @@ -3783,6 +3878,148 @@ GetTrimmingSurfBzSyncPoints( const ICurve* pCrvEdge1, const ICurve* pCrvEdge2, return true ; } +//------------------------------------------------------------------------------ +// Funzione per interpolare le Curve di Sincronizzazione tra due Curve di Bordo +bool +GetTrimmingSyncInterpolation( const ICurve* pCrvEdge1, const ICurve* pCrvEdge2, + const ICurve* pSync1, const ICurve* pSync2, double dLinTol, + double dAngTol, BIPNTVECTOR& vSyncPoints) +{ + vSyncPoints.clear() ; + + // Verifico la validità dei parametri + if ( pCrvEdge1 == nullptr || ! pCrvEdge1->IsValid() || + pCrvEdge2 == nullptr || ! pCrvEdge2->IsValid() || + pSync1 == nullptr || ! pSync1->IsValid() || + pSync2 == nullptr || ! pSync2->IsValid()) + return false ; + + // Le curve di Bordo devono essere entrambe aperte o entrambe chiuse + if ( pCrvEdge1->IsClosed() != pCrvEdge2->IsClosed()) + return false ; + + // Verifico i valori delle tolleranze + double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ; + double dMyAngTol = Clamp( dAngTol, EPS_ANG_SMALL, 60.) ; + + // Verifico le due curve di sincronizzazione abbiano gli estremi sulle due curve di bordo + Point3d ptS1 ; pSync1->GetStartPoint( ptS1) ; + Point3d ptE1 ; pSync1->GetEndPoint( ptE1) ; + if ( AreSamePointEpsilon( ptS1, ptE1, dMyLinTol)) + return false ; + double dUA, dUB, dUC, dUD ; // [A,C]->Edge1 | [B,D]->Edge2 + if ( ( ! pCrvEdge1->GetParamAtPoint( ptS1, dUA, dMyLinTol) || ! pCrvEdge2->GetParamAtPoint( ptE1, dUB, dMyLinTol)) && + ( ! pCrvEdge1->GetParamAtPoint( ptE1, dUA, dMyLinTol) || ! pCrvEdge2->GetParamAtPoint( ptS1, dUB, dMyLinTol))) + return false ; + Point3d ptS2 ; pSync2->GetStartPoint( ptS2) ; + Point3d ptE2 ; pSync2->GetEndPoint( ptE2) ; + if ( AreSamePointEpsilon( ptS2, ptE2, dMyLinTol)) + return false ; + if ( ( ! pCrvEdge1->GetParamAtPoint( ptS2, dUC, dMyLinTol) || ! pCrvEdge2->GetParamAtPoint( ptE2, dUD, dMyLinTol)) && + ( ! pCrvEdge1->GetParamAtPoint( ptE2, dUC, dMyLinTol) || ! pCrvEdge2->GetParamAtPoint( ptS2, dUD, dMyLinTol))) + return false ; + + // Recupero i due tratti di curva + PtrOwner pCompoGuide1( ConvertCurveToBasicComposite( pCrvEdge1->CopyParamRange( dUA, dUC))) ; + PtrOwner pCompoGuide2( ConvertCurveToBasicComposite( pCrvEdge2->CopyParamRange( dUB, dUD))) ; + if ( IsNull( pCompoGuide1) || IsNull( pCompoGuide2) || + ! pCompoGuide1->IsValid() || ! pCompoGuide2->IsValid()) + return false ; + + // Determino quale curva è la più lunga, servirà come riferimento per la parametrizzazione e l'interpolazione + double dLen1, dLen2 ; + if ( ! pCompoGuide1->GetLength( dLen1) || ! pCompoGuide2->GetLength( dLen2) || + dLen1 < dMyLinTol || dLen2 < dMyLinTol) + return false ; + if ( dLen2 > dLen1) { + swap( pCompoGuide1, pCompoGuide2) ; + swap( dLen1, dLen2) ; + } + if ( pCompoGuide2->IsPointOn( ptS1)) + swap( ptS1, ptE1) ; + if ( pCompoGuide2->IsPointOn( ptS2)) + swap( ptS2, ptE2) ; + + #if DEBUG_SYNC_INTERPOLATION + VT.clear() ; VC.clear() ; + VT.emplace_back( pCompoGuide1->Clone()) ; + VC.emplace_back( AQUA) ; + VT.emplace_back( pCompoGuide2->Clone()) ; + VC.emplace_back( ORANGE) ; + PtrOwner ptG( CreateGeoPoint3d()) ; ptG->Set( ptS1) ; + VT.emplace_back( ptG->Clone()) ; VC.emplace_back( AQUA) ; + ptG->Set( ptE1) ; + VT.emplace_back( ptG->Clone()) ; VC.emplace_back( ORANGE) ; + ptG->Set( ptS2) ; + VT.emplace_back( ptG->Clone()) ; VC.emplace_back( AQUA) ; + ptG->Set( ptE2) ; + VT.emplace_back( ptG->Clone()) ; VC.emplace_back( ORANGE) ; + PtrOwner pLine( CreateCurveLine()) ; pLine->Set( ptS1, ptE1) ; + VT.emplace_back( pLine->Clone()) ; VC.emplace_back( PURPLE) ; + pLine->Set( ptS2, ptE2) ; + VT.emplace_back( pLine->Clone()) ; VC.emplace_back( PURPLE) ; + SaveGeoObj( VT, VC, "C:\\Temp\\SyncLinesPlanes.nge") ; + #endif + + // Determino le Normali dei piani di taglio agli agli estremi delle due curve + Vector3d vtStart1, vtStart2 ; + if ( ! pCompoGuide1->GetStartDir( vtStart1) || ! pCompoGuide2->GetStartDir( vtStart2)) + return false ; + Vector3d vtAux = ptE1 - ptS1 ; vtAux.Normalize() ; + Vector3d vtMTan = Media( vtStart1, vtStart2) ; vtMTan.Normalize() ; + Vector3d vtN = OrthoCompo( vtMTan, vtAux) ; vtN.Normalize() ; + Plane3d plStart ; + if ( ! plStart.Set( ptS1, vtN)) + return false ; + Vector3d vtEnd1, vtEnd2 ; + if ( ! pCompoGuide1->GetEndDir( vtEnd1) || ! pCompoGuide2->GetEndDir( vtEnd2)) + return false ; + vtAux = ptE2 - ptS2 ; vtAux.Normalize() ; + vtMTan = Media( vtEnd1, vtEnd2) ; vtMTan.Normalize() ; + vtN = OrthoCompo( vtMTan, vtAux) ; vtN.Normalize() ; + Plane3d plEnd ; + if ( ! plEnd.Set( ptS2, vtN)) + return false ; + + #if DEBUG_SYNC_INTERPOLATION + Frame3d frPlStart ; frPlStart.Set( ptS1, plStart.GetVersN()) ; + Frame3d frPlEnd ; frPlEnd.Set( ptS2, plEnd.GetVersN()) ; + PtrOwner frS( CreateGeoFrame3d()) ; frS->Set( frPlStart) ; + PtrOwner frE( CreateGeoFrame3d()) ; frE->Set( frPlEnd) ; + VT.emplace_back( Release( frS)) ; + VC.emplace_back( WHITE) ; + VT.emplace_back( Release( frE)) ; + VC.emplace_back( WHITE) ; + SaveGeoObj( VT, VC, "C:\\Temp\\SyncLinesPlanes.nge") ; + #endif + + // Curve di Sincronizzazione del Bordo 1 sul Bordo 2 + BIPNTVECTOR vBiPts1 ; + if ( ! InterpolateSyncCurvesOnEndGuidePoints( pCompoGuide1, pCompoGuide2, plStart, plEnd, dMyLinTol, vBiPts1)) + return false ; + + // Curve di Sincronizzazione del Bordo 2 sul Bordo 1 + BIPNTVECTOR vBiPts2 ; + if ( ! InterpolateSyncCurvesOnEndGuidePoints( pCompoGuide2, pCompoGuide1, plStart, plEnd, dMyLinTol, vBiPts2)) + return false ; + + // Restituisco le Curve di Sincronizzazione + // [Da Bordo 1 a Bordo 2 originale] + vSyncPoints.reserve( ssize( vBiPts1) + ssize( vBiPts2)) ; + for ( int i = 0 ; i < ssize( vBiPts1) ; ++ i) { + vSyncPoints.emplace_back( vBiPts1[i]) ; + if ( pCrvEdge1->IsPointOn( vBiPts1[i].second, dMyLinTol)) + swap( vSyncPoints.back().first, vSyncPoints.back().second) ; + } + for ( int i = 0 ; i < ssize( vBiPts2) ; ++ i) { + vSyncPoints.emplace_back( vBiPts2[i]) ; + if ( pCrvEdge1->IsPointOn( vBiPts2[i].second, dMyLinTol)) + swap( vSyncPoints.back().first, vSyncPoints.back().second) ; + } + + return true ; +} + //------------------------------------------------------------------------------ // Funzione per il calcolo della superficie di Bezier rigata // NB. Possono essere passati dei parametri opzionali come vIndPriority e vIndVisible : From 6d544f93f4e8f465e5ee6c5a7acac8e08bbe5c62 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Thu, 19 Feb 2026 18:15:58 +0100 Subject: [PATCH 2/2] EgtGeomKernel : - miglioramento dell'approssimazione con curve di bezier. --- CurveAux.cpp | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/CurveAux.cpp b/CurveAux.cpp index 484367d..43c1f53 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -1642,8 +1642,11 @@ ApproxCurveWithBezier( const ICurve* pCrv , double dTol) double dRadPrec = vRad[0] ; int nStart = 0 ; int nEnd = 1 ; + double dRatio = 1.5 ; while ( nStart < ssize( vPnt) - 1) { double dRadTol = max( max( vRad[nEnd], dRadPrec) / 10 , 1.) ; + if ( dRadPrec > dRatio * vRad[nEnd] || dRatio * dRadPrec < vRad[nEnd]) + dRadTol = 0 ; while ( nEnd < ssize( vPnt) - 1 && abs( vRad[nEnd] - dRadPrec) < dRadTol) { dRadPrec = vRad[nEnd] ; ++nEnd ; @@ -1678,16 +1681,27 @@ ApproxCurveWithBezier( const ICurve* pCrv , double dTol) vNextDer[i].Normalize() ; } + // potrei verificare prima se un tratto è retto e aggiustare le tangenti del tratto precedente e successivo prima di approssimare PtrOwner pCCApproxTot( CreateCurveComposite()) ; for ( INTINT iiSE : vConstCurv) { nFirst = iiSE.first ; nLast = iiSE.second ; - //definisco la bezier che vado a raffinare iterativamente - PtrOwner pCApprox( FitWithBezier( pCrv, vPntOverSampling, vParam, nFirst, nLast, vPrevDer, vNextDer, dTol, true)) ; - if ( IsNull( pCApprox) || ! pCApprox->IsValid()) - return nullptr ; - if ( ! pCCApproxTot->AddCurve( Release( pCApprox))) - return nullptr ; + // riconosco se ho un tratto retto + int nPnt = nFirst / 3 ; + if ( nLast - nFirst == 3 && ( nPnt > 0 && vRad[nPnt] > dRatio * vRad[nPnt - 1]) && ( nPnt < ssize( vRad) && vRad[nPnt]> dRatio * vRad[nPnt + 1])) { + CurveLine CL ; CL.Set( vPntOverSampling[nFirst], vPntOverSampling[nLast]) ; + PtrOwner pCApprox( LineToBezierCurve( &CL, 3, false)) ; + if ( ! pCCApproxTot->AddCurve( Release( pCApprox))) + return nullptr ; + } + else { + //definisco la bezier che vado a raffinare iterativamente + PtrOwner pCApprox( FitWithBezier( pCrv, vPntOverSampling, vParam, nFirst, nLast, vPrevDer, vNextDer, dTol, true)) ; + if ( IsNull( pCApprox) || ! pCApprox->IsValid()) + return nullptr ; + if ( ! pCCApproxTot->AddCurve( Release( pCApprox))) + return nullptr ; + } } return Release( pCCApproxTot) ;