EgtGeomKernel :

- nuovo paradigma per la bezier ruled.
This commit is contained in:
Daniele Bariletti
2026-04-10 09:20:02 +02:00
parent a27b9e871a
commit cb2b63320a
3 changed files with 282 additions and 42 deletions
+1 -1
View File
@@ -726,7 +726,7 @@ GetSurfBezierRuled( const ICurve* pCurve1, const ICurve* pCurve2, int nType, dou
// creo e setto la superficie trimesh
PtrOwner<SurfBezier> pSbz( CreateBasicSurfBezier()) ;
if ( IsNull( pSbz) || ! pSbz->CreateByTwoCurves( pCC1, pCC2, nType))
if ( IsNull( pSbz) || ! pSbz->CreateSmoothByTwoCurves( pCC1, pCC2, 10))
return nullptr ;
// restituisco la superficie
+280 -41
View File
@@ -52,7 +52,9 @@
#define SAVEMATCHCURVES 0
#define SAVEFAILEDTREE 0
#define SAVELIMITSURF 0
#if SAVEFAILEDTRIANGULATION || SAVEREBUILTISO || SAVERULEDISO || SAVERULEDGUIDEDISO || SAVEMATCHCURVES || SAVEFAILEDTREE || SAVELIMITSURF
#define SAVEPACEDISO 1
#if SAVEFAILEDTRIANGULATION || SAVEREBUILTISO || SAVERULEDISO || SAVERULEDGUIDEDISO || SAVEMATCHCURVES \
|| SAVEFAILEDTREE || SAVELIMITSURF || SAVEPACEDISO
#include "/EgtDev/Include/EGkGeoObjSave.h"
std::vector<IGeoObj*> vGeo ;
#endif
@@ -5213,19 +5215,6 @@ SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int
i = c ;
}
}
//// faccio un merge di regioni adiacenti di mismatch
//int nCurr = 0, nNext = 1 ;
//while ( nNext < ssize( vMismatch0)) {
// if ( vMismatch0[nNext].first - vMismatch0[nCurr].second < 2 + EPS_SMALL) {
// vMismatch0[nCurr].second = vMismatch0[nNext].second ;
// }
// else {
// ++nCurr ;
// vMismatch0[nCurr] = vMismatch0[nNext] ;
// }
// ++nNext ;
//}
//vMismatch0.resize( nCurr + 1) ;
DBLVECTOR vdDistMismatch1 ;
int nPnt1 = CrvU1.GetCurveCount() ;
@@ -5248,19 +5237,6 @@ SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int
i = c ;
}
}
//// faccio un merge di regioni adiacenti di mismatch
//nCurr = 0, nNext = 1 ;
//while ( nNext < ssize( vMismatch1)) {
// if ( vMismatch1[nNext].first - vMismatch1[nCurr].second < 2 + EPS_SMALL) {
// vMismatch1[nCurr].second = vMismatch1[nNext].second ;
// }
// else {
// ++nCurr ;
// vMismatch1[nCurr] = vMismatch1[nNext] ;
// }
// ++nNext ;
//}
//vMismatch1.resize( nCurr + 1) ;
// verifico la presenza di eventuali "edge" lungo le polyline ( punti di passaggio di un edge e quindi cambi bruschi di direzione della polyline)
BOOLVECTOR vEdgeSplit0, vEdgeSplit1 ;
@@ -5920,6 +5896,263 @@ SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int
return true ;
}
struct Edge {
Vector3d vtPrev ;
Vector3d vtCurr ;
Point3d ptCurr ;
Edge(const Vector3d& _vtPrev, const Vector3d& _vtCurr, const Point3d& _ptCurr) :
vtPrev( _vtPrev), vtCurr( _vtCurr), ptCurr( _ptCurr) {;}
};
typedef vector<Edge> EDGEVECTOR ;
//----------------------------------------------------------------------------
bool
SurfBezier::CreateSmoothByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, double dSampleLen)
{
// converto in bezier la curva iniziale
CurveComposite CrvU0 ;
// se la curva è già una bezier singola la tengo, sennò la converto
if ( pCurve0->GetType() != CRV_BEZIER) {
// se è una compo controllo che siano già tutte bezier
bool bAlreadyBez = true ;
if ( pCurve0->GetType() == CRV_COMPO) {
const ICurveComposite* pCC0 = GetBasicCurveComposite( pCurve0) ;
for ( int i = 0 ; i < pCC0->GetCurveCount() ; ++i) {
if ( pCC0->GetCurve( i)->GetType() != CRV_BEZIER) {
bAlreadyBez = false ;
break ;
}
}
}
else
bAlreadyBez = false ;
if ( ! bAlreadyBez)
CrvU0.AddCurve( CurveToBezierCurve( pCurve0)) ;
else
CrvU0.AddCurve( pCurve0->Clone()) ;
}
else
CrvU0.AddCurve( pCurve0->Clone()) ;
if ( ! CrvU0.IsValid())
return false ;
// recupero span e grado nel parametro U
int nSpanU0 = int( CrvU0.GetCurveCount()) ;
int nDegU0 = ( GetCurveBezier( CrvU0.GetCurve(0)))->GetDegree() ;
bool bRat0 = (GetCurveBezier( CrvU0.GetCurve(0)))->IsRational() ;
// se la curva è già una bezier singola la tengo, sennò la converto
CurveComposite CrvU1 ;
// se la curva è già una bezier singola la tengo, sennò la converto
if ( pCurve1->GetType() != CRV_BEZIER) {
// se è una compo controllo che siano già tutte bezier
bool bAlreadyBez = true ;
if ( pCurve1->GetType() == CRV_COMPO) {
const ICurveComposite* pCC1 = GetBasicCurveComposite( pCurve1) ;
for ( int i = 0 ; i < pCC1->GetCurveCount() ; ++i) {
if ( pCC1->GetCurve( i)->GetType() != CRV_BEZIER) {
bAlreadyBez = false ;
break ;
}
}
}
else
bAlreadyBez = false ;
if ( ! bAlreadyBez)
CrvU1.AddCurve( CurveToBezierCurve( pCurve1)) ;
else
CrvU1.AddCurve( pCurve1->Clone()) ;
}
else
CrvU1.AddCurve( pCurve1->Clone()) ;
// recupero span e grado nel parametro U
int nSpanU1 = int( CrvU1.GetCurveCount()) ;
int nDegU1 = ( GetCurveBezier( CrvU1.GetCurve(0)))->GetDegree() ;
bool bRat1 = (GetCurveBezier( CrvU1.GetCurve(0)))->IsRational() ;
// se le due curve hanno grado diverso allora aumento il grado di quella con grado inferiore
if ( nDegU0 != nDegU1) {
while ( nDegU0 < nDegU1) {
CurveComposite CC ;
for ( int k = 0 ; k < nSpanU0 ; ++k)
CC.AddCurve( BezierIncreaseDegree( GetCurveBezier( CrvU0.GetCurve( k)))) ;
++nDegU0 ;
CrvU0 = CC ;
}
while ( nDegU0 > nDegU1) {
CurveComposite CC ;
for ( int k = 0 ; k < nSpanU0 ; ++k)
CC.AddCurve( BezierIncreaseDegree( GetCurveBezier( CrvU1.GetCurve( k)))) ;
++nDegU1 ;
CrvU1 = CC ;
}
}
// omogenizzo la razionalità
if ( bRat0 != bRat1) {
if ( bRat0) {
CurveComposite CC ;
for ( int k = 0 ; k < nSpanU0 ; ++k) {
const ICurveBezier* pCrvBez = GetCurveBezier( CrvU0.GetCurve( k)) ;
CC.AddCurve( EditBezierCurve( pCrvBez, nDegU0, false)) ;
}
CrvU0 = CC ;
bRat0 = false ;
}
if ( bRat1) {
CurveComposite CC ;
for ( int k = 0 ; k < nSpanU1 ; ++k) {
const ICurveBezier* pCrvBez = GetCurveBezier( CrvU1.GetCurve( k)) ;
CC.AddCurve( EditBezierCurve( pCrvBez, nDegU0, false)) ;
}
CrvU1 = CC ;
bRat1 = false ;
}
}
if ( nDegU0 != nDegU1)
return false ;
int nDegU = nDegU0 ;
// in V decido che la funzione è una patch di grado 1
int nSpanV = 1 ;
int nDegV = 1 ;
bool bIsClosed0 = CrvU0.IsClosed() ;
bool bIsClosed1 = CrvU1.IsClosed() ;
BIPNTVECTOR vPairs ;
// Recupero parametri iniziali
double dLen0 ; CrvU0.GetLength( dLen0) ;
double dLen1 ; CrvU1.GetLength( dLen1) ;
double dUS0, dUE0 ; CrvU0.GetDomain( dUS0, dUE0) ;
double dUS1, dUE1 ; CrvU1.GetDomain( dUS1, dUE1) ;
double dLenPrev0 = 0., dLenCurr0 = 0. ;
double dLenPrev1 = 0., dLenCurr1 = 0. ;
double dUPrev0 = 0., dUCurr0 = 0. ;
double dUPrev1 = 0., dUCurr1 = 0. ;
Point3d ptPrev0, ptCurr0 ; CrvU0.GetStartPoint( ptPrev0) ;
Point3d ptPrev1, ptCurr1 ; CrvU1.GetStartPoint( ptPrev1) ;
Vector3d vtCurr0 = V_NULL, vtCurr1 = V_NULL ;
#if SAVEPACEDISO
vGeo.clear() ;
#endif
while ( dLenPrev0 + dSampleLen < dLen0 - EPS_ZERO) {
// Recupero dU, Point3d e dLen corrente sul primo bordo, per un incremento del passo di campionamento
dLenCurr0 = Clamp( dLenPrev0 + dSampleLen, 0., dLen0) ;
CrvU0.GetParamAtLength( dLenCurr0, dUCurr0) ;
CrvU0.GetPointD1D2( dUCurr0, ICurve::FROM_MINUS, ptCurr0, &vtCurr0) ;
vtCurr0.Normalize() ;
// --- Piano di taglio per punto a minima distanza
IntersCurvePlane ICP( CrvU1, ptCurr0, vtCurr0) ;
bool bOkPlane = ( ICP.GetIntersPointNearTo( ptPrev1, ptCurr1, dUCurr1) && dUCurr1 > dUPrev1) ;
if ( ! bOkPlane) {
// --- Cerco il punto a minima distanza
DistPointCurve DPC( ptCurr0, CrvU1) ;
int nFlag ;
bool bOkMinDist = ( DPC.GetParamAtMinDistPoint( dUPrev1, dUCurr1, nFlag) && dUCurr1 > dUPrev1) ;
if ( ! bOkMinDist) {
// --- Aumento la distanza corrente del passo di campionamento
double dLen = Clamp( dLenPrev1 + dSampleLen, 0., dLen1) ;
CrvU1.GetParamAtLength( dLen, dUCurr1) ;
}
}
// Recupero il punto corrente e la direzione tangente sul secondo bordo
CrvU1.GetLengthAtParam( dUCurr1, dLenCurr1) ;
CrvU1.GetPointD1D2( dUCurr1, ICurve::FROM_MINUS, ptCurr1, &vtCurr1) ;
vtCurr1.Normalize() ;
// Verifico se le direzioni tangenti sono tra di loro circa parallele
const double COS_ANG_TOL = cos( 10. * DEGTORAD) ;
if ( vtCurr0 * vtCurr1 < COS_ANG_TOL) {
// Se fuori dalla tolleranza, recupero il miglior versore tangente sul secondo bordo nell'intervallo successivo di lunghezza ( 1. * dMyDist)
CrvU1.GetLengthAtPoint( ptCurr1, dLenCurr1) ;
double dLimInfLen1 = Clamp( dLenCurr1 - dSampleLen, dLenPrev1, dLen1) ;
double dLimSupLen1 = Clamp( dLenCurr1 + dSampleLen, dLenPrev1, dLen1) ;
// [Controllo migliorabile, magari mendiante metodo di bisezione (?)]
const int NUM_STEP = 20 ;
double dMinCos = - 1. - EPS_ZERO ;
for ( int i = 0 ; i <= NUM_STEP ; ++ i) {
double dLen = dLimInfLen1 + i * ( dLimSupLen1 - dLimInfLen1) / NUM_STEP ;
double dUStep1 ; CrvU1.GetParamAtLength( dLen, dUStep1) ;
Point3d ptStep1 ; Vector3d vtStep1 = V_NULL ;
CrvU1.GetPointD1D2( dUStep1, ICurve::FROM_MINUS, ptStep1, &vtStep1) ; vtStep1.Normalize() ;
double dStepCos1 = vtCurr0 * vtStep1 ;
if ( dStepCos1 > dMinCos) {
ptCurr1 = ptStep1 ;
vtCurr1 = vtStep1 ;
dUCurr1 = dUStep1 ;
dMinCos = dStepCos1 ;
}
}
}
// analizzo l'eventuale presenza di edge
int nSubCrv = int( ceil( dUPrev0)) ;
EDGEVECTOR vEdge0, vEdge1 ;
double dCosEdge = cos( 35. * DEGTORAD) ;
while ( nSubCrv < dUCurr0) {
if ( nSubCrv == 0 && ! bIsClosed0)
continue ;
int nPrevCrv = ( nSubCrv > 0 ? nSubCrv - 1 : int( dUE0 - 1)) ;
Vector3d vtPrev ; CrvU0.GetCurve( nPrevCrv)->GetEndDir( vtPrev) ;
Point3d ptCurr ; CrvU0.GetCurve( nPrevCrv)->GetEndPoint( ptCurr) ;
CrvU0.GetCurve( nSubCrv)->GetStartDir( vtCurr0) ;
vtCurr0.Normalize() ;
vtPrev.Normalize() ;
if ( vtPrev * vtCurr0 < dCosEdge)
vEdge0.emplace_back( vtPrev, vtCurr0, ptCurr) ;
++ nSubCrv ;
}
nSubCrv = int( ceil( dUPrev1)) ;
while ( nSubCrv < dUCurr1) {
if ( nSubCrv == 0 && ! bIsClosed0)
continue ;
int nPrevCrv = ( nSubCrv > 0 ? nSubCrv - 1 : int( dUE1 - 1)) ;
Vector3d vtPrev ; CrvU1.GetCurve( nPrevCrv)->GetEndDir( vtPrev) ;
Point3d ptCurr ; CrvU1.GetCurve( nPrevCrv)->GetEndPoint( ptCurr) ;
CrvU1.GetCurve( nSubCrv)->GetStartDir( vtCurr1) ;
vtCurr1.Normalize() ;
vtPrev.Normalize() ;
if ( vtPrev * vtCurr1 < dCosEdge)
vEdge1.emplace_back( vtPrev, vtCurr1, ptCurr) ;
++ nSubCrv ;
}
if ( ssize( vEdge0) > 0 && ssize( vEdge1) > 0) {
int c = 0 ;
for ( int i = 0 ; i < ssize( vEdge0) ; ++i) {
for ( int j = c ; j < ssize( vEdge1) ; ++j) {
if ( vEdge0[i].vtPrev * vEdge1[j].vtPrev > COS_ANG_TOL || vEdge0[i].vtCurr * vEdge1[j].vtCurr > COS_ANG_TOL) {
vPairs.emplace_back( vEdge0[i].ptCurr, vEdge1[j].ptCurr) ;
c = j + 1 ;
break ;
}
}
}
}
#if SAVEPACEDISO
ICurveLine* CL = CreateCurveLine() ; CL->Set( ptCurr0, ptCurr1) ;
vGeo.push_back( CL) ;
#endif
// Inserisco le curve di sincronizzazione nel Layer di destinazine
vPairs.emplace_back( ptCurr0, ptCurr1) ;
// Aggiorno i parametri
ptPrev0 = ptCurr0 ; dUPrev0 = dUCurr0 ; dLenPrev0 = dLenCurr0 ;
ptPrev1 = ptCurr1 ; dUPrev1 = dUCurr1 ; dLenPrev1 = dLenCurr1 ;
}
#if SAVEPACEDISO
SaveGeoObj( vGeo, "D:\\Temp\\bezier\\ruled\\smoothness\\iso.nge") ;
#endif
return CreateByIsoParamSet( &CrvU0, &CrvU1, vPairs) ;
}
//----------------------------------------------------------------------------
bool
SurfBezier::FindMatchByParam( const PolyLine& pl0, const PolyLine& pl1, INTVECTOR& vMatch, int& nLong) const
@@ -6535,14 +6768,17 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c
// se non ho corrispondenza allora aggiungo uno split sulla curva a cui manca il punto corrispondente
else if ( vdParamPos0[c0] < vdParamPos1[c1]) {
double dPar ; CrvU1.GetParamAtLength( dLenPrev1 + dLen1 * vdParamPos0[c0], dPar) ;
if ( abs( dPar - round( dPar)) > EPS_SMALL) {
vdSplit1.push_back( dPar) ;
nSplit1 = vdSplit1.size() ;
}
else if ( dPar = round( dPar) ; dPar > nLastParam1){
++ c1 ;
++ nLastParam1 ;
if ( dPar > dLastParam1 + EPS_PARAM) {
if ( abs( dPar - round( dPar)) > EPS_SMALL) {
vdSplit1.push_back( dPar) ;
nSplit1 = vdSplit1.size() ;
}
else if ( dPar = round( dPar) ; dPar > nLastParam1){
++ c1 ;
++ nLastParam1 ;
}
}
dLastParam1 = dPar ;
++nLastParam0 ;
vPairs.emplace_back( nLastParam0 + nSplit0, nLastParam1 + nSplit1) ;
++c0 ;
@@ -6550,14 +6786,17 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c
else if ( vdParamPos0[c0] > vdParamPos1[c1]) {
double dPar ; CrvU0.GetParamAtLength( dLenPrev0 + dLen0 * vdParamPos1[c1], dPar) ;
// se lo split non è in prossimità di una joint già esistente allora lo aggiungo
if ( abs( dPar - round( dPar)) > EPS_SMALL) {
vdSplit0.push_back( dPar) ;
nSplit0 = vdSplit0.size() ;
}
else if ( dPar = round( dPar) ; dPar > nLastParam0){
++ c0 ;
++ nLastParam0 ;
if ( dPar > dLastParam0 + EPS_PARAM) {
if ( abs( dPar - round( dPar)) > EPS_SMALL) {
vdSplit0.push_back( dPar) ;
nSplit0 = vdSplit0.size() ;
}
else if ( dPar = round( dPar) ; dPar > nLastParam0){
++ c0 ;
++ nLastParam0 ;
}
}
dLastParam0 = dPar ;
++nLastParam1 ;
vPairs.emplace_back( nLastParam0 + nSplit0, nLastParam1 + nSplit1) ;
++c1 ;
+1
View File
@@ -154,6 +154,7 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW
bool RemoveCollapsedSpans( void) override ;
bool SwapParameters( void) ;
bool LimitSurfToTrimmedRegion( void) override ;
bool CreateSmoothByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, double dSampleLen) override ;
public : // IGeoObjRW
int GetNgeId( void) const override ;