Merge branch 'Trimming'

This commit is contained in:
Daniele Bariletti
2026-04-21 15:05:12 +02:00
6 changed files with 654 additions and 143 deletions
+7 -1
View File
@@ -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) ;
+3
View File
@@ -557,6 +557,9 @@
</ClCompile>
<ClCompile Include="MultiGeomDB.cpp">
<Filter>File di origine\Gdb</Filter>
</ClCompile>
<ClCompile Include="Trimming.cpp">
<Filter>File di origine\GeoTrimming</Filter>
</ClCompile>
<ClCompile Include="DistPointSurfBz.cpp">
<Filter>File di origine\GeoDist</Filter>
+2 -2
View File
@@ -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<SurfBezier> pSbz( CreateBasicSurfBezier()) ;
if ( IsNull( pSbz) || ! pSbz->CreateSmoothRuledByTwoCurves( pCC1, pCC2, dSampleLen))
if ( IsNull( pSbz) || ! pSbz->CreateSmoothRuledByTwoCurves( pCC1, pCC2, dSampleLen, vSyncLines))
return nullptr ;
// restituisco la superficie
+459 -68
View File
@@ -57,6 +57,7 @@
|| SAVEFAILEDTREE || SAVELIMITSURF || SAVEPACEDISO
#include "/EgtDev/Include/EGkGeoObjSave.h"
std::vector<IGeoObj*> vGeo ;
std::vector<Color> 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<SharpEdge> 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<SharpEdge> 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<double, 2> 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<pair<BIPOINT, double>> 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<pair<Point3d, double>> _vPtK1 ;
vector<pair<Point3d, double>> _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<IGeoPoint3d> _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<IGeoPoint3d> _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<ICurveBezier> pCrvEdge1( GetCurveBezier( CurveToBezierCurve( pCurve0, 3, false))) ;
PtrOwner<ICurveBezier> pCrvEdge2( GetCurveBezier( CurveToBezierCurve( pCurve1, 3, false))) ;
PtrOwner<ICurve> pCrvEdge1( CurveToBezierCurve( pCurve0, 3, false)) ;
PtrOwner<ICurve> 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<ICurveLine> 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<ICurveLine> 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<ICurveComposite> pCrvQuad1( ConvertCurveToComposite( pCrvEdge1->CopyParamRange( dUPrev1, dUCurr1))) ;
PtrOwner<ICurveComposite> pCrvQuad2( ConvertCurveToComposite( pCrvEdge2->CopyParamRange( dUPrev2, dUCurr2))) ;
BIPNTVECTOR vEdgeSyncLines ;
ManageEdgesInQuadrangulation( pCrvQuad1, pCrvQuad2, vEdgeSyncLines) ;
#if SAVEPACEDISO
for ( int i = 0 ; i < ssize( vEdgeSyncLines) ; ++ i) {
PtrOwner<ICurveLine> 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<ICurveLine> 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<ICurveComposite> pCrvSubQuad1( ConvertCurveToComposite( pCrvQuad1->CopyParamRange( dUS1, dUE1))) ;
PtrOwner<ICurveComposite> 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<ICurveLine> 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) ;
}
//----------------------------------------------------------------------------
+1
View File
@@ -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 ;
+182 -72
View File
@@ -42,7 +42,6 @@
#include <numeric>
// -------------------------- 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<SurfBezier> pSBzRuled( GetBasicSurfBezier( GetSurfBezierRuled( pCompoEdge1, pCompoEdge2, ISurfBezier::RLT_B_MINDIST_PLUS, dMyLinTol))) ;
PtrOwner<SurfBezier> 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<PntInfo> 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<ICurveComposite> pCrv1( pSurfBz->GetSingleEdge3D( false, 2)) ;
PtrOwner<ICurveComposite> 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<ICurveComposite> pCC1( CreateCurveComposite()) ;
PtrOwner<ICurveComposite> pCC2( CreateCurveComposite()) ;
for ( int i = 0 ; i < ssize( vPnt0) - 3 ; i+=3) {
PtrOwner<ICurveBezier> 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<ICurveBezier> 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<ICurve> pCrvOrig1( pCrv1->CopyParamRange( nUS1, dParE1)) ;
PtrOwner<ICurve> 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 ;
}