EgtGeomKernel :

- aggiunte funzioni per la creazione delle smooth ruled bezier.
This commit is contained in:
Daniele Bariletti
2026-04-10 18:20:22 +02:00
parent c95ef6764d
commit 9220fd568f
4 changed files with 355 additions and 236 deletions
+37 -1
View File
@@ -726,7 +726,43 @@ GetSurfBezierRuled( const ICurve* pCurve1, const ICurve* pCurve2, int nType, dou
// creo e setto la superficie trimesh
PtrOwner<SurfBezier> pSbz( CreateBasicSurfBezier()) ;
if ( IsNull( pSbz) || ! pSbz->CreateSmoothByTwoCurves( pCC1, pCC2, 10))
if ( IsNull( pSbz) || ! pSbz->CreateByTwoCurves( pCC1, pCC2, nType))
return nullptr ;
// restituisco la superficie
return Release( pSbz) ;
}
//-------------------------------------------------------------------------------
ISurfBezier*
GetSurfBezierRuledSmooth( const ICurve* pCurve1, const ICurve* pCurve2, double dSampleLen)
{
// verifica parametri
if ( pCurve1 == nullptr || pCurve2 == nullptr)
return nullptr ;
// dLinTol servirà quando ci sarà la funzione ApproxWithCurveBezier
// se la curva è già una bezier singola la tengo, sennò la converto
PtrOwner<ICurveComposite> pCC1( CreateCurveComposite()) ;
if ( pCurve1->GetType() != CRV_BEZIER)
pCC1->AddCurve( CurveToBezierCurve( pCurve1, 3, false)) ;
else
pCC1->AddCurve( pCurve1->Clone()) ;
if ( IsNull( pCC1) || ! pCC1->IsValid())
return nullptr ;
// se la curva è già una bezier singola la tengo, sennò la converto
PtrOwner<ICurveComposite> pCC2( CreateCurveComposite()) ;
if ( pCurve2->GetType() != CRV_BEZIER)
pCC2->AddCurve( CurveToBezierCurve( pCurve2, 3, false)) ;
else
pCC2->AddCurve( pCurve2->Clone()) ;
if ( IsNull( pCC2) || ! pCC2->IsValid())
return nullptr ;
// creo e setto la superficie trimesh
PtrOwner<SurfBezier> pSbz( CreateBasicSurfBezier()) ;
if ( IsNull( pSbz) || ! pSbz->CreateSmoothRuledByTwoCurves( pCC1, pCC2, dSampleLen))
return nullptr ;
// restituisco la superficie
+316 -233
View File
@@ -5896,173 +5896,272 @@ 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 ;
struct SharpEdge {
double dParU ;
Point3d ptEdge ;
Vector3d vtTanPrev, vtTanAft ;
SharpEdge( double dU, const Point3d ptE, const Vector3d& vtTP, const Vector3d& vtTA)
: dParU( dU), ptEdge( ptE), vtTanPrev( vtTP), vtTanAft( vtTA) {}
} ;
typedef vector<SharpEdge> SHARPEDGEVECTOR ;
//----------------------------------------------------------------------------
bool
SurfBezier::CreateSmoothByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, double dSampleLen)
static bool
CalcSyncPointFromEdge( const SHARPEDGEVECTOR& vSharpEdge, const ICurveComposite* pCompoSubEdge, const SHARPEDGEVECTOR& vSharpSubEdge,
BIPNTVECTOR& vSyncLines)
{
// 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 ;
}
}
vSyncLines.clear() ;
if ( nDegU0 != nDegU1)
// Verifico la validità del SubEdge su cui trovare il punto di Sincronizzazione
if ( pCompoSubEdge == nullptr || ! pCompoSubEdge->IsValid())
return false ;
int nDegU = nDegU0 ;
// Se non ho spigoli da controllare, non devo fare nulla
if ( vSharpEdge.empty())
return true ;
// in V decido che la funzione è una patch di grado 1
int nSpanV = 1 ;
int nDegV = 1 ;
// Scorro gli SharpEdges
double dUPrevSubEdge = 0., dUCurrSubEdge = 0. ;
for ( const SharpEdge& mySharpEdge : vSharpEdge) {
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 ;
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) ;
int nIndParCloser = - 0 ;
int nIndPointCloser = -0 ;
// 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)) ;
int nIndParCloser = -1, nIndPointCloser = -1 ;
double dSqMinDist = INFINITO ;
for ( int nInfo = 0 ; nInfo < ICP.GetIntersCount() ; ++ nInfo) {
IntCrvPlnInfo aInfo ;
if ( ICP.GetIntCrvPlnInfo( nInfo, aInfo) && aInfo.Ici[0].dU > dUPrev1) {
if ( nIndParCloser == -0)
if ( ICP.GetIntCrvPlnInfo( nInfo, aInfo) && aInfo.Ici[0].dU > dUPrevSubEdge) {
if ( nIndParCloser == -1)
nIndParCloser = nInfo ;
double dSqDist = SqDist( ptCurr0, aInfo.Ici[0].ptI) ;
double dSqDist = SqDist( mySharpEdge.ptEdge, aInfo.Ici[0].ptI) ;
if ( dSqDist < dSqMinDist) {
dSqMinDist = dSqDist ;
nIndPointCloser = nInfo ;
}
}
}
bool bOkPlane = ( nIndParCloser != -0 && nIndPointCloser != -0) ;
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) ;
dUCurr1 = aInfo.Ici[0].dU ;
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) ;
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. ;
}
}
}
// Verifico se tale parametro può essere avvicinato ad uno Spigolo presente sulla curva
if ( ! vSharpSubEdge.empty()) {
const double EDGE_LEN_TOL = 5. ;
for ( const SharpEdge& mySharpSubEdge : vSharpSubEdge) {
// Se la linea di sincronizzazione è progressiva in parametro (ovvero non si attorciglia)
if ( mySharpSubEdge.dParU > dUPrevSubEdge) {
double dLenSub ; pCompoSubEdge->GetLengthAtParam( mySharpSubEdge.dParU, dLenSub) ;
double dLenSync ; pCompoSubEdge->GetLengthAtParam( dUCurrSubEdge, dLenSync) ;
// E Sufficientemente vicina ad uno Spigolo sull'altra
if ( abs( dLenSync - dLenSub) < EDGE_LEN_TOL) {
// Sposto il suo punto finale sullo Spigolo
dUCurrSubEdge = mySharpSubEdge.dParU ;
break ; // prendo la prima dato che sono ordinate per parametro
}
}
}
}
// Definisco una nuova linea dallo spigolo corrente al parametro trovato sull'altra curva di bordo
vSyncLines.emplace_back( mySharpEdge.ptEdge, P_INVALID) ;
pCompoSubEdge->GetPointD1D2( dUCurrSubEdge, ICurve::FROM_MINUS, vSyncLines.back().second) ;
// aggiorno i parametri
dUPrevSubEdge = dUCurrSubEdge ;
}
return true ;
}
// ---------------------------------------------------------------------------
// Debug [Gestione Edge in Quadrangolazioni]
static bool
ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComposite* pSubEdge2, BIPNTVECTOR& vSyncLines)
{
// Verifica validità delle curve
if ( pSubEdge1 == nullptr || ! pSubEdge1->IsValid() || pSubEdge2 == nullptr || ! pSubEdge2->IsValid())
return false ;
// Recupero il numero delle curve dei Sottotratti correnti dei bordi
int nCrv1 = pSubEdge1->GetCurveCount() ;
int nCrv2 = pSubEdge2->GetCurveCount() ;
if ( nCrv1 < 2 && nCrv2 < 2)
return true ;
const double COS_EDGE_LIMIT = cos( 35. * DEGTORAD) ;
SHARPEDGEVECTOR vSharpEdges1 ; vSharpEdges1.reserve( max( 0, nCrv1 - 1)) ;
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
if ( nCrv1 > 1) {
Point3d ptCurr1 ;
// Scorro le sottocurve
for ( int nCrv = 0 ; nCrv < nCrv1 - 1 ; ++ nCrv) {
// Recupero il parametro corrente sulla curva ( estremo finale)
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) ;
// Verifico se ho uno spigolo
vtTanPrev.Normalize() ;
vtTanAft.Normalize() ;
if ( vtTanPrev * vtTanAft < COS_EDGE_LIMIT)
vSharpEdges1.emplace_back( dU, ptCurr1, vtTanPrev, vtTanAft) ;
}
}
// --- Cerco gli spigoli sul Sottotratto del secondo bordo
// Se la Curva B ha solo una sottocurva, non faccio nulla
if ( nCrv2 > 1) {
Point3d ptCurr2 ;
// Scorro le sottocurve
for ( int nCrv = 0 ; nCrv < nCrv2 - 1 ; ++ nCrv) {
// Recupero il parametro corrente sulla curva ( estremo finale)
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) ;
// Verifico se ho uno spigolo
vtTanPrev.Normalize() ;
vtTanAft.Normalize() ;
if ( vtTanPrev * vtTanAft < COS_EDGE_LIMIT)
vSharpEdges2.emplace_back( dU, ptCurr2, vtTanPrev, vtTanAft) ;
}
}
// Se non ho alcuno spigolo, allora non faccio nulla
if ( vSharpEdges1.empty() && vSharpEdges2.empty())
return true ;
// Recupero le Curve di Sincronizzazione dell'Edge 1 sull'Edge 2
BIPNTVECTOR vSyncLines1 ;
CalcSyncPointFromEdge( vSharpEdges1, pSubEdge2, vSharpEdges2, vSyncLines1) ;
// Recupero le Curve di Sincronizzazione dell'Edge 2 sull'Egde 1
BIPNTVECTOR vSyncLines2 ;
CalcSyncPointFromEdge( vSharpEdges2, pSubEdge1, vSharpEdges1, vSyncLines2) ;
// Rimuovo eventuali linee sovrapposte ( le rimuovo da vSyncLines2)
const double TOL = 250. * EPS_SMALL ;
erase_if( vSyncLines2, [&]( const BIPOINT& SyncLine2) {
return any_of( vSyncLines1.begin(), vSyncLines1.end(), [&]( const BIPOINT& SyncLine1) {
return ( AreSamePointEpsilon( SyncLine1.first, SyncLine2.second, TOL) &&
AreSamePointEpsilon( SyncLine1.second, SyncLine2.first, TOL)) ;
}) ;
}) ;
// Ordino tutte le curve in base al parametro dU della curva principale
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),
vSyncLinesPar.empty() ? 0. : vSyncLinesPar.back().second)) ;
pSubEdge1->GetParamAtPoint( SyncLine1.first, vSyncLinesPar.back().second, TOL) ;
}
for ( BIPOINT& SyncLine2 : vSyncLines2) {
vSyncLinesPar.emplace_back( make_pair( make_pair( SyncLine2.second, SyncLine2.first),
vSyncLinesPar.empty() ? 0. : vSyncLinesPar.back().second)) ;
pSubEdge1->GetParamAtPoint( SyncLine2.second, vSyncLinesPar.back().second, TOL) ;
}
sort( vSyncLinesPar.begin(), vSyncLinesPar.end(), []( const auto& SyncLineParA, const auto& SyncLineParB) {
return SyncLineParA.second < SyncLineParB.second ;
}) ;
// Restituisco il risultato
for ( auto Iter = vSyncLinesPar.begin() ; Iter != vSyncLinesPar.end() ; ++ Iter)
vSyncLines.emplace_back( Iter->first) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfBezier::CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, double dSampleLen)
{
// converto in bezier le curve iniziali
PtrOwner<ICurveBezier> pCrvEdge1( GetCurveBezier( CurveToBezierCurve( pCurve0, 3, false))) ;
PtrOwner<ICurveBezier> pCrvEdge2( GetCurveBezier( CurveToBezierCurve( pCurve1, 3, false))) ;
if ( IsNull( pCrvEdge1) || IsNull( pCrvEdge2))
return false ;
// Recupero parametri iniziali
double dLen1 ; pCrvEdge1->GetLength( dLen1) ;
double dLen2 ; pCrvEdge2->GetLength( dLen2) ;
double dUS1, dUE1 ; pCrvEdge1->GetDomain( dUS1, dUE1) ;
double dUS2, dUE2 ; pCrvEdge2->GetDomain( dUS2, dUE2) ;
double dLenPrev1 = 0., dLenCurr1 = 0. ;
double dLenPrev2 = 0., dLenCurr2 = 0. ;
double dUPrev1 = 0., dUCurr1 = 0. ;
double dUPrev2 = 0., dUCurr2 = 0. ;
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) {
// Recupero dU, Point3d e dLen corrente sul primo bordo, per un incremento del passo di campionamento
dLenCurr1 = Clamp( dLenPrev1 + dSampleLen, 0., dLen1) ;
pCrvEdge1->GetParamAtLength( dLenCurr1, dUCurr1) ;
pCrvEdge1->GetPointD1D2( dUCurr1, ICurve::FROM_MINUS, ptCurr1, &vtCurr1) ;
vtCurr1.Normalize() ;
#if DEBUG_SYNCLINES
PtrOwner<IGeoPoint3d> ptGeo1( CreateGeoPoint3d()) ; ptGeo1->Set( ptCurr1) ;
PtrOwner<IGeoVector3d> vtGeo1( CreateGeoVector3d()) ; vtGeo1->Set( 5. * vtCurr1, ptCurr1) ;
pGeomDB->AddGeoObj( GDB_ID_NULL, nLay1, Release( ptGeo1)) ;
pGeomDB->AddGeoObj( GDB_ID_NULL, nLay1, Release( vtGeo1)) ;
#endif
// --- Piano di taglio per punto a minima distanza
IntersCurvePlane ICP( *pCrvEdge2, ptCurr1, vtCurr1) ;
int nIndParCloser = - 1, nIndPointCloser = -1 ;
double dSqMinDist = INFINITO ;
for ( int nInfo = 0 ; nInfo < ICP.GetIntersCount() ; ++ nInfo) {
IntCrvPlnInfo aInfo ;
if ( ICP.GetIntCrvPlnInfo( nInfo, aInfo) && aInfo.Ici[0].dU > dUPrev2) {
if ( nIndParCloser == -1)
nIndParCloser = nInfo ;
double dSqDist = SqDist( ptCurr1, 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) ;
dUCurr2 = aInfo.Ici[0].dU ;
}
// Se gli indici sono discordi, devo scegliere quale dei due punti tenere
else {
@@ -6070,126 +6169,110 @@ SurfBezier::CreateSmoothByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve
IntCrvPlnInfo aInfoPt, aInfoPar ;
ICP.GetIntCrvPlnInfo( nIndPointCloser, aInfoPt) ;
ICP.GetIntCrvPlnInfo( nIndParCloser, aInfoPar) ;
dUCurr1 = ( SqDist( ptCurr0, aInfoPt.Ici[0].ptI) < SqDist( ptCurr0, aInfoPar.Ici[0].ptI) ?
dUCurr2 = ( SqDist( ptCurr1, aInfoPt.Ici[0].ptI) < SqDist( ptCurr1, aInfoPar.Ici[0].ptI) ?
aInfoPt.Ici[0].dU : aInfoPar.Ici[0].dU) ;
#if DEBUG_SYNCLINES && 0
VT.clear() ; VC.clear() ;
VT.emplace_back( pCrvEdge1->Clone()) ; VC.emplace_back( Color( 0, 128, 255)) ;
VT.emplace_back( pCrvEdge2->Clone()) ; VC.emplace_back( Color( 0, 128, 255)) ;
PtrOwner<IGeoPoint3d> ptCurr1Geo( CreateGeoPoint3d()) ; ptCurr1Geo->Set( ptCurr1) ;
VT.emplace_back( Release( ptCurr1Geo)) ; VC.emplace_back( BLUE) ;
PtrOwner<IGeoPoint3d> ptPar( CreateGeoPoint3d()) ; ptPar->Set( aInfoPar.Ici[0].ptI) ;
PtrOwner<IGeoPoint3d> ptPt( CreateGeoPoint3d()) ; ptPt->Set( aInfoPt.Ici[0].ptI) ;
VT.emplace_back( Release( ptPar)) ; VC.emplace_back( LIME) ;
VT.emplace_back( Release( ptPt)) ; VC.emplace_back( FUCHSIA) ;
SaveGeoObj( VT, VC, "C:\\Temp\\TestTrimmingPlane.nge") ;
#endif
}
// Verifico di non essermi allontanato troppo
double dLen ; CrvU1.GetLengthAtParam( dUCurr1, dLen) ;
bOkPlane = ( dLen < dLenPrev1 + 1. * dSampleLen) ;
double dLen ; pCrvEdge2->GetLengthAtParam( dUCurr2, dLen) ;
bOkPlane = ( dLen < dLenPrev2 + 2. * dSampleLen) ;
}
if ( ! bOkPlane) {
// --- Altrimenti, cerco il punto a minima distanza
DistPointCurve DPC( ptCurr0, CrvU1) ;
DistPointCurve DPC( ptCurr1, *pCrvEdge2) ;
int nFlag ;
bool bOkMinDist = ( DPC.GetParamAtMinDistPoint( dUPrev1, dUCurr1, nFlag) && dUCurr1 > dUPrev1) ;
bool bOkMinDist = ( DPC.GetParamAtMinDistPoint( dUPrev2, dUCurr2, nFlag) && dUCurr2 > dUPrev2) ;
// Verifico di non essermi allontanato troppo
if ( bOkMinDist) {
double dLen ; CrvU1.GetLengthAtParam( dUCurr1, dLen) ;
bOkMinDist = ( dLen < dLenPrev1 + 1. * dSampleLen) ;
double dLen ; pCrvEdge2->GetLengthAtParam( dUCurr2, dLen) ;
bOkMinDist = ( dLen < dLenPrev2 + 2. * dSampleLen) ;
}
if ( ! bOkMinDist) {
// --- Aumento la distanza corrente del passo di campionamento
double dLen = Clamp( dLenPrev1 + dSampleLen, 0., dLen1) ;
CrvU1.GetParamAtLength( dLen, dUCurr1) ;
double dLen = Clamp( dLenPrev2 + dSampleLen, 0., dLen2) ;
pCrvEdge2->GetParamAtLength( dLen, dUCurr2) ;
}
}
// 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() ;
pCrvEdge2->GetLengthAtParam( dUCurr2, dLenCurr2) ;
pCrvEdge2->GetPointD1D2( dUCurr2, ICurve::FROM_MINUS, ptCurr2, &vtCurr2) ;
vtCurr2.Normalize() ;
// Verifico se le direzioni tangenti sono tra di loro circa parallele
const double COS_ANG_TOL = cos( 05. * 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) ;
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)
pCrvEdge2->GetLengthAtPoint( ptCurr2, dLenCurr2) ;
double dLimInfLen2 = Clamp( dLenCurr2 - dSampleLen, dLenPrev2, dLen2) ;
double dLimSupLen2 = Clamp( dLenCurr2 + dSampleLen, dLenPrev2, dLen2) ;
// [Controllo migliorabile, magari mendiante metodo di bisezione (?)]
const int NUM_STEP = 10 ;
double dMinCos = - 0. - EPS_ZERO ;
const int NUM_STEP = 20 ;
double dMinCos = - 1. - EPS_ZERO ;
const double DEGTOL = 5. ;
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 ;
double dAngTol = ( i < NUM_STEP / 1 ? ( 1. * DEGTOL) / NUM_STEP * i :
( - 1. * DEGTOL) / NUM_STEP * ( i - NUM_STEP)) ;
double dCosTol = 0. - cos( dAngTol * DEGTORAD) ;
if ( dStepCos1 + dCosTol > dMinCos) {
ptCurr1 = ptStep1 ;
vtCurr1 = vtStep1 ;
dUCurr1 = dUStep1 ;
dMinCos = dStepCos1 + dCosTol ;
double dLen = dLimInfLen2 + i * ( dLimSupLen2 - dLimInfLen2) / NUM_STEP ;
double dUStep2 ; pCrvEdge2->GetParamAtLength( dLen, dUStep2) ;
Point3d ptStep2 ; Vector3d vtStep2 = V_NULL ;
pCrvEdge2->GetPointD1D2( dUStep2, ICurve::FROM_MINUS, ptStep2, &vtStep2) ; vtStep2.Normalize() ;
double dStepCos2 = vtCurr1 * vtStep2 ;
double dAngTol = ( i < NUM_STEP / 2 ? ( 2. * DEGTOL) / NUM_STEP * i :
( - 2. * DEGTOL) / NUM_STEP * ( i - NUM_STEP)) ;
double dCosTol = 1. - cos( dAngTol * DEGTORAD) ;
if ( dStepCos2 + dCosTol > dMinCos) {
ptCurr2 = ptStep2 ;
vtCurr2 = vtStep2 ;
dUCurr2 = dUStep2 ;
dMinCos = dStepCos2 + dCosTol ;
}
}
}
#if DEBUG_SYNCLINES
PtrOwner<IGeoPoint3d> ptGeo2( CreateGeoPoint3d()) ; ptGeo2->Set( ptCurr2) ;
PtrOwner<IGeoVector3d> vtGeo2( CreateGeoVector3d()) ; vtGeo2->Set( 5. * vtCurr2, ptCurr2) ;
pGeomDB->AddGeoObj( GDB_ID_NULL, nLay2, Release( ptGeo2)) ;
pGeomDB->AddGeoObj( GDB_ID_NULL, nLay2, Release( vtGeo2)) ;
#endif
// 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 ;
}
}
}
}
// 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
ICurveLine* CL = CreateCurveLine() ; CL->Set( ptCurr0, ptCurr1) ;
vGeo.push_back( CL) ;
#endif
// --- 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
PtrOwner<ICurveComposite> pCrvQuad1( ConvertCurveToComposite( pCrvEdge1->CopyParamRange( dUPrev1, dUCurr1))) ;
PtrOwner<ICurveComposite> pCrvQuad2( ConvertCurveToComposite( pCrvEdge2->CopyParamRange( dUPrev2, dUCurr2))) ;
ManageEdgesInQuadrangulation( pCrvQuad1, pCrvQuad2, vEdgeSyncLines) ;
//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) ;
//}
// 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 ;
ptPrev2 = ptCurr2 ; dUPrev2 = dUCurr2 ; dLenPrev2 = dLenCurr2 ;
}
#if SAVEPACEDISO
SaveGeoObj( vGeo, "D:\\Temp\\bezier\\ruled\\smoothness\\iso.nge") ;
#endif
return CreateByIsoParamSet( &CrvU0, &CrvU1, vPairs) ;
return CreateByIsoParamSet( pCrvEdge1, pCrvEdge2, vEdgeSyncLines) ;
}
//----------------------------------------------------------------------------
+1 -1
View File
@@ -154,7 +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 ;
bool CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, double dSampleLen) override ;
public : // IGeoObjRW
int GetNgeId( void) const override ;
+1 -1
View File
@@ -4219,7 +4219,7 @@ GetTrimmingRuledBezier( const CISURFPVECTOR& vSurf, const ICurve* pCrvEdge1,
// Se non ho punti di controllo forzati
if ( vSyncPoints.empty()) {
pSurfBz.Set( GetSurfBezierRuled( pCompoEdge1, pCompoEdge2, ISurfBezier::RLT_B_MINDIST_PLUS, dMyLinTol)) ;
pSurfBz.Set( GetSurfBezierRuledSmooth( pCompoEdge1, pCompoEdge2, 10)) ;
if ( IsNull( pSurfBz) || ! pSurfBz->IsValid()) {
LOG_ERROR( GetEGkLogger(), "Error in Trimming : Ruled Bezier invalid") ;
return nullptr ;