diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 116749e..22fffab 100644 Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ diff --git a/Trimming.cpp b/Trimming.cpp index 7cac8b1..8b0cd9e 100644 --- a/Trimming.cpp +++ b/Trimming.cpp @@ -34,6 +34,7 @@ #include "/EgtDev/Include/EGkSbzFromCurves.h" #include "/EgtDev/Include/EGkStmFromTriangleSoup.h" #include "/EgtDev/Include/EGkIntersLineBox.h" +#include "/EgtDev/Include/EGkIntersCurvePlane.h" #include "/EgtDev/Include/EGkSurfTriMeshAux.h" #include "/EgtDev/Include/EgtNumUtils.h" #include @@ -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" @@ -3577,6 +3579,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 ---------------------------- //----------------------------------------------------------------------------- @@ -3847,10 +3938,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) ; @@ -3892,6 +3987,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 :