1f7fae5367
- agg. conversione CNurbs in CBezier.
317 lines
10 KiB
C++
317 lines
10 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2013-2013
|
|
//----------------------------------------------------------------------------
|
|
// File : CurveAux.cpp Data : 22.11.13 Versione : 1.3a1
|
|
// Contenuto : Implementazione di alcune funzioni di utilità per le curve.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 22.11.13 DS Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
#include "stdafx.h"
|
|
#include "CurveAux.h"
|
|
#include "GeoConst.h"
|
|
#include "/EgtDev/Include/EgkCurveComposite.h"
|
|
#include "/EgtDev/Include/EgkCurveBezier.h"
|
|
#include "/EgtDev/Include/EgkCurveArc.h"
|
|
#include "/EgtDev/Include/EgtPointerOwner.h"
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
IsClosed( const ICurve& crvC)
|
|
{
|
|
Point3d ptStart ;
|
|
Point3d ptEnd ;
|
|
|
|
|
|
return ( crvC.GetStartPoint( ptStart) && crvC.GetEndPoint( ptEnd) && AreSamePointNear( ptStart, ptEnd)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
GetTang( const ICurve& crvC, double dU, ICurve::Side nS, Vector3d& vtTang)
|
|
{
|
|
Point3d ptPos ;
|
|
return GetPointTang( crvC, dU, nS, ptPos, vtTang) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
GetPointTang( const ICurve& crvC, double dU, ICurve::Side nS, Point3d& ptPos, Vector3d& vtTang)
|
|
{
|
|
if ( ! crvC.GetPointD1D2( dU, nS, ptPos, &vtTang))
|
|
return false ;
|
|
if ( vtTang.Normalize())
|
|
return true ;
|
|
// nel caso la derivata prima sia nulla, utilizziamo la seconda
|
|
Vector3d vtDummy ;
|
|
if ( ! crvC.GetPointD1D2( dU, nS, ptPos, &vtDummy, &vtTang))
|
|
return false ;
|
|
return vtTang.Normalize() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
GetPointDiffGeom( const ICurve& crvC, double dU, ICurve::Side nS, CrvPointDiffGeom& oDiffG)
|
|
{
|
|
double dSqLenD1 ;
|
|
Point3d ptPos ;
|
|
Vector3d vtDer1 ;
|
|
Vector3d vtDer2 ;
|
|
|
|
|
|
if ( ! crvC.GetPointD1D2( dU, nS, ptPos, &vtDer1, &vtDer2))
|
|
return false ;
|
|
// assegno parametro e posizione
|
|
oDiffG.dU = dU ;
|
|
oDiffG.ptP = ptPos ;
|
|
// se esiste la derivata prima non nulla
|
|
dSqLenD1 = vtDer1.SqLen() ;
|
|
if ( vtDer1.Normalize()) {
|
|
oDiffG.vtT = vtDer1 ;
|
|
// del vettore deriv2^ tengo la sola componente perpendicolare al vettore tangente
|
|
oDiffG.vtN = vtDer2 - ( vtDer2 * vtDer1) * vtDer1 ;
|
|
if ( oDiffG.vtN.Normalize()) {
|
|
oDiffG.dCurv = ( vtDer1 ^ vtDer2).Len() / dSqLenD1 ;
|
|
oDiffG.nStatus = CrvPointDiffGeom::NCRV ;
|
|
}
|
|
else {
|
|
oDiffG.dCurv = 0 ;
|
|
oDiffG.nStatus = CrvPointDiffGeom::TANG ;
|
|
}
|
|
}
|
|
// se esiste almeno derivata seconda non nulla, definisce la tangente
|
|
else if ( vtDer2.Normalize()) {
|
|
oDiffG.vtT = vtDer2 ;
|
|
oDiffG.vtN.Set( 0, 0, 0) ;
|
|
oDiffG.dCurv = 0 ;
|
|
oDiffG.nStatus = CrvPointDiffGeom::TANG ;
|
|
}
|
|
// altrimenti non sono definite la tangente e la normale
|
|
else {
|
|
oDiffG.vtT.Set( 0, 0, 0) ;
|
|
oDiffG.vtN.Set( 0, 0, 0) ;
|
|
oDiffG.dCurv = 0 ;
|
|
oDiffG.nStatus = CrvPointDiffGeom::POS ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
ArcToBezierCurve( const ICurve* pCrv, ICurve*& pCrvNew)
|
|
{
|
|
// verifico sia un arco
|
|
const ICurveArc* pArc = GetCurveArc( pCrv) ;
|
|
if ( pArc == nullptr)
|
|
return false ;
|
|
|
|
// se angolo al centro sotto il limite, basta una curva
|
|
if ( fabs( pArc->GetAngCenter()) <= BEZARC_ANG_CEN_MAX) {
|
|
// creo la curva di Bezier
|
|
PtrOwner<ICurveBezier> pCrvBez( CreateCurveBezier()) ;
|
|
if ( ! IsValid( pCrvBez))
|
|
return false ;
|
|
if ( ! pCrvBez->FromArc( *pArc))
|
|
return false ;
|
|
// restituisco la curva
|
|
pCrvNew = Release( pCrvBez) ;
|
|
}
|
|
|
|
// altrimenti curva composita di Bezier
|
|
else {
|
|
// creo la curva composita
|
|
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
|
|
if ( ! IsValid( pCrvCompo))
|
|
return false ;
|
|
if ( ! pCrvCompo->AddCurve( *pArc) ||
|
|
! pCrvCompo->ArcsToBezierCurves())
|
|
return false ;
|
|
// restituisco la curva
|
|
pCrvNew = Release( pCrvCompo) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
NurbsCurveCanonicalize( CNurbsData& cnData)
|
|
{
|
|
// se periodica
|
|
if ( cnData.bPeriodic) {
|
|
// va trasformata in non-periodica (clamped)
|
|
// vedere The NurbsBook di Les Piegl e Tiller
|
|
// mancano esempi per testare
|
|
return false ;
|
|
}
|
|
// se con nodi extra
|
|
if ( cnData.bExtraKnotes) {
|
|
int nKnotesNbr = int( cnData.vU.size()) ;
|
|
if ( nKnotesNbr < 4)
|
|
return false ;
|
|
cnData.bExtraKnotes = false ;
|
|
for ( int i = 0 ; i < nKnotesNbr - 2 ; ++ i)
|
|
cnData.vU[i] = cnData.vU[i+1] ;
|
|
cnData.vU.resize( nKnotesNbr - 2) ;
|
|
return true ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
NurbsToBezierCurve( const CNurbsData& cnData, ICurve*& pCrvNew)
|
|
{
|
|
// la curva Nurbs deve essere in forma canonica
|
|
if ( cnData.bPeriodic || cnData.bExtraKnotes)
|
|
return false ;
|
|
// numero dei nodi
|
|
int nU = int( cnData.vCP.size()) + cnData.nDeg - 1 ;
|
|
// controllo relazione nodi - punti di controllo
|
|
if ( nU != int( cnData.vU.size()))
|
|
return false ;
|
|
// numero degli intervalli
|
|
int nInt = nU - 2 * cnData.nDeg + 1 ;
|
|
|
|
// se 1 solo intervallo, la Nurbs è già una curva di Bezier
|
|
if ( nInt == 1) {
|
|
// creo la curva di Bezier
|
|
PtrOwner<ICurveBezier> pCrvBez( CreateCurveBezier()) ;
|
|
if ( ! IsValid( pCrvBez))
|
|
return false ;
|
|
// la inizializzo
|
|
if ( ! pCrvBez->Init( cnData.nDeg, cnData.bRat))
|
|
return false ;
|
|
for ( int i = 0 ; i <= cnData.nDeg ; ++ i) {
|
|
if ( ! cnData.bRat) {
|
|
if ( ! pCrvBez->SetControlPoint( i, cnData.vCP[i]))
|
|
return false ;
|
|
}
|
|
else {
|
|
if ( ! pCrvBez->SetControlPoint( i, cnData.vCP[i], cnData.vW[i]))
|
|
return false ;
|
|
}
|
|
}
|
|
// restituisco la curva
|
|
pCrvNew = Release( pCrvBez) ;
|
|
return true ;
|
|
}
|
|
|
|
// altrimenti è equivalente ad una curva composita, la creo
|
|
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
|
|
if ( ! IsValid( pCrvCompo))
|
|
return false ;
|
|
|
|
// vettore dei punti di controllo della curva di Bezier
|
|
PNTVECTOR vBC ;
|
|
vBC.resize( cnData.nDeg + 1) ;
|
|
DBLVECTOR vBW ;
|
|
vBW.resize( cnData.nDeg + 1) ;
|
|
if ( ! cnData.bRat) {
|
|
for ( int i = 0 ; i <= cnData.nDeg ; ++ i)
|
|
vBC[i] = cnData.vCP[i] ;
|
|
}
|
|
else {
|
|
for ( int i = 0 ; i <= cnData.nDeg ; ++ i) {
|
|
vBC[i] = cnData.vCP[i] * cnData.vW[i] ;
|
|
vBW[i] = cnData.vW[i] ;
|
|
}
|
|
}
|
|
// primi coefficienti della successiva
|
|
PNTVECTOR vNextBC ;
|
|
vNextBC.resize( cnData.nDeg - 1) ;
|
|
DBLVECTOR vNextBW ;
|
|
vNextBW.resize( cnData.nDeg - 1) ;
|
|
// ...
|
|
DBLVECTOR vAlfa ;
|
|
vAlfa.resize( cnData.nDeg - 1) ;
|
|
int a = cnData.nDeg - 1 ;
|
|
int b = cnData.nDeg ;
|
|
// ciclo
|
|
while ( b < nU - 1) {
|
|
int i = b ;
|
|
while ( b < nU - 1 && fabs( cnData.vU[b+1] - cnData.vU[b]) < EPS_ZERO)
|
|
++ b ;
|
|
int mult = std::min( b - i + 1, cnData.nDeg) ;
|
|
if ( mult < cnData.nDeg) {
|
|
// numeratore di alfa
|
|
double numer = cnData.vU[b] - cnData.vU[a] ;
|
|
// calcola e salva gli alfa
|
|
for ( int j = cnData.nDeg ; j > mult ; -- j)
|
|
vAlfa[j-mult-1] = numer / ( cnData.vU[a+j] - cnData.vU[a]) ;
|
|
// inserisco il nodo r volte
|
|
int r = cnData.nDeg - mult ;
|
|
for ( int j = 1 ; j <= r ; ++ j) {
|
|
int save = r - j ;
|
|
int s = mult + j ;
|
|
for ( int k = cnData.nDeg ; k >= s ; -- k)
|
|
vBC[k] = vAlfa[k-s] * vBC[k] + ( 1 - vAlfa[k-s]) * vBC[k-1] ;
|
|
if ( cnData.bRat) {
|
|
for ( int k = cnData.nDeg ; k >= s ; -- k)
|
|
vBW[k] = vAlfa[k-s] * vBW[k] + ( 1 - vAlfa[k-s]) * vBW[k-1] ;
|
|
}
|
|
if ( b < nU - 1) {
|
|
vNextBC[save] = vBC[cnData.nDeg] ;
|
|
if ( cnData.bRat)
|
|
vNextBW[save] = vBW[cnData.nDeg] ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// costruisco la curva di Bezier e la inserisco nella curva composita
|
|
PtrOwner<ICurveBezier> pCrvBez( CreateCurveBezier()) ;
|
|
if ( ! IsValid( pCrvBez))
|
|
return false ;
|
|
// la inizializzo
|
|
if ( ! pCrvBez->Init( cnData.nDeg, cnData.bRat))
|
|
return false ;
|
|
if ( ! cnData.bRat) {
|
|
for ( int i = 0 ; i <= cnData.nDeg ; ++ i) {
|
|
if ( ! pCrvBez->SetControlPoint( i, vBC[i]))
|
|
return false ;
|
|
}
|
|
}
|
|
else {
|
|
for ( int i = 0 ; i <= cnData.nDeg ; ++ i) {
|
|
if ( ! pCrvBez->SetControlPoint( i, vBC[i] / vBW[i], vBW[i]))
|
|
return false ;
|
|
}
|
|
}
|
|
// la aggiungo alla curva composita
|
|
if ( ! pCrvCompo->AddCurve( Release( pCrvBez)))
|
|
return false ;
|
|
|
|
// inizializzazioni per la prossima curva di Bezier
|
|
if ( b < nU - 1) {
|
|
if ( ! cnData.bRat) {
|
|
for ( int i = 0 ; i < cnData.nDeg - 1 ; ++ i)
|
|
vBC[i] = vNextBC[i] ;
|
|
for ( int i = cnData.nDeg - mult ; i <= cnData.nDeg ; ++ i)
|
|
vBC[i] = cnData.vCP[b-cnData.nDeg+i+1] ;
|
|
}
|
|
else {
|
|
for ( int i = 0 ; i < cnData.nDeg - 1 ; ++ i) {
|
|
vBC[i] = vNextBC[i] ;
|
|
vBW[i] = vNextBW[i] ;
|
|
}
|
|
for ( int i = cnData.nDeg - mult ; i <= cnData.nDeg ; ++ i) {
|
|
vBC[i] = cnData.vCP[b-cnData.nDeg+i+1] * cnData.vW[b-cnData.nDeg+i+1] ;
|
|
vBW[i] = cnData.vW[b-cnData.nDeg+i+1] ;
|
|
}
|
|
}
|
|
a = b ;
|
|
++ b ;
|
|
}
|
|
}
|
|
|
|
// restituisco la curva composita
|
|
pCrvNew = Release( pCrvCompo) ;
|
|
return true ;
|
|
} |