diff --git a/CurveAux.cpp b/CurveAux.cpp
index 1aaceff..9291c93 100644
--- a/CurveAux.cpp
+++ b/CurveAux.cpp
@@ -1595,8 +1595,10 @@ FitWithBezier( const ICurve* pCrvOrig, const PNTVECTOR& vPnt, DBLVECTOR& vParam,
//----------------------------------------------------------------------------
ICurve*
-ApproxCurveWithBezier( const ICurve* pCrv , double dTol)
+ApproxCurveWithBezier( const ICurve* pCrv , double dTol, const Vector3d& vtStart, const Vector3d& vtEnd)
{
+ if ( pCrv == nullptr || ! pCrv->IsValid())
+ return nullptr ;
#if SAVECURVEPASSED
SaveGeoObj( pCrv->Clone(), "D:\\Temp\\bezier\\approxWithBezier\\CurveDaApprossimare\\"+ToString(nCrvPassed) + ".nge") ;
@@ -1668,6 +1670,10 @@ ApproxCurveWithBezier( const ICurve* pCrv , double dTol)
VCT3DVECTOR vPrevDer ;
VCT3DVECTOR vNextDer ;
ComputeAkimaTangents( false, vParam, vPnt, vPrevDer, vNextDer) ;
+ if ( ! AreSameVectorExact(vtStart, V_NULL)) {
+ vNextDer[0] = vtStart ;
+ vPrevDer.back() = vtEnd ;
+ }
int nOverSampling = ssize( vPntOverSampling) ;
vParam.resize( nOverSampling) ;
diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters
index e5df427..0143f2b 100644
--- a/EgtGeomKernel.vcxproj.filters
+++ b/EgtGeomKernel.vcxproj.filters
@@ -557,6 +557,9 @@
File di origine\Gdb
+
+
+ File di origine\GeoTrimming
File di origine\GeoDist
diff --git a/SbzFromCurves.cpp b/SbzFromCurves.cpp
index c68f5ea..b613556 100644
--- a/SbzFromCurves.cpp
+++ b/SbzFromCurves.cpp
@@ -735,7 +735,7 @@ GetSurfBezierRuled( const ICurve* pCurve1, const ICurve* pCurve2, int nType, dou
//-------------------------------------------------------------------------------
ISurfBezier*
-GetSurfBezierRuledSmooth( const ICurve* pCurve1, const ICurve* pCurve2, double dSampleLen)
+GetSurfBezierRuledSmooth( const ICurve* pCurve1, const ICurve* pCurve2, BIPNTVECTOR& vSyncLines, double dSampleLen)
{
// verifica parametri
if ( pCurve1 == nullptr || pCurve2 == nullptr)
@@ -762,7 +762,7 @@ GetSurfBezierRuledSmooth( const ICurve* pCurve1, const ICurve* pCurve2, double d
// creo e setto la superficie trimesh
PtrOwner pSbz( CreateBasicSurfBezier()) ;
- if ( IsNull( pSbz) || ! pSbz->CreateSmoothRuledByTwoCurves( pCC1, pCC2, dSampleLen))
+ if ( IsNull( pSbz) || ! pSbz->CreateSmoothRuledByTwoCurves( pCC1, pCC2, dSampleLen, vSyncLines))
return nullptr ;
// restituisco la superficie
diff --git a/SurfBezier.cpp b/SurfBezier.cpp
index 2b2e72d..3f9b541 100644
--- a/SurfBezier.cpp
+++ b/SurfBezier.cpp
@@ -57,6 +57,7 @@
|| SAVEFAILEDTREE || SAVELIMITSURF || SAVEPACEDISO
#include "/EgtDev/Include/EGkGeoObjSave.h"
std::vector vGeo ;
+ std::vector vCol ;
#endif
using namespace std ;
@@ -5896,15 +5897,31 @@ SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int
return true ;
}
+// Struttura per Spigolo
struct SharpEdge {
double dParU ;
Point3d ptEdge ;
- Vector3d vtTanPrev, vtTanAft ;
+ Vector3d vtTanPrev, vtTanNext ;
SharpEdge( double dU, const Point3d ptE, const Vector3d& vtTP, const Vector3d& vtTA)
- : dParU( dU), ptEdge( ptE), vtTanPrev( vtTP), vtTanAft( vtTA) {}
+ : dParU( dU), ptEdge( ptE), vtTanPrev( vtTP), vtTanNext( vtTA) {}
} ;
typedef vector SHARPEDGEVECTOR ;
+// Struttura per Punto a Curvatura Massima
+struct CurvaturePoint {
+ double dParU ;
+ Point3d ptCurvature ;
+ Vector3d vtTanPrev, vtTanNext ;
+ CurvaturePoint( double dU, const Point3d ptE, const Vector3d& vtTP, const Vector3d& vtTA)
+ : dParU( dU), ptCurvature( ptE), vtTanPrev( vtTP), vtTanNext( vtTA) {}
+} ;
+typedef vector SHARPEDGEVECTOR ;
+
+// ---------------------------------------------------------------------------
+// Calcolo delle Curve di Sync tra gli spigoli di una curva e l'altra curva nella sua integrità
+// [Dato un vettore di SharpEdge di una Curva di Bordo si calcola la Linea di Sincronizzazione tra ognuno di essi
+// e l'altra Curva di Bordo]
+// -> Restituisce un vettore di Linee di Sincronizzazione
static bool
CalcSyncPointFromEdge( const SHARPEDGEVECTOR& vSharpEdge, const ICurveComposite* pCompoSubEdge, const SHARPEDGEVECTOR& vSharpSubEdge,
BIPNTVECTOR& vSyncLines)
@@ -5919,13 +5936,20 @@ CalcSyncPointFromEdge( const SHARPEDGEVECTOR& vSharpEdge, const ICurveComposite*
if ( vSharpEdge.empty())
return true ;
+ // Se il numero di Spigoli coincide, allora li unisco sequenzialmente tra loro ( considerazione buona ???)
+ if ( ssize( vSharpEdge) == ssize( vSharpSubEdge)) {
+ for ( int i = 0 ; i < ssize( vSharpEdge) ; ++ i)
+ vSyncLines.emplace_back( vSharpEdge[i].ptEdge, vSharpSubEdge[i].ptEdge) ;
+ return false ;
+ }
+
// Scorro gli SharpEdges
double dUPrevSubEdge = 0., dUCurrSubEdge = 0. ;
for ( const SharpEdge& mySharpEdge : vSharpEdge) {
// Recupero il parametro sulla curva di sincronizzazione
// --- Piano di taglio per punto a distanza minima
- IntersCurvePlane ICP( *pCompoSubEdge, mySharpEdge.ptEdge, Media( mySharpEdge.vtTanPrev, mySharpEdge.vtTanAft)) ;
+ IntersCurvePlane ICP( *pCompoSubEdge, mySharpEdge.ptEdge, Media( mySharpEdge.vtTanPrev, mySharpEdge.vtTanNext)) ;
int nIndParCloser = -1, nIndPointCloser = -1 ;
double dSqMinDist = INFINITO ;
for ( int nInfo = 0 ; nInfo < ICP.GetIntersCount() ; ++ nInfo) {
@@ -5940,7 +5964,7 @@ CalcSyncPointFromEdge( const SHARPEDGEVECTOR& vSharpEdge, const ICurveComposite*
}
}
}
- bool bOkPlane = ( nIndParCloser != -1 && nIndPointCloser != -1) ;
+ bool bOkPlane = ( nIndParCloser != -1 && nIndPointCloser != -1) ;
if ( bOkPlane) {
// Se gli indici sono tra loro coerenti allora ho individuato il punto
if ( nIndParCloser == nIndPointCloser) {
@@ -5948,30 +5972,31 @@ CalcSyncPointFromEdge( const SHARPEDGEVECTOR& vSharpEdge, const ICurveComposite*
ICP.GetIntCrvPlnInfo( nIndParCloser, aInfo) ;
dUCurrSubEdge = aInfo.Ici[0].dU ;
}
+ // Se gli indici sono discordi, devo scegliere quale dei due punti tenere
+ else {
+ // scelgo il punto più vicino al corrente
+ IntCrvPlnInfo aInfoPt, aInfoPar ;
+ ICP.GetIntCrvPlnInfo( nIndPointCloser, aInfoPt) ;
+ ICP.GetIntCrvPlnInfo( nIndParCloser, aInfoPar) ;
+ dUCurrSubEdge = ( SqDist( mySharpEdge.ptEdge, aInfoPt.Ici[0].ptI) < SqDist( mySharpEdge.ptEdge, aInfoPar.Ici[0].ptI) ?
+ aInfoPt.Ici[0].dU : aInfoPar.Ici[0].dU) ;
+ }
}
- // Se gli indici sono discordi, devo scegliere quale dei due punti tenere
- else {
- // scelgo il punto più vicino al corrente
- IntCrvPlnInfo aInfoPt, aInfoPar ;
- ICP.GetIntCrvPlnInfo( nIndPointCloser, aInfoPt) ;
- ICP.GetIntCrvPlnInfo( nIndParCloser, aInfoPar) ;
- dUCurrSubEdge = ( SqDist( mySharpEdge.ptEdge, aInfoPt.Ici[0].ptI) < SqDist( mySharpEdge.ptEdge, aInfoPar.Ici[0].ptI) ?
- aInfoPt.Ici[0].dU : aInfoPar.Ici[0].dU) ;
- if ( ! bOkPlane) {
- // --- Altrimenti, cerco il punto a minima distanza
- DistPointCurve DPC( mySharpEdge.ptEdge, *pCompoSubEdge) ;
- int nFlag ;
- bool bOkMinDist = ( DPC.GetParamAtMinDistPoint( dUPrevSubEdge, dUCurrSubEdge, nFlag) && dUCurrSubEdge > dUPrevSubEdge) ;
- if ( ! bOkMinDist) {
- // --- Eh.... bho ( se arrivo qui non so che fare...)
- double dUStart, dUEnd ;
- pCompoSubEdge->GetDomain( dUStart, dUEnd) ;
- dUCurrSubEdge = ( dUEnd - dUCurrSubEdge) / 2. ;
- }
+ if ( ! bOkPlane) {
+ // --- Altrimenti, cerco il punto a minima distanza
+ DistPointCurve DPC( mySharpEdge.ptEdge, *pCompoSubEdge) ;
+ int nFlag ;
+ bool bOkMinDist = ( DPC.GetParamAtMinDistPoint( dUPrevSubEdge, dUCurrSubEdge, nFlag) && dUCurrSubEdge > dUPrevSubEdge) ;
+ if ( ! bOkMinDist) {
+ // --- Alla peggio mi posiziono a metà tra la posizione corrente e quella finale
+ double dPrevLen ; pCompoSubEdge->GetLengthAtParam( dUPrevSubEdge, dPrevLen) ;
+ double dLen ; pCompoSubEdge->GetLength( dLen) ;
+ pCompoSubEdge->GetParamAtLength( ( dPrevLen + dLen) / 2., dUCurrSubEdge) ;
}
}
// Verifico se tale parametro può essere avvicinato ad uno Spigolo presente sulla curva
+ // NB. Come descitto sopra gli spigoli in generale è meglio sincronizzarli tra loro
if ( ! vSharpSubEdge.empty()) {
const double EDGE_LEN_TOL = 5. ;
for ( const SharpEdge& mySharpSubEdge : vSharpSubEdge) {
@@ -6001,7 +6026,104 @@ CalcSyncPointFromEdge( const SHARPEDGEVECTOR& vSharpEdge, const ICurveComposite*
}
// ---------------------------------------------------------------------------
-// Debug [Gestione Edge in Quadrangolazioni]
+// Calcolo della curva di Sync tra un punto di una curva di Bordo (calcolato come il punto a curvatura massima) e il suo
+// associato sull'altra Curva di Bordo
+// -> Restituisce la singola Linea di Sincronizzazione
+static bool
+CalcSyncPointFromCurvature( const CurvaturePoint& PointK, const ICurveComposite* pCompoSubEdge, BIPOINT& SyncLine)
+{
+ // Verifico la validità del SubEdge su cui trovare il punto di Sincronizzazione
+ if ( pCompoSubEdge == nullptr || ! pCompoSubEdge->IsValid())
+ return false ;
+
+ // --- Piano di taglio per punto a distanza minima
+ double dUCurrSubEdge = 0. ;
+ IntersCurvePlane ICP( *pCompoSubEdge, PointK.ptCurvature, Media( PointK.vtTanPrev, PointK.vtTanNext)) ;
+ int nIndParCloser = -1, nIndPointCloser = -1 ;
+ double dSqMinDist = INFINITO ;
+ for ( int nInfo = 0 ; nInfo < ICP.GetIntersCount() ; ++ nInfo) {
+ IntCrvPlnInfo aInfo ;
+ if ( ICP.GetIntCrvPlnInfo( nInfo, aInfo)) {
+ if ( nIndParCloser == -1)
+ nIndParCloser = nInfo ;
+ double dSqDist = SqDist( PointK.ptCurvature, aInfo.Ici[0].ptI) ;
+ if ( dSqDist < dSqMinDist) {
+ dSqMinDist = dSqDist ;
+ nIndPointCloser = nInfo ;
+ }
+ }
+ }
+ bool bOkPlane = ( nIndParCloser != -1 && nIndPointCloser != -1) ;
+ if ( bOkPlane) {
+ // Se gli indici sono tra loro coerenti allora ho individuato il punto
+ if ( nIndParCloser == nIndPointCloser) {
+ IntCrvPlnInfo aInfo ;
+ ICP.GetIntCrvPlnInfo( nIndParCloser, aInfo) ;
+ dUCurrSubEdge = aInfo.Ici[0].dU ;
+ }
+ // Se gli indici sono discordi, devo scegliere quale dei due punti tenere
+ else {
+ // scelgo il punto più vicino al corrente
+ IntCrvPlnInfo aInfoPt, aInfoPar ;
+ ICP.GetIntCrvPlnInfo( nIndPointCloser, aInfoPt) ;
+ ICP.GetIntCrvPlnInfo( nIndParCloser, aInfoPar) ;
+ dUCurrSubEdge = ( SqDist( PointK.ptCurvature, aInfoPt.Ici[0].ptI) < SqDist( PointK.ptCurvature, aInfoPar.Ici[0].ptI) ?
+ aInfoPt.Ici[0].dU : aInfoPar.Ici[0].dU) ;
+ }
+ }
+ if ( ! bOkPlane) {
+ // --- Altrimenti, cerco il punto a minima distanza
+ DistPointCurve DPC( PointK.ptCurvature, *pCompoSubEdge) ;
+ int nFlag ;
+ bool bOkMinDist = ( DPC.GetParamAtMinDistPoint( 0., dUCurrSubEdge, nFlag)) ;
+ if ( ! bOkMinDist) {
+ // --- Alla peggio mi posiziono a metà tra la posizione corrente e quella finale
+ double dPrevLen ; pCompoSubEdge->GetLengthAtParam( 0., dPrevLen) ;
+ double dLen ; pCompoSubEdge->GetLength( dLen) ;
+ pCompoSubEdge->GetParamAtLength( ( dPrevLen + dLen) / 2., dUCurrSubEdge) ;
+ }
+ }
+
+ // Definisco il primo estremo della linea di Sincronizzazione corrente
+ SyncLine.first = PointK.ptCurvature ;
+
+ // Verifico se posso muovermi attorno al punto trovato per allinearmi meglio con le normali alla curva
+ // NB. Si cerca di privilgiare i punti più vicini ( in parametro) al punto calcolato sopra, in modo da cercare di
+ // non discostare troppo la Linea di sincronizzazione dal punto trovato.
+ const double MAX_DIST = 2.5 ;
+ const int NUM_SAMPLE_PNT = 20 ;
+ double dLen ; pCompoSubEdge->GetLength( dLen) ;
+ double dSyncLen ; pCompoSubEdge->GetLengthAtParam( dUCurrSubEdge, dSyncLen) ;
+ Vector3d vtSyncTanPrev, vtSyncTanNext ;
+ pCompoSubEdge->GetPointD1D2( dUCurrSubEdge, ICurve::FROM_MINUS, SyncLine.second, &vtSyncTanPrev) ; vtSyncTanPrev.Normalize() ;
+ pCompoSubEdge->GetPointD1D2( dUCurrSubEdge, ICurve::FROM_PLUS, SyncLine.second, &vtSyncTanNext) ; vtSyncTanNext.Normalize() ;
+ double dLimInfLen = Clamp( dSyncLen - MAX_DIST, 0., dLen) ;
+ double dLimSupLen = Clamp( dSyncLen + MAX_DIST, 0., dLen) ;
+ int nSamplePnt = int( ceil( NUM_SAMPLE_PNT / 4.)) ;
+ double dMaxCos = ( Media( PointK.vtTanPrev, PointK.vtTanNext) * Media( vtSyncTanPrev, vtSyncTanNext)) ;
+ double dShiftR = ( dLimSupLen - dSyncLen) / nSamplePnt ;
+ double dShiftL = ( dSyncLen - dLimInfLen) / nSamplePnt ;
+ array vdLens = { dSyncLen, dSyncLen} ;
+ for ( int i = 1 ; i <= nSamplePnt ; ++ i) {
+ vdLens[0] += dShiftR ;
+ vdLens[1] -= dShiftL ;
+ for ( int j = 0 ; j < 2 ; ++ j) {
+ double dU ; pCompoSubEdge->GetParamAtLength( vdLens[j], dU) ;
+ Point3d ptCurr ; Vector3d vtTan ;
+ pCompoSubEdge->GetPointD1D2( dU, ICurve::FROM_MINUS, ptCurr, &vtTan) ; vtTan.Normalize() ;
+ double dCos = ( vtTan * Media( PointK.vtTanPrev, PointK.vtTanNext)) ;
+ if ( dCos > dMaxCos) {
+ dMaxCos = dCos ;
+ SyncLine.second = ptCurr ;
+ }
+ }
+ }
+
+ return true ;
+}
+
+// ---------------------------------------------------------------------------
+// Gestione degli spigoli all'interno della Quadrangolazione corrente
static bool
ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComposite* pSubEdge2, BIPNTVECTOR& vSyncLines)
{
@@ -6020,7 +6142,7 @@ ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComp
SHARPEDGEVECTOR vSharpEdges2 ; vSharpEdges2.reserve( max( 0, nCrv2 - 1)) ;
// --- Cerco gli Spigoli sul SottoTratto del primo bordo
- // Se la CurvaA ha solo una sottocurva, non faccio nulla
+ // Se la CurvaA ha più di una sottocurva, verifico l'esistenza di Spigoli (Sharp Edges)
if ( nCrv1 > 1) {
Point3d ptCurr1 ;
// Scorro le sottocurve
@@ -6029,17 +6151,17 @@ ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComp
double dU = double( nCrv + 1) ;
// Recupero le tangenti prima e dopo tale parametro
Vector3d vtTanPrev ; pSubEdge1->GetPointD1D2( dU, ICurve::FROM_MINUS, ptCurr1, &vtTanPrev) ;
- Vector3d vtTanAft ; pSubEdge1->GetPointD1D2( dU, ICurve::FROM_PLUS, ptCurr1, &vtTanAft) ;
+ Vector3d vtTanNext ; pSubEdge1->GetPointD1D2( dU, ICurve::FROM_PLUS, ptCurr1, &vtTanNext) ;
// Verifico se ho uno spigolo
vtTanPrev.Normalize() ;
- vtTanAft.Normalize() ;
- if ( vtTanPrev * vtTanAft < COS_EDGE_LIMIT)
- vSharpEdges1.emplace_back( dU, ptCurr1, vtTanPrev, vtTanAft) ;
+ vtTanNext.Normalize() ;
+ if ( vtTanPrev * vtTanNext < COS_EDGE_LIMIT)
+ vSharpEdges1.emplace_back( dU, ptCurr1, vtTanPrev, vtTanNext) ;
}
}
// --- Cerco gli spigoli sul Sottotratto del secondo bordo
- // Se la Curva B ha solo una sottocurva, non faccio nulla
+ // Se la Curva B ha più di una sottocurva, verifico l'esistena di Spigoli (Sharp Edges)
if ( nCrv2 > 1) {
Point3d ptCurr2 ;
// Scorro le sottocurve
@@ -6048,24 +6170,24 @@ ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComp
double dU = double( nCrv + 1) ;
// Recupero le tangenti prima e dopo tale parametro
Vector3d vtTanPrev ; pSubEdge2->GetPointD1D2( dU, ICurve::FROM_MINUS, ptCurr2, &vtTanPrev) ;
- Vector3d vtTanAft ; pSubEdge2->GetPointD1D2( dU, ICurve::FROM_PLUS, ptCurr2, &vtTanAft) ;
+ Vector3d vtTanNext ; pSubEdge2->GetPointD1D2( dU, ICurve::FROM_PLUS, ptCurr2, &vtTanNext) ;
// Verifico se ho uno spigolo
vtTanPrev.Normalize() ;
- vtTanAft.Normalize() ;
- if ( vtTanPrev * vtTanAft < COS_EDGE_LIMIT)
- vSharpEdges2.emplace_back( dU, ptCurr2, vtTanPrev, vtTanAft) ;
+ vtTanNext.Normalize() ;
+ if ( vtTanPrev * vtTanNext < COS_EDGE_LIMIT)
+ vSharpEdges2.emplace_back( dU, ptCurr2, vtTanPrev, vtTanNext) ;
}
}
- // Se non ho alcuno spigolo, allora non faccio nulla
+ // Se non ho alcuno spigolo per entrambe le curve di Bordo, non faccio nulla
if ( vSharpEdges1.empty() && vSharpEdges2.empty())
return true ;
- // Recupero le Curve di Sincronizzazione dell'Edge 1 sull'Edge 2
+ // Recupero le Curve di Sincronizzazione associate agli spigoli dal primo Bordo al secondo Bordo
BIPNTVECTOR vSyncLines1 ;
CalcSyncPointFromEdge( vSharpEdges1, pSubEdge2, vSharpEdges2, vSyncLines1) ;
- // Recupero le Curve di Sincronizzazione dell'Edge 2 sull'Egde 1
+ // Recupero le Curve di Sincronizzazione associate agli spigoli dal secondo Bordo al primo Bordo
BIPNTVECTOR vSyncLines2 ;
CalcSyncPointFromEdge( vSharpEdges2, pSubEdge1, vSharpEdges1, vSyncLines2) ;
@@ -6078,7 +6200,7 @@ ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComp
}) ;
}) ;
- // Ordino tutte le curve in base al parametro dU della curva principale
+ // Ordino tutte le curve in base al parametro dU della prima curva di Bordo
vector> vSyncLinesPar ; vSyncLinesPar.reserve( vSyncLines1.size() + vSyncLines2.size()) ;
for ( BIPOINT& SyncLine1 : vSyncLines1) {
vSyncLinesPar.emplace_back( make_pair( make_pair( SyncLine1.first, SyncLine1.second),
@@ -6094,9 +6216,212 @@ ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComp
return SyncLineParA.second < SyncLineParB.second ;
}) ;
- // Restituisco il risultato
- for ( auto Iter = vSyncLinesPar.begin() ; Iter != vSyncLinesPar.end() ; ++ Iter)
- vSyncLines.emplace_back( Iter->first) ;
+ // Controllo che le linee di sincronizzazione non si intreccino e restituisco il risultato
+ // NB. Inserisco solo che curve che progressivamente non si intrecciano sulla seconda curva di Bordo
+ double dUSecondPrev = EPS_PARAM ;
+ for ( auto Iter = vSyncLinesPar.begin() ; Iter != vSyncLinesPar.end() ; ++ Iter) {
+ double dUSecondCurr ; pSubEdge2->GetParamAtPoint( ( *Iter).first.second, dUSecondCurr, TOL) ;
+ if ( dUSecondCurr > dUSecondPrev + EPS_SMALL) {
+ vSyncLines.emplace_back( Iter->first) ;
+ dUSecondPrev = dUSecondCurr ;
+ }
+ }
+
+ return true ;
+}
+
+// ---------------------------------------------------------------------------
+// Calcolo delle Curve di Sync per evitare Twist
+static bool
+ManageTwistInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComposite* pSubEdge2, BIPNTVECTOR& vSyncLines)
+{
+ // Verifica validità delle curve
+ if ( pSubEdge1 == nullptr || ! pSubEdge1->IsValid() || pSubEdge2 == nullptr || ! pSubEdge2->IsValid())
+ return false ;
+
+ const double COS_LIMIT = cos( 50. * DEGTORAD) ;
+ const int NUM_SAMPLE_PNT = 20 ;
+ #if DEBUG_CURVATURE
+ vector> _vPtK1 ;
+ vector> _vPtK2 ;
+ IGeomDB* pGeomDB = GetCurrGeomDB() ;
+ VERIFY_GEOMDB( pGeomDB, false)
+ #endif
+
+ // --- Verifico il cambiamento di Deviazione angolare tra Inizio-Fine della prima curva di Bordo
+ Vector3d vtS1 ; pSubEdge1->GetStartDir( vtS1) ;
+ Vector3d vtE1 ; pSubEdge1->GetEndDir( vtE1) ;
+ double dLen1 = - EPS_SMALL ;
+ bool bSplit1 = ( vtS1 * vtE1 < COS_LIMIT) ;
+ if ( bSplit1) {
+ // Individuo il punto a Curvatura Massima
+ pSubEdge1->GetLength( dLen1) ;
+ double dKMax1 = - INFINITO + 1, dUK1Max = - EPS_SMALL ;
+ Point3d ptKMax1 ; Vector3d vtTanKMax1Prev, vtTanKMax1Next ;
+ for ( int i = 0 ; i <= NUM_SAMPLE_PNT ; ++ i) {
+ // Ricavo la Lunghezza corrente e il parametro dU associato
+ double dCurrLen1 = Clamp( i * ( dLen1 / NUM_SAMPLE_PNT), 0., dLen1) ;
+ double dUCurr1 ; pSubEdge1->GetParamAtLength( dCurrLen1, dUCurr1) ;
+ // Calcolo la Curvatura
+ Point3d ptCurrSub1 ;
+ Vector3d vtCurrSub1Der1Prev, vtCurrSub1Der2Prev, vtCurrSub1Der1Next, vtCurrSub1Der2Next ;
+ pSubEdge1->GetPointD1D2( dUCurr1, ICurve::FROM_MINUS, ptCurrSub1, &vtCurrSub1Der1Prev, &vtCurrSub1Der2Prev) ;
+ pSubEdge1->GetPointD1D2( dUCurr1, ICurve::FROM_PLUS, ptCurrSub1, &vtCurrSub1Der1Next, &vtCurrSub1Der2Next) ;
+ Vector3d vtCurrSub1Der1 = Media( vtCurrSub1Der1Prev, vtCurrSub1Der1Next) ;
+ Vector3d vtCurrSub1Der2 = Media( vtCurrSub1Der2Prev, vtCurrSub1Der2Next) ;
+ double dCurrK1 = ( vtCurrSub1Der1 ^ vtCurrSub1Der2).Len() / max( EPS_SMALL, Pow( vtCurrSub1Der1.Len(), 3)) ;
+ // Se maggiore della massima trovata, aggiorno la massima
+ if ( dCurrK1 > dKMax1) {
+ dKMax1 = dCurrK1 ;
+ ptKMax1 = ptCurrSub1 ;
+ dUK1Max = dUCurr1 ;
+ vtTanKMax1Prev = vtCurrSub1Der1Prev ;
+ vtTanKMax1Next = vtCurrSub1Der1Next ;
+ }
+ #if DEBUG_CURVATURE
+ _vPtK1.emplace_back( make_pair( ptCurrSub1, dCurrK1)) ;
+ #endif
+ }
+ vtTanKMax1Prev.Normalize() ;
+ vtTanKMax1Next.Normalize() ;
+ // Calcolo la nuova linea di sincronizzazione
+ CurvaturePoint myCurvaturePoint( dUK1Max, ptKMax1, vtTanKMax1Prev, vtTanKMax1Next) ;
+ BIPOINT SyncLine ;
+ CalcSyncPointFromCurvature( myCurvaturePoint, pSubEdge2, SyncLine) ;
+ vSyncLines.emplace_back( SyncLine) ;
+ }
+
+ // --- Verifico il cambiamento di Deviazione angolare tra Inizio-Fine del tratto per la prima curva di Bordo
+ Vector3d vtS2 ; pSubEdge2->GetStartDir( vtS2) ;
+ Vector3d vtE2 ; pSubEdge2->GetEndDir( vtE2) ;
+ double dLen2 = - EPS_SMALL ;
+ bool bSplit2 = ( vtS2 * vtE2 < COS_LIMIT) ;
+ if ( bSplit2) {
+ // Individuo il punto a Curvatura Massima
+ pSubEdge2->GetLength( dLen2) ;
+ double dKMax2 = - INFINITO + 1, dUK2Max = - EPS_SMALL ;
+ Point3d ptKMax2 ; Vector3d vtTanKMax2Prev, vtTanKMax2Next ;
+ for ( int i = 0 ; i <= NUM_SAMPLE_PNT ; ++ i) {
+ // Ricavo la Lunghezza corrente e il parametro dU associato
+ double dCurrLen2 = Clamp( i * ( dLen2 / NUM_SAMPLE_PNT), 0., dLen2) ;
+ double dUCurr2 ; pSubEdge2->GetParamAtLength( dCurrLen2, dUCurr2) ;
+ // Calcolo la Curvatura
+ Point3d ptCurrSub2 ;
+ Vector3d vtCurrSub2Der1Prev, vtCurrSub2Der2Prev, vtCurrSub2Der1Next, vtCurrSub2Der2Next ;
+ pSubEdge2->GetPointD1D2( dUCurr2, ICurve::FROM_MINUS, ptCurrSub2, &vtCurrSub2Der1Prev, &vtCurrSub2Der2Prev) ;
+ pSubEdge2->GetPointD1D2( dUCurr2, ICurve::FROM_PLUS, ptCurrSub2, &vtCurrSub2Der1Next, &vtCurrSub2Der2Next) ;
+ Vector3d vtCurrSub2Der1 = Media( vtCurrSub2Der1Prev, vtCurrSub2Der1Next) ;
+ Vector3d vtCurrSub2Der2 = Media( vtCurrSub2Der2Prev, vtCurrSub2Der2Next) ;
+ double dCurrK2 = ( vtCurrSub2Der1 ^ vtCurrSub2Der2).Len() / max( EPS_SMALL, Pow( vtCurrSub2Der1.Len(), 3)) ;
+ // Se maggiore della massima trovata, aggiorno la massima
+ if ( dCurrK2 > dKMax2) {
+ dKMax2 = dCurrK2 ;
+ ptKMax2 = ptCurrSub2 ;
+ dUK2Max = dUCurr2 ;
+ vtTanKMax2Prev = vtCurrSub2Der1Prev ;
+ vtTanKMax2Next = vtCurrSub2Der1Next ;
+ }
+ #if DEBUG_CURVATURE
+ _vPtK1.emplace_back( make_pair( ptCurrSub2, dCurrK2)) ;
+ #endif
+ }
+ vtTanKMax2Prev.Normalize() ;
+ vtTanKMax2Next.Normalize() ;
+ // Calcolo la nuova linea di sincronizzazione
+ CurvaturePoint myCurvaturePoint( dUK2Max, ptKMax2, vtTanKMax2Prev, vtTanKMax2Next) ;
+ BIPOINT SyncLine ;
+ CalcSyncPointFromCurvature( myCurvaturePoint, pSubEdge1, SyncLine) ;
+ // !<-- Inverto la curva di Sincronizzaione per coerenza con la prima -->!
+ swap( SyncLine.first, SyncLine.second) ;
+ vSyncLines.emplace_back( SyncLine) ;
+ }
+
+ #if DEBUG_CURVATURE // Curvatura minima -> AQUA | Curvatura massima -> ORANGE
+ auto [itMin1, itMax1] = std::minmax_element( _vPtK1.begin(), _vPtK1.end(), [](auto const& A, auto const& B) {
+ return A.second < B.second ;
+ }) ;
+ double _dK1Max = itMax1->second ;
+ double _dK1Min = itMin1->second ;
+ for ( int i = 0 ; i < ssize( _vPtK1) ; ++ i) {
+ double _t = 0. ;
+ if ( _dK1Max > _dK1Min)
+ _t = ( _vPtK1[i].second - _dK1Min) / ( _dK1Max - _dK1Min) ;
+ double _dh = 30 - 180. ; // AQUA -> HSV( 180, 1, 1) | ORANGE -> HSV( 30, 1, 1)
+ if ( _dh > 180.) _dh -= 360.0 ;
+ if ( _dh < -180.0) _dh += 360.0 ;
+ double _h = 180. + _t * _dh ;
+ if ( _h < 0.0) _h += 360.0 ;
+ if ( _h >= 360.0) _h -= 360.0 ;
+ PtrOwner _ptC( CreateGeoPoint3d()) ; _ptC->Set( _vPtK1[i].first) ;
+ int _nId = pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, Release( _ptC)) ;
+ pGeomDB->SetMaterial( _nId, Color( GetColorFromHSV( HSV( _h, 1., 1.)))) ;
+ }
+ auto [itMin2, itMax2] = std::minmax_element( _vPtK2.begin(), _vPtK2.end(), [](auto const& A, auto const& B) {
+ return A.second < B.second ;
+ }) ;
+ double _dK2Max = itMax2->second ;
+ double _dK2Min = itMin2->second ;
+ for ( int i = 0 ; i < ssize( _vPtK2) ; ++ i) {
+ double _t = 0. ;
+ if ( _dK2Max > _dK2Min)
+ _t = ( _vPtK2[i].second - _dK2Min) / ( _dK2Max - _dK2Min) ;
+ double _dh = 30 - 180. ; // CYAN -> HSV( 180, 1, 1) | ORANGE -> HSV( 30, 1, 1)
+ if ( _dh > 180.) _dh -= 360.0 ;
+ if ( _dh < -180.0) _dh += 360.0 ;
+ double _h = 180. + _t * _dh ;
+ if ( _h < 0.0) _h += 360.0 ;
+ if ( _h >= 360.0) _h -= 360.0 ;
+ PtrOwner _ptC( CreateGeoPoint3d()) ; _ptC->Set( _vPtK2[i].first) ;
+ int _nId = pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, Release( _ptC)) ;
+ pGeomDB->SetMaterial( _nId, Color( GetColorFromHSV( HSV( _h, 1., 1.)))) ;
+ }
+ #endif
+
+ // Se non ho alcuna linea di sincronizzazione, non faccio nulla
+ if ( vSyncLines.empty())
+ return true ;
+
+ const double TOL = 250. * EPS_SMALL ;
+
+ // Elimino tutte le curve di Sincronizzazione a ridosso degli estremi della Quadrangolazione
+ // NB. Risultano ridondanti, creano SottoQuadrangolazioni molto strette o possono Inclinare eccssivamente l'Utensile
+ // NB. Così facendo evito anche di creare curve di Sync lungo le diagonali della Quadrangolazione
+ const double LEN_TOL = 2. ;
+ for ( int i = 0 ; i < ssize( vSyncLines) ; ++ i) {
+ double dSyncLen1 ; pSubEdge1->GetLengthAtPoint( vSyncLines[i].first, dSyncLen1, TOL) ;
+ bool bErase = ( dSyncLen1 < max( LEN_TOL, 0.2 * dLen1) || dSyncLen1 > min( dLen1 - LEN_TOL, 0.8 * dLen1)) ;
+ if ( ! bErase) {
+ double dSyncLen2 ; pSubEdge2->GetLengthAtPoint( vSyncLines[i].second, dSyncLen2, TOL) ;
+ bErase = ( dSyncLen2 < max( LEN_TOL, 0.2 * dLen2) || dSyncLen2 > min( dLen2 - LEN_TOL, 0.8 * dLen2)) ;
+ }
+ if ( bErase) {
+ vSyncLines.erase( vSyncLines.begin() + i) ;
+ -- i ;
+ }
+ }
+ if ( vSyncLines.empty())
+ return true ;
+
+ // Se due curve di Sincronizzazione rimaste
+ if ( ssize( vSyncLines) == 2) {
+ // Se si sovrappongono, ne elimino una
+ if ( AreSamePointEpsilon( vSyncLines[0].first, vSyncLines[1].first, LEN_TOL) &&
+ AreSamePointEpsilon( vSyncLines[0].second, vSyncLines[1].second, LEN_TOL))
+ vSyncLines.pop_back() ;
+ }
+ // Se due curve di Sincronizzazione rimaste
+ if ( ssize( vSyncLines) == 2) {
+ // Ordino tutte le linee di sincronizzazione in base al parametro dU della curva principale
+ double dU0 ; pSubEdge1->GetParamAtPoint( vSyncLines[0].first, dU0, TOL) ;
+ double dU1 ; pSubEdge1->GetParamAtPoint( vSyncLines[1].first, dU1, TOL) ;
+ if ( dU0 > dU1 - EPS_SMALL)
+ swap( vSyncLines[0], vSyncLines[1]) ;
+ // Verifico che le curve non si intreccino
+ pSubEdge2->GetParamAtPoint( vSyncLines[0].second, dU0, TOL) ;
+ pSubEdge2->GetParamAtPoint( vSyncLines[1].second, dU1, TOL) ;
+ if ( dU0 > dU1 - EPS_SMALL)
+ vSyncLines.pop_back() ; // lascio solo la prima... ( bisognerebbe scegliere quale lasciare con un criterio migliore ?)
+ }
return true ;
}
@@ -6104,14 +6429,29 @@ ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComp
//----------------------------------------------------------------------------
bool
SurfBezier::CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, double dSampleLen)
+{
+ BIPNTVECTOR vSyncLines ;
+ return CreateSmoothRuledByTwoCurves( pCurve0, pCurve1, dSampleLen, vSyncLines) ;
+}
+
+//----------------------------------------------------------------------------
+bool
+SurfBezier::CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, double dSampleLen, BIPNTVECTOR& vSyncLines)
{
// converto in bezier le curve iniziali
- PtrOwner pCrvEdge1( GetCurveBezier( CurveToBezierCurve( pCurve0, 3, false))) ;
- PtrOwner pCrvEdge2( GetCurveBezier( CurveToBezierCurve( pCurve1, 3, false))) ;
+ PtrOwner pCrvEdge1( CurveToBezierCurve( pCurve0, 3, false)) ;
+ PtrOwner pCrvEdge2( CurveToBezierCurve( pCurve1, 3, false)) ;
if ( IsNull( pCrvEdge1) || IsNull( pCrvEdge2))
return false ;
+ #if SAVEPACEDISO
+ vGeo.clear() ;
+ vCol.clear() ;
+ #endif
+
+ // Verifico che la distanza di campionamento sia ammissibile
+ double dSampleDist = Clamp( dSampleLen, 2., 30.) ; // 20.0 sembra un passo di campionamento ideale
// Recupero parametri iniziali
double dLen1 ; pCrvEdge1->GetLength( dLen1) ;
double dLen2 ; pCrvEdge2->GetLength( dLen2) ;
@@ -6124,10 +6464,9 @@ SurfBezier::CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* p
Point3d ptPrev1, ptCurr1 ; pCrvEdge1->GetStartPoint( ptPrev1) ;
Point3d ptPrev2, ptCurr2 ; pCrvEdge2->GetStartPoint( ptPrev2) ;
Vector3d vtCurr1 = V_NULL, vtCurr2 = V_NULL ;
- BIPNTVECTOR vEdgeSyncLines ;
- while ( dLenPrev1 + dSampleLen < dLen1 - EPS_ZERO) {
+ while ( dLenPrev1 + dSampleDist < dLen1 - EPS_ZERO) {
// Recupero dU, Point3d e dLen corrente sul primo bordo, per un incremento del passo di campionamento
- dLenCurr1 = Clamp( dLenPrev1 + dSampleLen, 0., dLen1) ;
+ dLenCurr1 = Clamp( dLenPrev1 + dSampleDist, 0., dLen1) ;
pCrvEdge1->GetParamAtLength( dLenCurr1, dUCurr1) ;
pCrvEdge1->GetPointD1D2( dUCurr1, ICurve::FROM_MINUS, ptCurr1, &vtCurr1) ;
vtCurr1.Normalize() ;
@@ -6186,7 +6525,7 @@ SurfBezier::CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* p
}
// Verifico di non essermi allontanato troppo
double dLen ; pCrvEdge2->GetLengthAtParam( dUCurr2, dLen) ;
- bOkPlane = ( dLen < dLenPrev2 + 2. * dSampleLen) ;
+ bOkPlane = ( dLen < dLenPrev2 + 2. * dSampleDist) ;
}
if ( ! bOkPlane) {
// --- Altrimenti, cerco il punto a minima distanza
@@ -6196,11 +6535,11 @@ SurfBezier::CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* p
// Verifico di non essermi allontanato troppo
if ( bOkMinDist) {
double dLen ; pCrvEdge2->GetLengthAtParam( dUCurr2, dLen) ;
- bOkMinDist = ( dLen < dLenPrev2 + 2. * dSampleLen) ;
+ bOkMinDist = ( dLen < dLenPrev2 + 2. * dSampleDist) ;
}
if ( ! bOkMinDist) {
// --- Aumento la distanza corrente del passo di campionamento
- double dLen = Clamp( dLenPrev2 + dSampleLen, 0., dLen2) ;
+ double dLen = Clamp( dLenPrev2 + dSampleDist, 0., dLen2) ;
pCrvEdge2->GetParamAtLength( dLen, dUCurr2) ;
}
}
@@ -6213,10 +6552,10 @@ SurfBezier::CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* p
// Verifico se le direzioni tangenti sono tra di loro circa parallele
const double COS_ANG_TOL = cos( 15. * DEGTORAD) ;
if ( vtCurr1 * vtCurr2 < COS_ANG_TOL) {
- // Se fuori dalla tolleranza, recupero il miglior versore tangente sul secondo bordo nell'intervallo successivo di lunghezza ( 2. * dSampleLen)
+ // Se fuori dalla tolleranza, recupero il miglior versore tangente sul secondo bordo nell'intervallo successivo di lunghezza ( 2. * dMyDist)
pCrvEdge2->GetLengthAtPoint( ptCurr2, dLenCurr2) ;
- double dLimInfLen2 = Clamp( dLenCurr2 - dSampleLen, dLenPrev2, dLen2) ;
- double dLimSupLen2 = Clamp( dLenCurr2 + dSampleLen, dLenPrev2, dLen2) ;
+ double dLimInfLen2 = Clamp( dLenCurr2 - dSampleDist, dLenPrev2, dLen2) ;
+ double dLimSupLen2 = Clamp( dLenCurr2 + dSampleDist, dLenPrev2, dLen2) ;
// [Controllo migliorabile, magari mendiante metodo di bisezione (?)]
const int NUM_STEP = 20 ;
double dMinCos = - 1. - EPS_ZERO ;
@@ -6246,33 +6585,85 @@ SurfBezier::CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* p
pGeomDB->AddGeoObj( GDB_ID_NULL, nLay2, Release( vtGeo2)) ;
#endif
- // debug
- //// Inserisco le curve di sincronizzazione nel Layer di destinazine
- // PtrOwner pLine( CreateCurveLine()) ; pLine->Set( ptCurr1, ptCurr2) ;
- // pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrp, Release( pLine)) ;
+#if SAVEPACEDISO
+ // Inserisco le curve di sincronizzazione nel Layer di destinazine
+ PtrOwner pLine( CreateCurveLine()) ; pLine->Set( ptCurr1, ptCurr2) ;
+ vGeo.push_back( Release( pLine)) ;
+ vCol.push_back( LIME) ;
+#endif
+ vSyncLines.emplace_back( ptCurr1, ptCurr2) ;
- // --- Analisi degli spigoli all'interno della Quadrangolazione ---
- // Perchè si fa questa cosa ? Perchè parametrizzando per la lunghezza i SottoTratti ricavati, non è sempre detto
- // che uno spigolo di una curva sia sincronizzato con lo spigolo di un'altra ( se questi esistono)... Pertanto
- // la Bezier Ruled ricavata non è detto che sia in grado di approssimare lo spigolo correttamente, potrebbe sdondarlo
+ // --- Analisi degli spigoli all'interno della Quadrangolazione corrente ---
+ // NB. Non è sempre detto che uno spigolo di una curva sia sincronizzato con lo spigolo di un'altra ( se questi esistono)...
+ // Pertanto la Bezier Ruled ricavata non è detto che sia in grado di approssimare lo spigolo correttamente, potrebbe sdondarlo
PtrOwner pCrvQuad1( ConvertCurveToComposite( pCrvEdge1->CopyParamRange( dUPrev1, dUCurr1))) ;
PtrOwner pCrvQuad2( ConvertCurveToComposite( pCrvEdge2->CopyParamRange( dUPrev2, dUCurr2))) ;
+ BIPNTVECTOR vEdgeSyncLines ;
ManageEdgesInQuadrangulation( pCrvQuad1, pCrvQuad2, vEdgeSyncLines) ;
+#if SAVEPACEDISO
+ for ( int i = 0 ; i < ssize( vEdgeSyncLines) ; ++ i) {
+ PtrOwner pLine( CreateCurveLine()) ; pLine->Set( vEdgeSyncLines[i].first, vEdgeSyncLines[i].second) ;
+ vGeo.push_back( Release( pLine)) ;
+ vCol.push_back( GREEN) ;
+ }
+#endif
- //debug
- //for ( int i = 0 ; i < ssize( vEdgeSyncLines) ; ++ i) {
- // PtrOwner pLine( CreateCurveLine()) ; pLine->Set( vEdgeSyncLines[i].first, vEdgeSyncLines[i].second) ;
- // int nNewId = pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrp, Release( pLine)) ;
- // pGeomDB->SetMaterial( nNewId, GREEN) ;
- //}
-
+ // --- Aggiunta di Linee di Sync all'interno della Quandrangolazione corrente ---
+ // Perchè parametrizzando per la lunghezza i SottoTratti ricavati, nel caso di elevate variazioni angolari tra l'inizio e la fine
+ // ( tra due curva di Sync) si potrebbero generare delle torsioni non volute
+ // -->! NB. Queste linee vengono create considerando le SubQuadrangolazioni con gli Spigoli. !<--
+ BIPNTVECTOR vTwistSyncLines ;
+ if ( vEdgeSyncLines.empty())
+ ManageTwistInQuadrangulation( pCrvQuad1, pCrvQuad2, vTwistSyncLines) ;
+ else {
+ BIPOINT SyncLinePrev, SyncLineNext ;
+ pCrvQuad1->GetStartPoint( SyncLinePrev.first) ;
+ pCrvQuad2->GetStartPoint( SyncLinePrev.second) ;
+ for ( int i = 0 ; i < ssize( vEdgeSyncLines) ; ++ i) {
+ if ( i == ssize( vEdgeSyncLines) - 1) {
+ pCrvQuad1->GetEndPoint( SyncLineNext.first) ;
+ pCrvQuad2->GetEndPoint( SyncLineNext.second) ;
+ }
+ else {
+ SyncLineNext.first = vEdgeSyncLines[i].first ;
+ SyncLineNext.second = vEdgeSyncLines[i].second ;
+ }
+ // Recupero i parametri correnti
+ double dUS1, dUE1, dUS2, dUE2 ;
+ pCrvQuad1->GetParamAtPoint( SyncLinePrev.first, dUS1) ;
+ pCrvQuad2->GetParamAtPoint( SyncLinePrev.second, dUS2) ;
+ pCrvQuad1->GetParamAtPoint( SyncLineNext.first, dUE1) ;
+ pCrvQuad2->GetParamAtPoint( SyncLineNext.second, dUE2) ;
+ PtrOwner pCrvSubQuad1( ConvertCurveToComposite( pCrvQuad1->CopyParamRange( dUS1, dUE1))) ;
+ PtrOwner pCrvSubQuad2( ConvertCurveToComposite( pCrvQuad2->CopyParamRange( dUE1, dUE2))) ;
+ ManageTwistInQuadrangulation( pCrvSubQuad1, pCrvSubQuad2, vTwistSyncLines) ;
+ // Aggiorno i parametri
+ SyncLinePrev = SyncLineNext ;
+ }
+ }
+ // aggiungo le nuove curve ( non importa che siano in ordine di parametro)
+ vSyncLines.insert( vSyncLines.end(), vEdgeSyncLines.begin(), vEdgeSyncLines.end()) ;
+ vSyncLines.insert( vSyncLines.end(), vTwistSyncLines.begin(), vTwistSyncLines.end()) ;
+#if SAVEPACEDISO
+ for ( int i = 0 ; i < ssize( vTwistSyncLines) ; ++ i) {
+ PtrOwner pLine( CreateCurveLine()) ; pLine->Set( vTwistSyncLines[i].first, vTwistSyncLines[i].second) ;
+ vGeo.push_back( Release( pLine)) ;
+ vCol.push_back( OLIVE) ;
+ }
+#endif
// Aggiorno i parametri
ptPrev1 = ptCurr1 ; dUPrev1 = dUCurr1 ; dLenPrev1 = dLenCurr1 ;
ptPrev2 = ptCurr2 ; dUPrev2 = dUCurr2 ; dLenPrev2 = dLenCurr2 ;
}
- return CreateByIsoParamSet( pCrvEdge1, pCrvEdge2, vEdgeSyncLines) ;
+ #if SAVEPACEDISO
+ SaveGeoObj( vGeo, vCol, "D:\\Temp\\bezier\\ruled\\trimming\\smooth.nge") ;
+ #endif
+
+
+ // devo riempire vSyncLines
+ return CreateByIsoParamSet( pCrvEdge1, pCrvEdge2, vSyncLines) ;
}
//----------------------------------------------------------------------------
diff --git a/SurfBezier.h b/SurfBezier.h
index 7db854f..c765695 100644
--- a/SurfBezier.h
+++ b/SurfBezier.h
@@ -155,6 +155,7 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW
bool SwapParameters( void) ;
bool LimitSurfToTrimmedRegion( void) override ;
bool CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, double dSampleLen) override ;
+ bool CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, double dSampleLen, BIPNTVECTOR& vSyncLines) override ;
public : // IGeoObjRW
int GetNgeId( void) const override ;
diff --git a/Trimming.cpp b/Trimming.cpp
index 8e6d286..7e187f4 100644
--- a/Trimming.cpp
+++ b/Trimming.cpp
@@ -42,7 +42,6 @@
#include
// -------------------------- Debug --------------------------------------------
-#define DEBUG 0
#define DEBUG_BASIC_BORDERS 0
#define DEBUG_CHAIN_CURVES 0
#define DEBUG_ANG_APPROX 0
@@ -63,11 +62,12 @@
#define DEBUG_EDGES 0
#define DEBUG_SHAPE_STM 0
#define DEBUG_HOLES 0
+#define DEBUG_SMOOTH_CURVATURE 1
#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_SYNC_INTERPOLATION || \
DEBUG_BEZIER_RULED || DEBUG_CURVATURE || DEBUG_SIMPLE_PATCHES || DEBUG_SURF_PATCHES || \
- DEBUG_RAW_EDGES || DEBUG_EDGES || DEBUG_SHAPE_STM || DEBUG_HOLES || DEBUG
+ DEBUG_RAW_EDGES || DEBUG_EDGES || DEBUG_SHAPE_STM || DEBUG_HOLES || DEBUG_SMOOTH_CURVATURE
#include "CurveLine.h"
#include "/EgtDev/Include/EGkGeoObjSave.h"
#include "/EgtDev/Include/EgtPerfCounter.h"
@@ -284,58 +284,6 @@ GetPointSetByAngTol( const PolyLine& PL, double dAngTol, POLYLINEVECTOR& vPL)
return true ;
}
-//-----------------------------------------------------------------------------
-// Funzione per spezzare una curva compo in diversi tratti in corrispondenza
-// di cambi di direzione maggiori della tolleranza angolare passata
-static bool
-SplitCurveCompoByAngTol( const ICurveComposite* pCC, double dAngTol, ICRVCOMPOPOVECTOR& vCC)
-{
- int nCurves = pCC->GetCurveCount() ;
- vCC.emplace_back( CreateCurveComposite()) ;
- vCC.back()->AddCurve( pCC->GetCurve(0)->Clone()) ;
- // Cos della tolleranza angolare massima
- double dCosTol = cos( dAngTol * DEGTORAD) ;
-
- for ( int nC = 0 ; nC < nCurves - 2; ++ nC) {
- // Recupero l'angolo tra la fine della curva corrente e l'inizio della successiva
- const ICurve* pCrvCurr = pCC->GetCurve( nC) ;
- const ICurve* pCrvNext = pCC->GetCurve( nC + 1) ;
- Vector3d vtCurrEnd ; pCrvCurr->GetEndDir( vtCurrEnd) ;
- Vector3d vtNextStart ; pCrvNext->GetStartDir( vtNextStart) ;
- // Calcolo il Coseno tra i due versori
- double dCos = vtCurrEnd * vtNextStart ;
- // Se dentro alla tolleranza, allora i punti apparterranno alla stessa curva
- if ( dCos > dCosTol) {
- // Aggiungo la curva
- vCC.back()->AddCurve( pCrvNext->Clone()) ;
- }
- // Se tratto al di fuori della tolleranza, devo definire una nuova curva
- else {
- vCC.emplace_back( CreateCurveComposite()) ;
- vCC.back()->AddCurve( pCrvNext->Clone()) ;
- }
- }
-
- // Se curva originale chiusa
- if ( pCC->IsClosed() && ssize( vCC) > 1) {
- // Se ho più tratti, potrei riunire il primo con l'ultimo
- const ICurve* pCrvFirst = pCC->GetCurve( 0) ;
- const ICurve* pCrvLast = pCC->GetCurve( nCurves - 1) ;
- Vector3d vtFirstStart ; pCrvFirst->GetEndDir( vtFirstStart) ;
- Vector3d vtLastEnd ; pCrvLast->GetStartDir( vtLastEnd) ;
- // Calcolo il Coseno tra i due versori
- double dCos = vtFirstStart * vtLastEnd ;
- // Se dentro alla tolleranza, allora i punti appartengono alla stessa curva
- if ( dCos > dCosTol) {
- // Aggiungo la curva
- vCC.back()->AddCurve( Release( vCC.front())) ;
- vCC.erase( vCC.begin()) ;
- }
- }
-
- return true ;
-}
-
////-----------------------------------------------------------------------------
//// Funzione che approssima la curva di bordo per la costruzione della Bezier Ruled mediante
//// Patches di curve di Bezier
@@ -3959,26 +3907,26 @@ GetTrimmingSurfBzSyncPoints( const ICurve* pCrvEdge1, const ICurve* pCrvEdge2,
#endif
// Definisco la superficie di Bezier rigata
- PtrOwner pSBzRuled( GetBasicSurfBezier( GetSurfBezierRuled( pCompoEdge1, pCompoEdge2, ISurfBezier::RLT_B_MINDIST_PLUS, dMyLinTol))) ;
+ PtrOwner pSBzRuled( GetBasicSurfBezier( GetSurfBezierRuledSmooth( pCompoEdge1, pCompoEdge2, vSyncPoints, 10))) ;
if ( IsNull( pSBzRuled) || ! pSBzRuled->IsValid())
return false ;
- // Recupero i punti di sincronizzazione e li restituisco
- ICURVEPOVECTOR vCrv ;
- pSBzRuled->GetAllPatchesIsocurves( false, vCrv) ;
- vSyncPoints.reserve( vCrv.size()) ;
- for ( int i = 0 ; i < ssize( vCrv) ; ++ i) {
- if ( ! IsNull( vCrv[i]) && vCrv[i]->IsValid()) {
- #if DEBUG_SYNC_POINTS
- VT.emplace_back( vCrv[i]->Clone()) ;
- VC.emplace_back( LIME) ;
- #endif
- Point3d ptStart ; vCrv[i]->GetStartPoint( ptStart) ;
- Point3d ptEnd ; vCrv[i]->GetEndPoint( ptEnd) ;
- if ( ! AreSamePointApprox( ptStart, ptEnd))
- vSyncPoints.emplace_back( make_pair( ptStart, ptEnd)) ;
- }
- }
+ //// Recupero i punti di sincronizzazione e li restituisco
+ // ICURVEPOVECTOR vCrv ;
+ // pSBzRuled->GetAllPatchesIsocurves( false, vCrv) ;
+ // vSyncPoints.reserve( vCrv.size()) ;
+ // for ( int i = 0 ; i < ssize( vCrv) ; ++ i) {
+ // if ( ! IsNull( vCrv[i]) && vCrv[i]->IsValid()) {
+ // #if DEBUG_SYNC_POINTS
+ // VT.emplace_back( vCrv[i]->Clone()) ;
+ // VC.emplace_back( LIME) ;
+ // #endif
+ // Point3d ptStart ; vCrv[i]->GetStartPoint( ptStart) ;
+ // Point3d ptEnd ; vCrv[i]->GetEndPoint( ptEnd) ;
+ // if ( ! AreSamePointApprox( ptStart, ptEnd))
+ // vSyncPoints.emplace_back( make_pair( ptStart, ptEnd)) ;
+ // }
+ // }
#if DEBUG_SYNC_POINTS
SaveGeoObj( VT, VC, "C:\\Temp\\BorderSyncPoints.nge") ;
@@ -4219,7 +4167,8 @@ GetTrimmingRuledBezier( const CISURFPVECTOR& vSurf, const ICurve* pCrvEdge1,
// Se non ho punti di controllo forzati
if ( vSyncPoints.empty()) {
- pSurfBz.Set( GetSurfBezierRuledSmooth( pCompoEdge1, pCompoEdge2, 10)) ;
+ BIPNTVECTOR vSyncLines ;
+ pSurfBz.Set( GetSurfBezierRuledSmooth( pCompoEdge1, pCompoEdge2, vSyncLines, 10)) ;
if ( IsNull( pSurfBz) || ! pSurfBz->IsValid()) {
LOG_ERROR( GetEGkLogger(), "Error in Trimming : Ruled Bezier invalid") ;
return nullptr ;
@@ -4291,6 +4240,10 @@ GetTrimmingRuledBezier( const CISURFPVECTOR& vSurf, const ICurve* pCrvEdge1,
}
}
+ //////debug
+ //RegolarizeBordersLocally(pCrvEdge1,pCrvEdge2, pSurfBz, 0.2) ;
+ //return nullptr ;
+
return ( IsNull( pSurfBz) || ! pSurfBz->IsValid() ? nullptr : Release( pSurfBz)) ;
}
@@ -4950,3 +4903,160 @@ GetTrimmingHoleBorders( const CISURFPVECTOR& vpSurf, const Point3d& ptRef, doubl
return true ;
}
+
+
+struct PntInfo{
+ Point3d pt ;
+ int nSubCurve ;
+ int nPnt ;
+ double dDist ;
+ Vector3d vtN ;
+ int nSide ;
+ PntInfo( const Point3d& _pt, int _nSubCrv, int _nPnt, double _dDist, const Vector3d& _vtN, int _nSide) :
+ pt( _pt), nSubCurve( _nSubCrv), nPnt( _nPnt), dDist( _dDist), vtN( _vtN), nSide( _nSide) {;}
+};
+typedef vector PNTINFOVECTOR ;
+
+//------------------------------------------------------------------------------
+// Funzione per la regolarizzazione delle curve di bordo di una lavorazione di trim
+// Le curve vengono modificate entro una data tolleranza, in modo che
+bool
+RegolarizeBordersLocally( ISurfBezier* pSurfBz, const BIPOINT& bpIsoStart, const BIPOINT& bpIsoEnd, double dTol)
+{
+ #if DEBUG_SMOOTH_CURVATURE
+ VT.clear() ;
+ #endif
+
+ // prendo per buone le isocurve di inizio e fine tratto e devo identificare tra loro le isocurve che creano troppo twist e che sono da raddrizzare
+ const Point3d& ptS1 = bpIsoStart.first ;
+ const Point3d& ptS2 = bpIsoEnd.first ;
+ const Point3d& ptE1 = bpIsoStart.second ;
+ const Point3d& ptE2 = bpIsoEnd.second ;
+ int nDegU, nDegV, nSpanU, nSpanV ;
+ bool bRat, bTrimmed ;
+ pSurfBz->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bRat, bTrimmed) ;
+ if ( nDegU != 3)
+ return false ;
+ // individuo quali isocurve sono state indicate come inizio e fine
+ PtrOwner pCrv1( pSurfBz->GetSingleEdge3D( false, 2)) ;
+ PtrOwner pCrv2( pSurfBz->GetSingleEdge3D( false, 0)) ;
+ double dParS1 = -1 ; double dParS2 = -1 ;
+ if ( ! pCrv1->GetParamAtPoint( ptS1, dParS1) || ! pCrv1->GetParamAtPoint( ptS2, dParS2))
+ return false ;
+ double dParE1 = -1 ; double dParE2 = -1 ;
+ if ( ! pCrv2->GetParamAtPoint( ptE1, dParE1) || ! pCrv2->GetParamAtPoint( ptE2, dParE2))
+ return false ;
+ int nUS1 = int ( dParS1) ;
+ int nUS2 = int ( dParS2) ;
+ bool bInverted = false ;
+ if ( nUS1 > nUS2) {
+ swap( nUS1, nUS2) ;
+ swap( dParE1, dParE2) ;
+ bInverted = true ;
+ }
+
+ // scorro le isocurve a partire dallo start e dell'end della zona indicata
+ // controllo il twist rispetto alla isocurva precedente
+ Point3d ptPrevS = ptS1 ;
+ Point3d ptPrevE = ! bInverted ? bpIsoStart.second : bpIsoEnd.second ;
+ Vector3d vtIsoPrev = ptPrevE - ptPrevS ; vtIsoPrev.Normalize() ;
+ Point3d ptBez ; Vector3d vtNPrev ;
+ pSurfBz->GetPointNrmD1D2( nUS1, 0.5, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBez, vtNPrev) ;
+ int nPoints = ( nUS2 - nUS1) * nDegU + 1 ;
+ PNTVECTOR vPnt0 ; vPnt0.reserve( nPoints) ; vPnt0.push_back( ptPrevS) ;
+ PNTVECTOR vPnt1 ; vPnt1.reserve( nPoints) ;vPnt1.push_back( ptPrevE) ;
+ // salvo il secondo punto di controllo della patch
+ bool bOk = false ;
+ Point3d ptSecond1Curr = pSurfBz->GetControlPoint( nUS1 + 1, 0, &bOk) ;
+ vPnt0.push_back( ptSecond1Curr) ;
+ Point3d ptSecond2Curr = pSurfBz->GetControlPoint( nUS1 + 1, 1, &bOk) ;
+ vPnt1.push_back( ptSecond2Curr) ;
+ // scorro le isocurve di separazione tra patch
+ for ( int i = nUS1 + 3 ; i < nUS2 ; i +=3) {
+ // recupero precedente e successivo
+ Point3d ptThird1Curr = pSurfBz->GetControlPoint( i - 1, 0, &bOk) ;
+ Point3d ptThird2Curr = pSurfBz->GetControlPoint( i - 1, 1, &bOk) ;
+ Point3d ptSecond1Next = pSurfBz->GetControlPoint( i + 1, 0, &bOk) ;
+ Point3d ptSecond2Next = pSurfBz->GetControlPoint( i + 1, 1, &bOk) ;
+ // recupero corrente e verifico la torsione
+ Point3d ptCurrS = pSurfBz->GetControlPoint( i, 0, &bOk) ;
+ Point3d ptCurrE = pSurfBz->GetControlPoint( i, 1, &bOk) ;
+ Vector3d vtIsoCurr = ptCurrE - ptCurrS ;
+ double dDist = vtIsoCurr.Len() ;
+ vtIsoCurr.Normalize() ;
+ Vector3d vtDirPrev = vtIsoPrev ^ vtNPrev ;
+ Vector3d vtCurrInPlane = OrthoCompo( vtIsoCurr, vtDirPrev) ;
+ bool bDet = false ;
+ double dAng = 0 ; vtIsoPrev.GetRotation( vtCurrInPlane, vtDirPrev, dAng, bDet) ;
+ if ( abs( dAng) > 0) {
+ // se l'isocurva di separazione dalla patch successiva è torta rispetto alla precedente
+ // allora prendo il penultimo punto della curva corrente, l'ultimo e il secondo della prossima e li sposto lungo la normale della superficie
+ dDist *= dAng * DEGTORAD / 2 ;
+ ptThird1Curr += vtNPrev * dDist ;
+ ptCurrS += vtNPrev * dDist ;
+ ptSecond1Next += vtNPrev * dDist ;
+ ptThird2Curr -= vtNPrev * dDist ;
+ ptCurrE -= vtNPrev * dDist ;
+ ptSecond2Next -= vtNPrev * dDist ;
+ }
+ vPnt0.push_back( ptThird1Curr) ;
+ vPnt0.push_back( ptCurrS) ;
+ vPnt0.push_back( ptSecond1Next) ;
+
+ vPnt1.push_back( ptThird2Curr) ;
+ vPnt1.push_back( ptCurrE) ;
+ vPnt1.push_back( ptSecond2Next) ;
+
+ vtIsoPrev = ptCurrE - ptCurrS ; vtIsoPrev.Normalize() ;
+ vtNPrev = ( ptSecond1Next - ptCurrS) ^ vtIsoPrev ; vtNPrev.Normalize() ;
+ }
+
+ PtrOwner pCC1( CreateCurveComposite()) ;
+ PtrOwner pCC2( CreateCurveComposite()) ;
+ for ( int i = 0 ; i < ssize( vPnt0) - 3 ; i+=3) {
+ PtrOwner cb1( CreateCurveBezier()) ; cb1->Init( 3, false) ;
+ cb1->SetControlPoint( 0, vPnt0[i]) ;
+ cb1->SetControlPoint( 1, vPnt0[i+1]) ;
+ cb1->SetControlPoint( 2, vPnt0[i+2]) ;
+ cb1->SetControlPoint( 3, vPnt0[i+3]) ;
+ pCC1->AddCurve( Release( cb1)) ;
+
+ PtrOwner cb2( CreateCurveBezier()) ; cb2->Init( 3, false) ;
+ cb2->SetControlPoint( 0, vPnt1[i]) ;
+ cb2->SetControlPoint( 1, vPnt1[i+1]) ;
+ cb2->SetControlPoint( 2, vPnt1[i+2]) ;
+ cb2->SetControlPoint( 3, vPnt1[i+3]) ;
+ pCC2->AddCurve( Release( cb2)) ;
+ }
+
+ // controllo di essere rimasto in tolleranza
+ PtrOwner pCrvOrig1( pCrv1->CopyParamRange( nUS1, dParE1)) ;
+ PtrOwner pCrvOrig2( pCrv2->CopyParamRange( nUS2, dParE2)) ;
+ double dErr = 0 ;
+ CalcApproxError( pCrvOrig1, pCC1, dErr, 20) ;
+ if ( dErr > dTol)
+ return false ;
+ CalcApproxError( pCrvOrig2, pCC2, dErr, 20) ;
+ if ( dErr > dTol)
+ return false ;
+
+ // controllo di non aver creato dei cambi di concavità
+ // se ne trovo allora ruoto i terzetti attorno alla nuova isocurva
+ ////////////////// DA IMPLEMENTARE (prendendo dalla versione precedente della Regolarize)
+
+ // aggiorno i punti di controllo della superficie di bezier
+ for ( int i = 0 ; i < ssize( vPnt0) ; ++i) {
+ pSurfBz->SetControlPoint( nUS1 + i, 0, vPnt0[i]) ;
+ pSurfBz->SetControlPoint( nUS1 + i, 1, vPnt1[i]) ;
+ }
+ #if DEBUG_SMOOTH_CURVATURE
+ VT.push_back( Release(pCC1)) ;
+ VT.push_back( Release(pCC2)) ;
+ VT.push_back( Release(pCrv1)) ;
+ VT.push_back( Release(pCrv2)) ;
+ VT.push_back(pSurfBz->Clone());
+ SaveGeoObj( VT, "C:\\Temp\\bezier\\ruled\\smoothness\\regolarized.nge") ;
+ #endif
+
+ return true ;
+}