Files
EgtGeomKernel/CurveBezier.cpp
T
Dario Sassi b4b996dac0 EgtGeomKernel 1.6g7 :
- aggiunta approssimazione di punti con archi e rette (CurveByApprox)
- fatte correzioni ad intersezioni rette/archi e archi/archi quasi tangenti
- correzioni ad offset di curve composite che non liberava memoria in caso di errore.
2015-07-27 13:32:02 +00:00

2121 lines
64 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2013-2014
//----------------------------------------------------------------------------
// File : CurveBezier.cpp Data : 26.03.14 Versione : 1.5c9
// Contenuto : Implementazione della classe Curva di Bezier.
//
//
//
// Modifiche : 28.12.12 DS Creazione modulo.
// 26.03.14 DS Modif. Save/Load, ora ogni punto su una linea.
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "CurveBezier.h"
#include "CurveComposite.h"
#include "DistPointCrvBezier.h"
#include "BiArcs.h"
#include "GeoConst.h"
#include "PolygonPlane.h"
#include "DistPointLine.h"
#include "GeoObjFactory.h"
#include "NgeWriter.h"
#include "NgeReader.h"
#include "PolynomialPoint3d.h"
#include "/EgtDev/Include/EGkCurveArc.h"
#include "/EgtDev/Include/EGkStringUtils3d.h"
#include "/EgtDev/Include/EGkUiUnits.h"
#include "/EgtDev/Include/ENkPolynomial.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
#include <new>
using namespace std ;
//----------------------------------------------------------------------------
static const double MIN_EXT_WEIGHT = 0.25 ;
//----------------------------------------------------------------------------
GEOOBJ_REGISTER( CRV_BEZ, NGE_C_BEZ, CurveBezier) ;
//----------------------------------------------------------------------------
CurveBezier::CurveBezier( void)
: m_nStatus( TO_VERIFY), m_nDeg(), m_bRat( false), m_dParSing( -2),
m_nDimArr(), m_aPtCtrl( nullptr), m_aWeCtrl( nullptr), m_VtExtr(), m_dThick(), m_nTempProp()
{
}
//----------------------------------------------------------------------------
CurveBezier::~CurveBezier( void)
{
if ( m_nDimArr > 0) {
delete [] m_aPtCtrl ;
delete [] m_aWeCtrl ;
}
m_nDimArr = 0 ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Init( int nDeg, bool bIsRational)
{
// verifico validità grado
if ( nDeg < 1 || nDeg > MAXDEG)
return false ;
// se spazio dinamico sufficiente
if ( ( nDeg + 1) <= m_nDimArr)
;
// se altrimenti spazio statico sufficiente
else if ( ( nDeg + 1) <= ST_PTC) {
m_aPtCtrl = m_aStPtCtrl ;
if ( bIsRational)
m_aWeCtrl = m_aStWeCtrl ;
}
// altrimenti
else {
// se necessaria, pulizia
if ( m_nDimArr > 0) {
delete [] m_aPtCtrl ;
delete [] m_aWeCtrl ;
}
// alloco punti
m_aPtCtrl = new Point3d [ nDeg + 1] ;
if ( m_aPtCtrl == nullptr)
return false ;
// se razionale, alloco pesi
if ( bIsRational) {
m_aWeCtrl = new double [ nDeg + 1] ;
if ( m_aWeCtrl == nullptr) {
delete [] m_aPtCtrl ;
return false ;
}
}
// salvo dimensione array allocati
m_nDimArr = nDeg + 1 ;
}
// salvo il grado
m_nDeg = nDeg ;
// salvo flag di razionale
m_bRat = bIsRational ;
// dichiaro non si è ancora fatta analisi presenza singolarità
m_dParSing = - 2 ;
// pulisco, assegnando 0 ai punti e 1 ai pesi
memset( m_aPtCtrl, 0, sizeof( Point3d) * ( m_nDeg + 1)) ;
if ( m_bRat) {
for ( int i = 0 ; i <= m_nDeg ; ++ i)
m_aWeCtrl[i] = 1 ;
}
m_nStatus = TO_VERIFY ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return Validate() ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::SetControlPoint( int nInd, const Point3d& ptCtrl)
{
// verifico validità indice
if ( m_nStatus != OK || m_bRat || nInd < 0 || nInd > m_nDeg)
return false ;
// assegno il valore
m_aPtCtrl[nInd] = ptCtrl ;
// se razionale, metto il peso a 1
if ( m_bRat)
m_aWeCtrl[nInd] = 1 ;
// annullo analisi presenza singolarità
m_dParSing = - 2 ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::SetControlPoint( int nInd, const Point3d& ptCtrl, double dW)
{
// verifico validità, razionalità e indice
if ( m_nStatus != OK || ! m_bRat || nInd < 0 || nInd > m_nDeg)
return false ;
// verifico che il peso non sia nullo o negativo
if ( dW < EPS_SMALL)
return false ;
// assegno il valore e il peso
m_aPtCtrl[nInd] = ptCtrl ;
m_aWeCtrl[nInd] = dW ;
// annullo analisi presenza singolarità
m_dParSing = - 2 ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::FromArc( const ICurveArc& crArc)
{
const double MAX_ANG_CEN_DEG = 120 ;
double dAngCen ;
double dCosAhalf ;
double dW ;
Point3d ptStart ;
Point3d ptEnd ;
Point3d ptEndNoDN ;
Point3d ptMed ;
Point3d ptNew ;
Point3d ptNew1 ;
Point3d ptNew2 ;
Vector3d vtDeltaN ;
Vector3d vtDir ;
if ( ! crArc.IsValid())
return false ;
dAngCen = crArc.GetAngCenter() ;
if ( fabs( dAngCen) > MAX_ANG_CEN_DEG)
return false ;
dCosAhalf = cos( 0.5 * dAngCen * DEGTORAD) ;
// se arco piatto, basta quadrica razionale
// algoritmo di Sederberg (BYU) CAGD cap. 2 pag. 33
if ( fabs( crArc.GetDeltaN()) < EPS_ZERO) {
// peso del punto di controllo intermedio
dW = dCosAhalf ;
// calcolo dei punti di controllo
crArc.GetStartPoint( ptStart) ;
crArc.GetEndPoint( ptEnd) ;
ptMed = Media( ptStart, ptEnd, 0.5) ;
vtDir = ptMed - crArc.GetCenter() ;
ptNew = crArc.GetCenter() + vtDir / ( dCosAhalf * dCosAhalf) ;
// inserimento nella curva dei punti di controllo con i pesi
Init( 2, true) ;
SetControlPoint( 0, ptStart, 1) ;
SetControlPoint( 1, ptNew, dW) ;
SetControlPoint( 2, ptEnd, 1) ;
}
// altrimenti per elica serve cubica razionale
// algoritmo di Juhasz HelixApproxByCubicBezier CAD 1995
else {
// peso dei punti di controllo intermedi
dW = ( 1 + 2 * dCosAhalf) / 3 ;
// calcolo dei punti di controllo
crArc.GetStartPoint( ptStart) ;
crArc.GetEndPoint( ptEnd) ;
vtDeltaN = crArc.GetDeltaN() * crArc.GetNormVersor() ;
ptEndNoDN = ptEnd - vtDeltaN ;
ptMed = Media( ptStart, ptEndNoDN, 0.5) ;
vtDir = ptMed - crArc.GetCenter() ;
ptNew = crArc.GetCenter() + vtDir / ( dCosAhalf * dCosAhalf) ;
ptNew1 = ( ptStart + 2 * dCosAhalf * ptNew) / ( 1 + 2 * dCosAhalf) +
0.5 * ( 1 - dCosAhalf / ( 2 + dCosAhalf)) * vtDeltaN ;
ptNew2 = ( ptEndNoDN + 2 * dCosAhalf * ptNew) / ( 1 + 2 * dCosAhalf) +
0.5 * ( 1 + ( dCosAhalf / ( 2 + dCosAhalf))) * vtDeltaN ;
// inserimento nella curva dei punti di controllo con i pesi
Init( 3, true) ;
SetControlPoint( 0, ptStart, 1) ;
SetControlPoint( 1, ptNew1, dW) ;
SetControlPoint( 2, ptNew2, dW) ;
SetControlPoint( 3, ptEnd, 1) ;
}
// copio estrusione e spessore
crArc.GetExtrusion( m_VtExtr) ;
crArc.GetThickness( m_dThick) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::IsAPoint( void) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// ciclo sui punti
for ( int i = 1 ; i <= m_nDeg ; ++ i) {
if ( ! AreSamePointApprox( m_aPtCtrl[0], m_aPtCtrl[i]))
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
const Point3d&
CurveBezier::GetControlPoint( int nInd, bool* pbOk) const
{
// verifico validità e indice
if ( m_nStatus != OK || nInd < 0 || nInd > m_nDeg) {
if ( pbOk != NULL)
*pbOk = false ;
return ORIG ;
}
// ritorno i dati
if ( pbOk != NULL)
*pbOk = true ;
return m_aPtCtrl[nInd] ;
}
//----------------------------------------------------------------------------
double
CurveBezier::GetControlWeight( int nInd, bool* pbOk) const
{
// verifico validità, razionalità e indice
if ( m_nStatus != OK || ! m_bRat || nInd < 0 || nInd > m_nDeg) {
if ( pbOk != NULL)
*pbOk = false ;
return 0 ;
}
// ritorno i dati
if ( pbOk != NULL)
*pbOk = true ;
return m_aWeCtrl[nInd] ;
}
//----------------------------------------------------------------------------
CurveBezier*
CurveBezier::Clone( void) const
{
// alloco oggetto
CurveBezier* pCrv = new(nothrow) CurveBezier ;
if ( pCrv != nullptr) {
if ( ! pCrv->CopyFrom( *this)) {
delete pCrv ;
return nullptr ;
}
}
return pCrv ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::CopyFrom( const IGeoObj* pGObjSrc)
{
const CurveBezier* pCB = dynamic_cast<const CurveBezier*>( pGObjSrc) ;
if ( pCB == nullptr)
return false ;
return CopyFrom( *pCB) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::CopyFrom( const CurveBezier& cbSrc)
{
if ( &cbSrc == this)
return true ;
if ( ! Init( cbSrc.m_nDeg, cbSrc.m_bRat))
return false ;
m_VtExtr = cbSrc.m_VtExtr ;
m_dThick = cbSrc.m_dThick ;
m_nTempProp = cbSrc.m_nTempProp ;
for ( int i = 0 ; i <= m_nDeg ; ++ i) {
m_aPtCtrl[i] = cbSrc.m_aPtCtrl[i] ;
if ( cbSrc.m_bRat)
m_aWeCtrl[i] = cbSrc.m_aWeCtrl[i] ;
}
return true ;
}
//----------------------------------------------------------------------------
GeoObjType
CurveBezier::GetType( void) const
{
return static_cast<GeoObjType>( GEOOBJ_GETTYPE( CurveBezier)) ;
}
//----------------------------------------------------------------------------
const string&
CurveBezier::GetTitle( void) const
{
static const string sTitle = "CBezier" ;
return sTitle ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Dump( string& sOut, bool bMM, const char* szNewLine) const
{
// dati generali di una curva
if ( ! CurveDump( *this, sOut, bMM, szNewLine))
return false ;
// parametri : flag razionale
sOut += ( m_bRat ? "Rat " : "Int ") ;
// grado
sOut += "Deg=" + ToString( m_nDeg) + szNewLine ;
// ciclo sui punti di controllo ( con pesi se razionale)
for ( int i = 0 ; i <= m_nDeg ; ++ i) {
sOut += "PC(" + ToString( GetInUiUnits( m_aPtCtrl[i], bMM), 3) ;
if ( m_bRat)
sOut += "," + ToString( m_aWeCtrl[i], 3) ;
sOut += string( ")") + szNewLine ;
}
return true ;
}
//----------------------------------------------------------------------------
int
CurveBezier::GetNgeId( void) const
{
return GEOOBJ_GETNGEID( CurveBezier) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Save( NgeWriter& ngeOut) const
{
// flag razionale
if ( ! ngeOut.WriteBool( m_bRat, ";"))
return false ;
// grado
if ( ! ngeOut.WriteInt( m_nDeg, ";", true))
return false ;
// ciclo sui punti di controllo ( con pesi se razionale)
for ( int i = 0 ; i <= m_nDeg ; ++ i) {
if ( ! m_bRat) {
if ( ! ngeOut.WritePoint( m_aPtCtrl[i], ";", true))
return false ;
}
else {
if ( ! ngeOut.WritePointW( m_aPtCtrl[i], m_aWeCtrl[i], ";", true))
return false ;
}
}
// da versione 1008 : linea con VtEstrusione e Spessore
if ( ! ngeOut.WriteVector( m_VtExtr, ";"))
return false ;
if ( ! ngeOut.WriteDouble( m_dThick, ";", true))
return false ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Load( NgeReader& ngeIn)
{
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// leggo la prossima linea ( 2 parametri)
// recupero il flag razionale
bool bIsRat ;
if ( ! ngeIn.ReadBool( bIsRat, ";"))
return false ;
// recupero il grado
int nDeg ;
if ( ! ngeIn.ReadInt( nDeg, ";", true))
return false ;
// inizializzo la curva di Bezier
if ( ! Init( nDeg, bIsRat))
return false ;
// se integrale
if ( ! bIsRat) {
// recupero e setto punti di controllo
string sLine ;
Point3d ptP ;
for ( int i = 0 ; i <= nDeg ; ++ i) {
// leggo la prossima linea ( un punto)
if ( ! ngeIn.ReadPoint( ptP, ";", true))
return false ;
// lo assegno
if ( ! SetControlPoint( i, ptP))
return false ;
}
}
// altrimenti razionale
else {
// recupero e setto punti di controllo
string sLine ;
Point3d ptP ;
double dW ;
for ( int i = 0 ; i <= nDeg ; ++ i) {
// leggo la prossima linea ( un punto con peso)
if ( ! ngeIn.ReadPointW( ptP, dW, ";", true))
return false ;
// lo assegno
if ( ! SetControlPoint( i, ptP, dW))
return false ;
}
}
// da versione 1008 : linea con VtEstrusione e Spessore
if ( ngeIn.GetFileVersion() >= NGE_VER_1008) {
if ( ! ngeIn.ReadVector( m_VtExtr, ";"))
return false ;
if ( ! ngeIn.ReadDouble( m_dThick, ";", true))
return false ;
}
// eseguo validazione
return Validate() ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Validate( void)
{
if ( m_nStatus == TO_VERIFY)
m_nStatus = ( ( m_nDeg > 0 && m_aPtCtrl != nullptr) ? OK : ERR) ;
return ( m_nStatus == OK) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetLocalBBox( BBox3d& b3Loc, int nFlag) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// assegno il box in locale
b3Loc.Reset() ;
// basta approssimato
if ( ( nFlag & BBF_EXACT) == 0) {
for ( int i = 0 ; i <= m_nDeg ; ++ i)
b3Loc.Add( m_aPtCtrl[i]) ;
}
// deve essere preciso
else {
// costruisco una approssimazione lineare
PolyLine PL ;
if ( ! ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_STD, PL))
return false ;
// ciclo sui punti della approssimazione
Point3d ptTemp ;
for ( bool bFound = PL.GetFirstPoint( ptTemp) ; bFound ; bFound = PL.GetNextPoint( ptTemp)) {
b3Loc.Add( ptTemp) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetBBox( const Frame3d& frRef, BBox3d& b3Ref, int nFlag) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// assegno il box nel riferimento
b3Ref.Reset() ;
// basta approssimato
if ( ( nFlag & BBF_EXACT) == 0) {
for ( int i = 0 ; i <= m_nDeg ; ++ i) {
Point3d ptTemp = m_aPtCtrl[i] ;
ptTemp.ToGlob( frRef) ;
b3Ref.Add( ptTemp) ;
}
}
// deve essere preciso
else {
// costruisco una approssimazione lineare
PolyLine PL ;
if ( ! ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_STD, PL))
return false ;
// ciclo sui punti della approssimazione
Point3d ptTemp ;
for ( bool bFound = PL.GetFirstPoint( ptTemp) ; bFound ; bFound = PL.GetNextPoint( ptTemp)) {
ptTemp.ToGlob( frRef) ;
b3Ref.Add( ptTemp) ;
}
}
// se c'è estrusione, devo tenerne conto
if ( ! m_VtExtr.IsSmall() && fabs( m_dThick) > EPS_SMALL) {
Vector3d vtFrExtr = m_VtExtr ;
vtFrExtr.ToGlob( frRef) ;
Point3d ptMinExtr = b3Ref.GetMin() + vtFrExtr * m_dThick ;
Point3d ptMaxExtr = b3Ref.GetMax() + vtFrExtr * m_dThick ;
b3Ref.Add( ptMinExtr) ;
b3Ref.Add( ptMaxExtr) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::IsFlat( Plane3d& plPlane, double dToler) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// polilinea dei punti rappresentativi
PolyLine shPL ;
int nLastPC = m_nDeg ;
for ( int i = 0 ; i <= nLastPC ; ++ i) {
double dU = i / double( nLastPC) ;
if ( ! shPL.AddUPoint( dU, GetControlPoint( i)))
return false ;
}
// recupero dati sulla planarità
int nRank ;
Point3d ptCen ;
Vector3d vtDir ;
bool bFlat = shPL.IsFlat( nRank, ptCen, vtDir, dToler) ;
// se punto
switch ( nRank) {
case 0 : // punto
if ( bFlat) {
plPlane.vtN = ( m_VtExtr.IsSmall() ? Z_AX : m_VtExtr) ;
plPlane.dDist = ( ptCen - ORIG) * plPlane.vtN ;
}
else {
plPlane.vtN = ( m_VtExtr.IsSmall() ? V_NULL : m_VtExtr) ;
plPlane.dDist = 0 ;
}
break ;
case 1 : // linea
if ( m_VtExtr.IsSmall()) {
plPlane.vtN = FromUprightOrtho( vtDir) ;
}
else {
plPlane.vtN = m_VtExtr ;
bFlat = bFlat && ( AreOrthoApprox( m_VtExtr, vtDir)) ;
}
plPlane.dDist = ( ptCen - ORIG) * plPlane.vtN ;
break ;
default : // piana o 3d
if ( m_VtExtr.IsSmall()) {
plPlane.vtN = vtDir ;
}
else {
plPlane.vtN = m_VtExtr ;
bFlat = bFlat && ( AreSameOrOppositeVectorApprox( m_VtExtr, vtDir)) ;
}
plPlane.dDist = ( ptCen - ORIG) * plPlane.vtN ;
break ;
}
return bFlat ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetStartPoint( Point3d& ptStart) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// assegno il punto
ptStart = m_aPtCtrl[0] ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetEndPoint( Point3d& ptEnd) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// assegno il punto
ptEnd = m_aPtCtrl[m_nDeg] ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetMidPoint( Point3d& ptMid) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// determino il valore del parametro a metà lunghezza
double dLen, dMid ;
if ( ! GetLength( dLen) || ! GetParamAtLength( 0.5 * dLen, dMid))
return false ;
// calcolo il punto
return GetPointD1D2( dMid, ptMid) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetCentroid( Point3d& ptCen) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// approssimo la curva con una polilinea
PolyLine PL ;
if ( ! ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_STD, PL))
return false ;
// calcolo il centro mediante PolygonPlane
Point3d ptP ;
PolygonPlane PolyPlane ;
for ( bool bFound = PL.GetFirstPoint( ptP) ; bFound ; bFound = PL.GetNextPoint( ptP))
PolyPlane.AddPoint( ptP) ;
if ( PolyPlane.GetCentroid( ptCen))
return true ;
// se non riuscito, uso il punto medio
return GetMidPoint( ptCen) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetMidDir( Vector3d& vtDir) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// determino il valore del parametro a metà lunghezza
double dLen, dMid ;
if ( ! GetLength( dLen) || ! GetParamAtLength( 0.5 * dLen, dMid))
return false ;
// calcolo la direzione
return ::GetTang( *this, dMid, FROM_MINUS, vtDir) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetPointD1D2( double dU, Side nS, Point3d& ptPos, Vector3d* pvtDer1, Vector3d* pvtDer2) const
{
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// il parametro U deve essere compreso tra 0 e 1
if ( dU < 0)
dU = 0 ;
else if ( dU > 1)
dU = 1 ;
// verifico se punto singolare
double dSingU ;
if ( GetSingularParam( dSingU) > 0 && fabs( dU - dSingU) < EPS_PARAM) {
if ( nS == ICurve::FROM_MINUS)
dU -= 100 * EPS_PARAM ;
else
dU += 100 * EPS_PARAM ;
}
return GetPointD1D2( dU, ptPos, pvtDer1, pvtDer2) ;
}
//----------------------------------------------------------------------------
// Calcolo i polinomi di Bernstein e da questi il punto ( vedi Piegl-Tiller)
//----------------------------------------------------------------------------
bool
CurveBezier::GetPointD1D2( double dU, Point3d& ptPos, Vector3d* pvtDer1, Vector3d* pvtDer2) const
{
int i ;
double dBern[MAXDEG] ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// il parametro U deve essere compreso tra 0 e 1
if ( dU < 0)
dU = 0 ;
else if ( dU > 1)
dU = 1 ;
// se forma polinomiale (o integrale)
if ( ! m_bRat) {
// calcolo dei polinomi di Bernstein di grado opportuno
dBern[0] = 1 ;
for ( i = 1 ; i <= m_nDeg - 2 ; ++ i)
IncreaseBernsteinOneDegree( dU, i, dBern) ;
// se richiesto, calcolo della derivata seconda
if ( pvtDer2 != nullptr && pvtDer1 != nullptr) {
pvtDer2->Set( 0, 0, 0) ;
for ( i = 0 ; i <= m_nDeg - 2 ; ++ i) {
*pvtDer2 += dBern[i] * ( m_aPtCtrl[i+2] + m_aPtCtrl[i] - 2 * m_aPtCtrl[i+1]) ;
}
*pvtDer2 *= m_nDeg * ( m_nDeg - 1) ;
}
// aumento il grado
IncreaseBernsteinOneDegree( dU, m_nDeg - 1, dBern) ;
// se richiesto, calcolo della derivata prima
if ( pvtDer1 != nullptr) {
pvtDer1->Set( 0, 0, 0) ;
for ( i = 0 ; i <= m_nDeg - 1 ; ++ i) {
*pvtDer1 += dBern[i] * ( m_aPtCtrl[i+1] - m_aPtCtrl[i]) ;
}
*pvtDer1 *= m_nDeg ;
}
// aumento il grado
IncreaseBernsteinOneDegree( dU, m_nDeg, dBern) ;
// calcolo del punto
ptPos.Set( 0, 0, 0) ;
for ( i = 0 ; i <= m_nDeg ; ++ i)
ptPos += dBern[i] * m_aPtCtrl[i] ;
}
// altrimenti forma razionale
else {
double dW ;
double dW1 ;
double dW2 ;
double dInvW ;
Point3d aPtWCtrl[MAXDEG] ;
Vector3d vtPos ;
// porto i punti in forma omogenea moltiplicandoli per i pesi
for ( i = 0 ; i <= m_nDeg ; ++ i)
aPtWCtrl[i] = m_aWeCtrl[i] * m_aPtCtrl[i] ;
// calcolo dei polinomi di Bernstein di grado opportuno
dBern[0] = 1 ;
for ( i = 1 ; i <= m_nDeg - 2 ; ++ i)
IncreaseBernsteinOneDegree( dU, i, dBern) ;
// se richiesto, calcolo della derivata seconda
if ( pvtDer2 != nullptr && pvtDer1 != nullptr) {
pvtDer2->Set( 0, 0, 0) ; dW2 = 0 ;
for ( i = 0 ; i <= m_nDeg - 2 ; ++ i) {
*pvtDer2 += dBern[i] * ( aPtWCtrl[i+2] + aPtWCtrl[i] - 2 * aPtWCtrl[i+1]) ;
dW2 += dBern[i] * ( m_aWeCtrl[i+2] + m_aWeCtrl[i] - 2 * m_aWeCtrl[i+1]) ;
}
*pvtDer2 *= m_nDeg * ( m_nDeg - 1) ;
dW2 *= m_nDeg * ( m_nDeg - 1) ;
}
// aumento il grado
IncreaseBernsteinOneDegree( dU, m_nDeg - 1, dBern) ;
// se richiesto, calcolo della derivata prima
if ( pvtDer1 != nullptr) {
pvtDer1->Set( 0, 0, 0) ; dW1 = 0 ;
for ( i = 0 ; i <= m_nDeg - 1 ; ++ i) {
*pvtDer1 += dBern[i] * ( aPtWCtrl[i+1] - aPtWCtrl[i]) ;
dW1 += dBern[i] * ( m_aWeCtrl[i+1] - m_aWeCtrl[i]) ;
}
*pvtDer1 *= m_nDeg ;
dW1 *= m_nDeg ;
}
// aumento il grado
IncreaseBernsteinOneDegree( dU, m_nDeg, dBern) ;
// calcolo del punto
ptPos.Set( 0, 0, 0) ; dW = 0 ;
for ( i = 0 ; i <= m_nDeg ; ++ i) {
ptPos += dBern[i] * aPtWCtrl[i] ;
dW += dBern[i] * m_aWeCtrl[i] ;
}
// ritrasformo da forma omogenea a forma standard
dInvW = 1 / ( ( dW > EPS_ZERO) ? dW : EPS_ZERO) ;
ptPos *= dInvW ;
if ( pvtDer1 != nullptr) {
vtPos.Set( ptPos.x, ptPos.y, ptPos.z) ;
*pvtDer1 = ( *pvtDer1 - dW1 * vtPos) * dInvW ;
if ( pvtDer2 != nullptr)
*pvtDer2 = ( *pvtDer2 - 2 * dW1 * *pvtDer1 - dW2 * vtPos) * dInvW ;
}
}
return true ;
}
//----------------------------------------------------------------------------
void
CurveBezier::IncreaseBernsteinOneDegree( double dU, int nDeg, double dBern[]) const
{
int j ;
double dU1 ;
double dTot ;
double dTmp ;
dU1 = 1 - dU ;
dTot = 0 ;
for ( j = 0 ; j < nDeg ; ++ j) {
dTmp = dBern[j] ;
dBern[j] = dTot + dU1 * dTmp ;
dTot = dU * dTmp ;
}
dBern[nDeg] = ( nDeg > 0 ? dTot : 1) ;
}
//----------------------------------------------------------------------------
int
CurveBezier::GetSingularParam( double& dPar) const
{
// se da calcolare, lo faccio
if ( m_dParSing < -1.5)
CalcSingularParam() ;
// se esiste singolarità
if ( m_dParSing > 0 && m_dParSing < 1) {
dPar = m_dParSing ;
return 1 ;
}
// altrimenti, non esiste
else
return 0 ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::CalcSingularParam( void) const
{
// non si considerano singolarità agli estremi ( non creano problemi)
// le curve di grado 1 non possono avere singolarità
if ( m_nDeg <= 1) {
m_dParSing = -1 ;
return true ;
}
// le curve di grado 2 possono avere singolarità solo se i punti sono allineati con ordine P0 P2 P1
if ( m_nDeg == 2) {
Vector3d vtV1 = m_aPtCtrl[1] - m_aPtCtrl[0] ;
Vector3d vtV2 = m_aPtCtrl[2] - m_aPtCtrl[1] ;
if ( ( vtV1 * vtV2) > - EPS_ZERO) {
m_dParSing = -1 ;
return true ;
}
}
// calcolo della derivata o del suo numeratore se curva razionale
PolynomialPoint3d pol3P ;
// se polinomiale
if ( ! m_bRat) {
// derivata come curva di Bezier delle differenze tra i punti di controllo
CurveBezier cbDeriv ;
cbDeriv.Init( m_nDeg - 1, false) ;
for ( int i = 0 ; i < m_nDeg ; ++ i)
cbDeriv.SetControlPoint( i, m_nDeg * ( m_aPtCtrl[i+1] + ( - m_aPtCtrl[i]))) ;
// trasformo nella forma monomia
cbDeriv.ToPowerBase( pol3P) ;
}
// altrimenti razionale
else {
// numeratore e denominatore in forma monomia
PolynomialPoint3d pol3Num ;
Polynomial polDen ;
ToPowerBase( pol3Num, polDen) ;
// derivata del numeratore
PolynomialPoint3d pol3NumD ;
pol3NumD.Derive( pol3Num) ;
// derivata del denominatore
Polynomial polDenD ;
polDenD.Derive( polDen) ;
// numeratore della derivata complessiva ( NumD * Den - Num * DenD)
pol3P = pol3NumD * polDen - pol3Num * polDenD ;
pol3P.AdjustDegree() ;
}
// calcolo gli zeri della componente più importante della derivata
DBLVECTOR vdRoot ;
int nZ = pol3P.FindMainComponentRoots( vdRoot) ;
// scarto gli zeri fuori dall'intervallo aperto 0-1 e quelli ripetuti
nZ = FilterMultipleAndOutOfRangeRoots( vdRoot, 0 + EPS_PARAM, 1 - EPS_PARAM, EPS_PARAM) ;
// verifico se in corrispondenza di qualche zero si annulla la derivata
Point3d ptPos ;
Vector3d vtDer1 ;
for ( int i = 0 ; i < nZ ; ++ i) {
GetPointD1D2( vdRoot[i], ptPos, &vtDer1) ;
if ( vtDer1.IsZero()) {
m_dParSing = vdRoot[i] ;
LOG_DBG_INFO( GetEGkLogger(), "INFO : Found Singularity in CurveBezier")
return true ;
}
}
// non ci sono singolarità
m_dParSing = -1 ;
return true ;
}
//----------------------------------------------------------------------------
// i coefficienti sono ordinati dalla potenza più bassa alla più alta
// se razionale, ritorna la sola forma monomiale del numeratore
//----------------------------------------------------------------------------
bool
CurveBezier::ToPowerBase( PolynomialPoint3d& pol3P) const
{
// creo un vettore di punti ausiliario (pulito e di dimensioni adeguate)
PNTVECTOR vPow ;
vPow.clear() ;
vPow.reserve( m_nDeg + 1) ;
// algoritmo di Sederberg (BYU) CAGD cap. 3
// copio i punti di controllo
for ( int i = 0 ; i <= m_nDeg ; ++ i)
vPow.push_back( m_aPtCtrl[i]) ;
// se razionale, li moltiplico per i relativi pesi
if ( m_bRat) {
for ( int i = 0 ; i <= m_nDeg ; ++ i)
vPow[i] *= m_aWeCtrl[i] ;
}
// applico differenze successive, lasciando sul posto il risultato
for ( int i = 1 ; i <= m_nDeg ; ++ i) {
for ( int j = m_nDeg ; j >= i ; -- j)
vPow[j] += - vPow[j-1] ;
}
// calcolo i coefficienti binomiali
double dBinom[ MAXDEG+1] ;
dBinom[0] = 1 ;
for ( int i = 1 ; i <= m_nDeg ; ++ i)
dBinom[i] = 0 ;
for ( int i = 1 ; i <= m_nDeg ; ++ i) {
for ( int j = i ; j > 0 ; -- j)
dBinom[j] += dBinom[j-1] ;
}
// ottengo i coefficienti delle potenze
for ( int i = 1 ; i <= m_nDeg ; ++ i)
vPow[i] *= dBinom[i] ;
// assegno il risultato al parametro di ritorno
pol3P.Set( m_nDeg, vPow) ;
return true ;
}
//----------------------------------------------------------------------------
// i coefficienti sono ordinati dalla potenza più bassa alla più alta
// se polinomiale, la forma monomiale del denominatore è un 1
//----------------------------------------------------------------------------
bool
CurveBezier::ToPowerBase( PolynomialPoint3d& pol3Num, Polynomial& polDen) const
{
// creo un vettore di punti ausiliario (pulito e di dimensioni adeguate)
PNTVECTOR vPow ;
vPow.reserve( m_nDeg + 1) ;
// creo un vettore di double ausiliario (pulito e di dimensioni adeguate)
DBLVECTOR dPow ;
if ( m_bRat)
dPow.reserve( m_nDeg + 1) ;
// algoritmo di Sederberg (BYU) CAGD cap. 3
// copio i punti di controllo
for ( int i = 0 ; i <= m_nDeg ; ++ i)
vPow.push_back( m_aPtCtrl[i]) ;
// se razionale
if ( m_bRat) {
// moltiplico i punti per i relativi pesi
for ( int i = 0 ; i <= m_nDeg ; ++ i)
vPow[i] *= m_aWeCtrl[i] ;
// copio i pesi
for ( int i = 0 ; i <= m_nDeg ; ++ i)
dPow.push_back( m_aWeCtrl[i]) ;
}
// applico differenze successive, lasciando sul posto il risultato
for ( int i = 1 ; i <= m_nDeg ; ++ i) {
for ( int j = m_nDeg ; j >= i ; -- j) {
vPow[j] += - vPow[j-1] ;
if ( m_bRat)
dPow[j] += - dPow[j-1] ;
}
}
// calcolo i coefficienti binomiali
double dBinom[ MAXDEG+1] ;
dBinom[0] = 1 ;
for ( int i = 1 ; i <= m_nDeg ; ++ i)
dBinom[i] = 0 ;
for ( int i = 1 ; i <= m_nDeg ; ++ i) {
for ( int j = i ; j > 0 ; -- j)
dBinom[j] += dBinom[j-1] ;
}
// ottengo i coefficienti delle potenze
for ( int i = 1 ; i <= m_nDeg ; ++ i) {
vPow[i] *= dBinom[i] ;
if ( m_bRat)
dPow[i] *= dBinom[i] ;
}
// assegno i risultati ai parametri di ritorno
pol3Num.Set( m_nDeg, vPow) ;
if ( m_bRat)
polDen.Set( m_nDeg, dPow) ;
else
polDen.SetToConstant( 1) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetControlPolygonLength( double& dLen) const
{
// la curva deve essere valida
if ( m_nStatus != OK)
return false ;
// ciclo sui punti di controllo
dLen = 0 ;
for ( int i = 1 ; i <= m_nDeg ; ++ i)
dLen += Dist( m_aPtCtrl[i], m_aPtCtrl[i-1]) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetLength( double& dLen) const
{
return ( GetLengthAtParam( 1, dLen) && dLen > EPS_SMALL) ;
}
//----------------------------------------------------------------------------
double
CurveBezier::GetSegmentLength( int nLev, double dU0, double dU1, double dU2,
const Point3d& ptP0, const Point3d& ptP1, const Point3d& ptP2) const
{
const int MAX_LEV = 10 ;
const double MAX_ARC = 1.05 ;
const double LEN_RATIO = 1.2 ;
double dD1 ;
double dDa ;
double dDb ;
double dD2 ;
// algoritmo dell'approssimazione con arco per tre punti di S. Vincent e D. Forsey
// verifica superamento del massimo livello di recursione per debug
if ( nLev >= MAX_LEV)
LOG_DBG_ERR( GetEGkLogger(), "ERROR : Exceeded recursions")
// calcolo delle distanze
dD1 = Dist( ptP0, ptP2) ;
dDa = Dist( ptP0, ptP1) ;
dDb = Dist( ptP1, ptP2) ;
dD2 = dDa + dDb ;
// distanza piccola o massimo livello di recursione, approx arco ok
if ( dD2 < EPS_SMALL || nLev >= MAX_LEV)
return ( dD2 + ( dD2 - dD1) / 3) ;
// se ci sono anomalie si suddivide
if ( dD1 < EPS_SMALL || dD2 / dD1 > MAX_ARC ||
dDa < 0.1 * EPS_SMALL || dDb / dDa > LEN_RATIO ||
dDb < 0.1 * EPS_SMALL || dDa / dDb > LEN_RATIO) {
double dUMid ;
Point3d ptMid ;
// prima metà
dUMid = 0.5 * ( dU0 + dU1) ;
GetPointD1D2( dUMid, ptMid) ;
double dD3 = GetSegmentLength( nLev +1, dU0, dUMid, dU1,
ptP0, ptMid, ptP1) ;
// seconda metà
dUMid = 0.5 * ( dU1 + dU2) ;
GetPointD1D2( dUMid, ptMid) ;
double dD4 = GetSegmentLength( nLev + 1, dU1, dUMid, dU2,
ptP1, ptMid, ptP2) ;
// la lunghezza è la somma delle due
return ( dD3 + dD4) ;
}
// caso normale
return ( dD2 + ( dD2 - dD1) / 3) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetLengthAtParam( double dU, double& dLen) const
{
const int NUM_SEG = 16 ;
double dUIni ;
double dUMid ;
double dUFin ;
Point3d ptIni ;
Point3d ptMid ;
Point3d ptFin ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// fuori dominio del parametro -> errore
if ( dU < 0 - EPS_PARAM)
return false ;
if ( dU > ( 1 + EPS_PARAM))
return false ;
// inizio
if ( dU < 0 + EPS_PARAM) {
dLen = 0 ;
return true ;
}
// parto con un numero fisso di punti e poi affino dove serve
dLen = 0 ;
dUIni = 0 ;
GetPointD1D2( 0, ptIni) ;
for ( int i = 1 ; i <= NUM_SEG ; ++ i) {
// ricavo il punto
dUFin = i / (double) NUM_SEG * dU ;
GetPointD1D2( dUFin, ptFin) ;
// se punto dispari
if ( ( i % 2) == 1) {
// assegno nuovo medio
dUMid = dUFin ;
ptMid = ptFin ;
}
// se punto pari, calcolo la lunghezza
else {
dLen += GetSegmentLength( 0, dUIni, dUMid, dUFin, ptIni, ptMid, ptFin) ;
// nuovo iniziale prende i valori del finale
dUIni = dUFin ;
ptIni = ptFin ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetSegmentParam( double dLen, double& dCurrLen, double& dSegLen,
double& dUIni, double& dUFin) const
{
const int NUM_SEG = 16 ;
double dUMid ;
Point3d ptIni ;
Point3d ptMid ;
Point3d ptFin ;
double dUStart = dUIni ;
double dUEnd = dUFin ;
GetPointD1D2( dUIni, ptIni) ;
for ( int i = 1 ; i <= NUM_SEG ; ++ i) {
// ricavo il punto
dUFin = dUStart + i / (double) NUM_SEG * ( dUEnd - dUStart) ;
GetPointD1D2( dUFin, ptFin) ;
// se punto dispari
if ( ( i % 2) == 1) {
// assegno nuovo medio
dUMid = dUFin ;
ptMid = ptFin ;
}
// se punto pari, calcolo la lunghezza
else {
dSegLen = GetSegmentLength( 0, dUIni, dUMid, dUFin, ptIni, ptMid, ptFin) ;
if ( ( dCurrLen + dSegLen) >= dLen) {
return true ;
}
else
dCurrLen += dSegLen ;
// nuovo iniziale prende i valori del finale
dUIni = dUFin ;
ptIni = ptFin ;
}
}
return false ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetParamAtLength( double dLen, double& dU) const
{
const double MIN_SEG_LEN = 0.2 ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// se prima di inizio, errore
if ( dLen < - EPS_SMALL)
return false ;
// inizio
if ( dLen < EPS_SMALL) {
dU = 0 ;
return true ;
}
// approfondisco nell'intervallo di interesse
bool bOk ;
double dSegLen ;
double dCurrLen = 0 ;
double dUIni = 0 ;
double dUFin = 1 ;
while ( ( bOk = GetSegmentParam( dLen, dCurrLen, dSegLen, dUIni, dUFin)) && dSegLen > MIN_SEG_LEN) {
// allungo di un poco l'intervallo di ricerca per compensare l'approssimazione della lunghezza
dUFin = min( dUFin + ( dUFin - dUIni) * 0.05, 1.) ;
}
// aggiustamento finale parametro
if ( bOk)
dU = dUIni + ( dLen - dCurrLen) / dSegLen * ( dUFin - dUIni) ;
return bOk ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::IsPointOn( const Point3d& ptP, double dTol) const
{
double dSqDist ;
dTol = max( dTol, EPS_ZERO) ;
return ( DistPointCrvBezier( ptP, *this).GetSqDist( dSqDist) && dSqDist < dTol * dTol) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetParamAtPoint( const Point3d& ptP, double& dPar, double dTol) const
{
double dSqDist ;
dTol = max( dTol, EPS_ZERO) ;
DistPointCrvBezier DPB( ptP, *this) ;
if ( ! DPB.GetSqDist( dSqDist) || dSqDist > dTol * dTol)
return false ;
int nFlag ;
return DPB.GetParamAtMinDistPoint( 0, dPar, nFlag) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetLengthAtPoint( const Point3d& ptP, double& dLen, double dTol) const
{
double dU ;
if ( ! GetParamAtPoint( ptP, dU, dTol))
return false ;
return GetLengthAtParam( dU, dLen) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::ApproxWithLines( double dLinTol, double dAngTolDeg, int nType, PolyLine& PL) const
{
// pulisco la polilinea
PL.Clear() ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// se di primo grado, basta inserire gli estremi
if ( m_nDeg == 1) {
return ( PL.AddUPoint( 0, m_aPtCtrl[0]) && PL.AddUPoint( 1, m_aPtCtrl[m_nDeg])) ;
}
// limiti minimi su tolleranza e deviazione angolare
dLinTol = max( dLinTol, LIN_TOL_MIN) ;
dAngTolDeg = max( dAngTolDeg, ANG_TOL_MIN_DEG) ;
// se lineare con lato obbligato, gestione speciale
if ( nType == APL_LEFT || nType == APL_LEFT_CONVEX ||
nType == APL_RIGHT || nType == APL_RIGHT_CONVEX) {
// prima approssimazione lineare a 10 * Epsilon
if ( ! ApproxWithLines( 10 * EPS_SMALL, dAngTolDeg, APL_STD, PL))
return false ;
// eliminazione dei punti in tolleranza andando solo dalla parte ammessa
Vector3d vtExtr = ( m_VtExtr.IsSmall() ? Z_AX : m_VtExtr) ;
if ( ! PL.ApproxOnSide( vtExtr, ( nType == APL_LEFT), dLinTol))
return false ;
// se necessario, sistemo per convessità dalla parte ammessa
if ( nType == APL_RIGHT_CONVEX || nType == APL_LEFT_CONVEX) {
if ( ! PL.MakeConvex( vtExtr, ( nType == APL_LEFT_CONVEX)))
return false ;
}
return true ;
}
// inserisco il punto iniziale
if ( ! PL.AddUPoint( 0, m_aPtCtrl[0]))
return false ;
// verifico se va divisa
if ( ! FlatOrSplit( 0, *this, 0, 1, dLinTol, dAngTolDeg, PL))
return false ;
// se è stato inserito un solo punto, aggiungo il finale
if ( PL.GetPointNbr() == 1)
return PL.AddUPoint( 1, m_aPtCtrl[m_nDeg]) ;
// altrimenti, se l'ultimo punto non coincide con il finale lo sostituisco (distano al max di dLinTol)
else {
Point3d ptLast ;
PL.GetLastPoint( ptLast) ;
if ( ! AreSamePointApprox( ptLast, m_aPtCtrl[m_nDeg])) {
PL.EraseLastUPoint() ;
return PL.AddUPoint( 1, m_aPtCtrl[m_nDeg]) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::FlatOrSplit( int nLev, const CurveBezier& crvBez, double dParStart, double dParEnd,
double dLinTol, double dAngTolDeg, PolyLine& PL) const
{
// se raggiunto il massimo livello di recursione ...
const int MAX_LEV = 10 ;
if ( nLev >= MAX_LEV) {
// segnalo situazione per debug
LOG_DBG_ERR( GetEGkLogger(), "ERROR : Exceeded recursions")
// considero la curva piatta (inserisco il punto se abbastanza lontano dal precedente) ed esco
Point3d ptLast ;
PL.GetLastPoint( ptLast) ;
if ( SqDist( ptLast, crvBez.m_aPtCtrl[m_nDeg]) > ( dLinTol * dLinTol))
PL.AddUPoint( dParEnd, crvBez.m_aPtCtrl[m_nDeg]) ;
return true ;
}
// massima distanza al quadrato dei punti di controllo intermedi dalla linea tra primo e ultimo
double dMaxSqDist = 0 ;
double dLen ;
Vector3d vtDir ;
DirDist( crvBez.m_aPtCtrl[0], crvBez.m_aPtCtrl[m_nDeg], vtDir, dLen) ;
for ( int i = 1 ; i < m_nDeg ; i ++) {
DistPointLine dstPL( crvBez.m_aPtCtrl[i], crvBez.m_aPtCtrl[0], vtDir, dLen) ;
double dSqDist ;
if ( dstPL.GetSqDist( dSqDist) && dSqDist > dMaxSqDist)
dMaxSqDist = dSqDist ;
}
// se distanza entro tolleranza
if ( dMaxSqDist <= ( dLinTol * dLinTol)) {
// deviazione angolare tra primo e ultimo tratto del poligono di controllo (grado >= 1)
Vector3d vtDirI = crvBez.m_aPtCtrl[1] - crvBez.m_aPtCtrl[0] ;
Vector3d vtDirF = crvBez.m_aPtCtrl[m_nDeg] - crvBez.m_aPtCtrl[m_nDeg-1] ;
double dAngDeg ;
vtDirI.GetAngle( vtDirF, dAngDeg) ;
// se deviazione angolare entro tolleranza oppure lunghezza poligono controllo entro tolleranza
double dPolLen ;
if ( fabs( dAngDeg) <= dAngTolDeg ||
( crvBez.GetControlPolygonLength( dPolLen) && dPolLen <= dLinTol)) {
// considero la curva piatta (inserisco il punto se abbastanza lontano dal precedente) ed esco
Point3d ptLast ;
PL.GetLastPoint( ptLast) ;
if ( SqDist( ptLast, crvBez.m_aPtCtrl[m_nDeg]) > ( dLinTol * dLinTol))
PL.AddUPoint( dParEnd, crvBez.m_aPtCtrl[m_nDeg]) ;
return true ;
}
}
// curva da dividere
{
double dParDiv ;
double dParMid ;
CurveBezier crvBez1 ;
// se prima suddivisione e c'è singolarità, divido su questa
if ( nLev == 0 && GetSingularParam( dParDiv) > 0)
;
// altrimenti divido a metà
else
dParDiv = 0.5 ;
dParMid = dParDiv * ( dParStart + dParEnd) ;
// prima metà
crvBez1 = crvBez ;
crvBez1.TrimEndAtParam( dParDiv) ;
if ( ! FlatOrSplit( nLev + 1, crvBez1, dParStart, dParMid, dLinTol, dAngTolDeg, PL))
return false ;
// seconda metà
crvBez1 = crvBez ;
crvBez1.TrimStartAtParam( dParDiv) ;
if ( ! FlatOrSplit( nLev + 1, crvBez1, dParMid, dParEnd, dLinTol, dAngTolDeg, PL))
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const
{
// se estrusione definita e diversa da Z+
if ( ! m_VtExtr.IsSmall() && ! m_VtExtr.IsZplus()) {
// devo portarmi in un piano perpendicolare all'estrusione per costruirvi gli archi
Frame3d frExtr ;
if ( ! frExtr.Set( ORIG, m_VtExtr))
return false ;
// copio la curva e la porto nel riferimento di estrusione
CurveBezier crvAux ;
if ( ! crvAux.CopyFrom( *this))
return false ;
crvAux.ToLoc( frExtr) ;
// approssimo
bool bOk = crvAux.ApproxWithArcsXY( dLinTol, dAngTolDeg, PA) ;
// porto il risultato nel riferimento originale
PA.ToGlob( frExtr) ;
return bOk ;
}
// l'estrusione è secondo Z+, pertanto sono già nel piano XY
else
return ApproxWithArcsXY( dLinTol, dAngTolDeg, PA) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::ApproxWithArcsXY( double dLinTol, double dAngTolDeg, PolyArc& PA) const
{
// si creano gli archi nel piano XY
// pulisco il poliarco
PA.Clear() ;
// costruisco una approssimazione lineare
PolyLine PL ;
if ( ! ApproxWithLines( dLinTol, dAngTolDeg, ICurve::APL_STD, PL))
return false ;
// approssimo la curva per approssimazioni successive mediante bisezione
return BiArcOrSplit( 0, PL, dLinTol, dAngTolDeg, PA) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::BiArcOrSplit( int nLev, PolyLine& PL, double dLinTol, double dAngTolDeg, PolyArc& PA) const
{
const int MAX_LEV = 10 ;
// se non chiusa
if ( ! PL.IsClosed()) {
PtrOwner<ICurve> pCrv ;
double dMaxDist ;
// se la polilinea ha più di 2 punti
if ( PL.GetPointNbr() > 2) {
// calcolo punti e direzioni agli estremi della polilinea usando la curva di Bezier
double dU ;
Point3d ptP0, ptP1 ;
Vector3d vtDir ;
double dDir0Deg, dDir1Deg ;
if ( ! PL.GetFirstU( dU) || ! GetPointTang( dU, ICurve::FROM_PLUS, ptP0, vtDir))
return false ;
vtDir.ToSpherical( nullptr, nullptr, &dDir0Deg) ;
if ( ! PL.GetLastU( dU) || ! GetPointTang( dU, ICurve::FROM_MINUS, ptP1, vtDir))
return false ;
vtDir.ToSpherical( nullptr, nullptr, &dDir1Deg) ;
// costruisco un biarco sulla polilinea (secondo metodo di Z. Sir)
pCrv.Set( GetBiArc( ptP0, dDir0Deg, ptP1, dDir1Deg, PL, dMaxDist)) ;
if ( IsNull( pCrv))
return false ;
}
// se la polilinea è formata da 2 punti
else if ( PL.GetPointNbr() == 2) {
// se molto vicini, esco
double dLen ;
if ( PL.GetLength( dLen) && dLen < EPS_SMALL)
return true ;
// costruisco la retta che li unisce
PtrOwner<CurveComposite> pCC( CreateBasicCurveComposite()) ;
if ( IsNull( pCC))
return false ;
if ( ! pCC->FromPolyLine( PL))
return false ;
pCrv.Set( Release( pCC)) ;
dMaxDist = 0 ;
}
// se la polilinea ha un solo punto, esco
else
return true ;
// se raggiunto il massimo livello di recursione, forzo l'accettazione del biarco
if ( nLev >= MAX_LEV) {
dMaxDist = 0 ;
// segnalo situazione per debug
LOG_DBG_ERR( GetEGkLogger(), "ERROR : Exceeded recursions")
}
// se lunghezza abbastanza picccola, forzo l'accettazione della curva
double dLen ;
if ( PL.GetApproxLength( dLen) && dLen < 10 * EPS_SMALL)
dMaxDist = 0 ;
// se in tolleranza
if ( dMaxDist <= dLinTol) {
// creo un nuovo poliarco
PolyArc PA2 ;
if ( ! pCrv->ApproxWithArcs( dLinTol, dAngTolDeg, PA2))
return false ;
// aggiusto la parametrizzazione
double dUStart, dUEnd ;
PL.GetFirstU( dUStart) ;
PL.GetLastU( dUEnd) ;
PA2.ParamLinearTransform( dUStart, dUEnd) ;
// accodo all'esistente
if ( ! PA.Join( PA2))
return false ;
// esco
return true ;
}
}
// se raggiunto il massimo livello di recursione, errore
if ( nLev >= MAX_LEV) {
// segnalo situazione per debug
LOG_DBG_ERR( GetEGkLogger(), "ERROR : Exceeded recursions")
return false ;
}
// spezzo l'intervallo in due parti
double dParMid ;
// se prima suddivisione e c'è singolarità, divido su questa
if ( nLev == 0 && GetSingularParam( dParMid) > 0)
;
// altrimenti divido a metà
else {
double dParStart, dParEnd ;
if ( ! PL.GetFirstU( dParStart) || ! PL.GetLastU( dParEnd))
return false ;
dParMid = 0.5 * ( dParStart + dParEnd) ;
}
PolyLine PL2 ;
if ( ! PL.Split( dParMid, PL2))
return false ;
// prima metà
if ( ! BiArcOrSplit( nLev + 1, PL, dLinTol, dAngTolDeg, PA))
return false ;
// seconda metà
return BiArcOrSplit( nLev + 1, PL2, dLinTol, dAngTolDeg, PA) ;
}
//----------------------------------------------------------------------------
ICurve*
CurveBezier::CopyParamRange( double dUStart, double dUEnd) const
{
// i parametri start ed end devono essere compresi nel dominio parametrico della curva
if ( dUStart < - EPS_PARAM || dUStart > 1 + EPS_PARAM ||
dUEnd < - EPS_PARAM || dUEnd > 1 + EPS_PARAM)
return nullptr ;
// se il parametro start supera quello di end
if ( dUStart > dUEnd - EPS_PARAM) {
// se curva aperta, il trim la cancella completamente quindi non resta alcunchè
if ( ! IsClosed())
return nullptr ;
// se curva chiusa, il trim si avvolge attorno al punto di giunzione
else {
// eseguo la copia sulla curva composita equivalente
CurveComposite cCompo ;
cCompo.CopyFrom( this) ;
return cCompo.CopyParamRange( dUStart, dUEnd) ;
}
}
// creo la curva di Bezier copia
PtrOwner<CurveBezier> pCopy( Clone()) ;
if ( IsNull( pCopy))
return nullptr ;
// eseguo il trim
if ( ! pCopy->TrimStartEndAtParam( dUStart, dUEnd))
return nullptr ;
return ( ::Release( pCopy)) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Invert( void)
{
// la curva deve essere valida
if ( m_nStatus != OK)
return false ;
// inverto i punti di controllo
int nMid = ( m_nDeg + 1) / 2 ;
for ( int i = 0 ; i < nMid ; ++ i) {
Point3d ptTemp = m_aPtCtrl[i] ;
m_aPtCtrl[i] = m_aPtCtrl[m_nDeg-i] ;
m_aPtCtrl[m_nDeg-i] = ptTemp ;
}
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::ModifyStart( const Point3d& ptNewStart)
{
// la curva deve essere valida
if ( m_nStatus != OK)
return false ;
// modifico il primo punto di controllo
m_aPtCtrl[0] = ptNewStart ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::ModifyEnd( const Point3d& ptNewEnd)
{
// la curva deve essere valida
if ( m_nStatus != OK)
return false ;
// modifico l'ultimo punto di controllo
m_aPtCtrl[m_nDeg] = ptNewEnd ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::TrimStartAtParam( double dUTrim)
{
// la curva deve essere valida
if ( m_nStatus != OK)
return false ;
// se devo togliere dall'inizio o prima non tolgo niente
if ( dUTrim <= 0)
return true ;
// se devo togliere a partire dalla fine o dopo non rimane niente
if ( dUTrim >= 1)
return false ;
// eseguo il trim (algoritmo di de Casteljau)
for ( int k = 1 ; k <= m_nDeg ; k ++) {
for ( int i = 0 ; i <= m_nDeg - k ; i ++) {
if ( ! m_bRat) {
m_aPtCtrl[i] = ( 1 - dUTrim) * m_aPtCtrl[i] + dUTrim * m_aPtCtrl[i+1] ;
}
else {
m_aPtCtrl[i] = ( 1 - dUTrim) * m_aWeCtrl[i] * m_aPtCtrl[i] + dUTrim * m_aWeCtrl[i+1] * m_aPtCtrl[i+1] ;
m_aWeCtrl[i] = ( 1 - dUTrim) * m_aWeCtrl[i] + dUTrim * m_aWeCtrl[i+1] ;
m_aPtCtrl[i] = m_aPtCtrl[i] * ( 1 / m_aWeCtrl[i]) ;
}
}
}
// con i controlli sopra fatti rimane validata, ma la grafica va ricalcolata
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::TrimEndAtParam( double dUTrim)
{
// la curva deve essere valida
if ( m_nStatus != OK)
return false ;
// se devo togliere a partire dall'inizio o prima non rimane niente
if ( dUTrim < EPS_PARAM)
return false ;
// se devo togliere dalla fine o dopo non tolgo niente
if ( dUTrim > 1 - EPS_PARAM)
return true ;
// eseguo il trim (algoritmo di de Casteljau)
for ( int k = 1 ; k <= m_nDeg ; k ++) {
for ( int i = m_nDeg ; i >= k ; i --) {
if ( ! m_bRat) {
m_aPtCtrl[i] = ( 1 - dUTrim) * m_aPtCtrl[i-1] + dUTrim * m_aPtCtrl[ i] ;
}
else {
m_aPtCtrl[i] = ( 1 - dUTrim) * m_aWeCtrl[i-1] * m_aPtCtrl[i-1] + dUTrim * m_aWeCtrl[ i] * m_aPtCtrl[ i] ;
m_aWeCtrl[i] = ( 1 - dUTrim) * m_aWeCtrl[i-1] + dUTrim * m_aWeCtrl[ i] ;
m_aPtCtrl[i] = m_aPtCtrl[i] * ( 1 / m_aWeCtrl[i]) ;
}
}
}
// con i controlli sopra fatti rimane validata, ma la grafica va ricalcolata
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::TrimStartEndAtParam( double dUStartTrim, double dUEndTrim)
{
// i parametri start ed end devono essere compresi nel dominio parametrico della curva
if ( dUStartTrim < - EPS_PARAM || dUStartTrim > 1 + EPS_PARAM ||
dUEndTrim < - EPS_PARAM || dUEndTrim > 1 + EPS_PARAM)
return false ;
// verifico che i trim non cancellino interamente la curva
if ( dUStartTrim > dUEndTrim - EPS_PARAM)
return false ;
// trim finale
if ( ! TrimEndAtParam( dUEndTrim))
return false ;
// trim iniziale con il parametro opportunamente ricalcolato
double dNewUStartTrim = dUStartTrim / dUEndTrim ;
return TrimStartAtParam( dNewUStartTrim) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::TrimStartAtLen( double dLenTrim)
{
// lunghezze negative vengono considerate nulle
dLenTrim = max( dLenTrim, 0.) ;
// converto le lunghezze in valori parametrici
double dUTrim ;
if ( ! GetParamAtLength( dLenTrim, dUTrim))
return false ;
// utilizzo il trim sui parametri
return TrimStartAtParam( dUTrim) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::TrimEndAtLen( double dLenTrim)
{
// lunghezze negative vengono considerate nulle
dLenTrim = max( dLenTrim, 0.) ;
// converto le lunghezze in valori parametrici
double dUTrim ;
if ( ! GetParamAtLength( dLenTrim, dUTrim))
return false ;
// utilizzo il trim sui parametri
return TrimEndAtParam( dUTrim) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::ExtendStartByLen( double dLenExt)
{
// la lunghezza deve essere positiva
if ( dLenExt < - EPS_ZERO)
return false ;
// determino la lunghezza originale della curva
double dLen ;
if ( ! GetLength( dLen))
return false ;
// stimo il valore del parametro al nuovo punto iniziale
double dUTrim = - dLenExt / dLen ;
// estrapolo sul parametro con de Casteljau
// se polinomiale, va sicuramente bene
if ( ! m_bRat) {
for ( int k = 1 ; k <= m_nDeg ; k ++) {
for ( int i = 0 ; i <= m_nDeg - k ; i ++)
m_aPtCtrl[i] = ( 1 - dUTrim) * m_aPtCtrl[i] + dUTrim * m_aPtCtrl[i+1] ;
}
}
// se razionale, devo verificare che i pesi non diventino negativi
else {
Point3d aPtCtrl[MAXDEG+1] ;
double aWeCtrl[MAXDEG+1] ;
for ( int i = 0 ; i <= m_nDeg ; i ++) {
aPtCtrl[i] = m_aPtCtrl[i] ;
aWeCtrl[i] = m_aWeCtrl[i] ;
}
for ( int k = 1 ; k <= m_nDeg ; k ++) {
for ( int i = 0 ; i <= m_nDeg - k ; i ++) {
aPtCtrl[i] = ( 1 - dUTrim) * aWeCtrl[i] * aPtCtrl[i] + dUTrim * aWeCtrl[i+1] * aPtCtrl[i+1] ;
aWeCtrl[i] = ( 1 - dUTrim) * aWeCtrl[i] + dUTrim * aWeCtrl[i+1] ;
if ( aWeCtrl[i] < MIN_EXT_WEIGHT)
return false ;
aPtCtrl[i] = aPtCtrl[i] * ( 1 / aWeCtrl[i]) ;
}
}
for ( int i = 0 ; i <= m_nDeg ; i ++) {
m_aPtCtrl[i] = aPtCtrl[i] ;
m_aWeCtrl[i] = aWeCtrl[i] ;
}
}
// con i controlli sopra fatti rimane validata, ma la grafica va ricalcolata
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::ExtendEndByLen( double dLenExt)
{
// la lunghezza deve essere positiva
if ( dLenExt < - EPS_ZERO)
return false ;
// determino la lunghezza originale della curva
double dLen ;
if ( ! GetLength( dLen))
return false ;
// stimo il valore del parametro al nuovo punto finale
double dUTrim = 1 + dLenExt / dLen ;
// estrapolo sul parametro con de Casteljau
// se polinomiale, va sicuramente bene
if ( ! m_bRat) {
for ( int k = 1 ; k <= m_nDeg ; k ++) {
for ( int i = m_nDeg ; i >= k ; i --)
m_aPtCtrl[i] = ( 1 - dUTrim) * m_aPtCtrl[i-1] + dUTrim * m_aPtCtrl[ i] ;
}
}
// se razionale, devo verificare che i pesi non diventino negativi
else {
Point3d aPtCtrl[MAXDEG+1] ;
double aWeCtrl[MAXDEG+1] ;
for ( int i = 0 ; i <= m_nDeg ; i ++) {
aPtCtrl[i] = m_aPtCtrl[i] ;
aWeCtrl[i] = m_aWeCtrl[i] ;
}
for ( int k = 1 ; k <= m_nDeg ; k ++) {
for ( int i = m_nDeg ; i >= k ; i --) {
aPtCtrl[i] = ( 1 - dUTrim) * aWeCtrl[i-1] * aPtCtrl[i-1] + dUTrim * aWeCtrl[ i] * aPtCtrl[ i] ;
aWeCtrl[i] = ( 1 - dUTrim) * aWeCtrl[i-1] + dUTrim * aWeCtrl[ i] ;
if ( aWeCtrl[i] < MIN_EXT_WEIGHT)
return false ;
aPtCtrl[i] = aPtCtrl[i] * ( 1 / aWeCtrl[i]) ;
}
}
for ( int i = 0 ; i <= m_nDeg ; i ++) {
m_aPtCtrl[i] = aPtCtrl[i] ;
m_aWeCtrl[i] = aWeCtrl[i] ;
}
}
// con i controlli sopra fatti rimane validata, ma la grafica va ricalcolata
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Translate( const Vector3d& vtMove)
{
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// traslo i punti di controllo
for ( int i = 0 ; i <= m_nDeg ; ++ i)
m_aPtCtrl[i].Translate( vtMove) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, double dSinAng)
{
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico validità dell'asse di rotazione
if ( vtAx.IsSmall())
return false ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// ruoto i punti di controllo
for ( int i = 0 ; i <= m_nDeg ; ++ i)
m_aPtCtrl[i].Rotate( ptAx, vtAx, dCosAng, dSinAng) ;
// ruoto il vettore estrusione
m_VtExtr.Rotate( vtAx, dCosAng, dSinAng) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double dCoeffZ)
{
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico non sia nulla
if ( fabs( dCoeffX) < EPS_ZERO && fabs( dCoeffY) < EPS_ZERO && fabs( dCoeffZ) < EPS_ZERO)
return false ;
// verifico che la scalatura dei punti non li porti tutti a coincidere
PNTVECTOR vPnt ;
vPnt.reserve( m_nDeg + 1) ;
for ( int i = 0 ; i <= m_nDeg ; ++ i) {
Point3d ptTmp = m_aPtCtrl[i] ;
ptTmp.Scale( frRef, dCoeffX, dCoeffY, dCoeffZ) ;
vPnt.push_back( ptTmp) ;
}
bool bOk = false ;
for ( int i = 1 ; i <= m_nDeg ; ++ i) {
if ( ! AreSamePointApprox( vPnt[0], vPnt[i])) {
bOk = true ;
break ;
}
}
if ( ! bOk)
return false ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// scalo i punti di controllo
for ( int i = 0 ; i <= m_nDeg ; ++ i)
m_aPtCtrl[i] = vPnt[i] ;
// scalo vettore estrusione, lo normalizzo e aggiusto spessore
m_VtExtr.Scale( frRef, dCoeffX, dCoeffY, dCoeffZ) ;
double dLen = m_VtExtr.Len() ;
if ( dLen > EPS_ZERO) {
m_VtExtr /= dLen ;
m_dThick *= dLen ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Mirror( const Point3d& ptOn, const Vector3d& vtNorm)
{
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico validità del piano di specchiatura
if ( vtNorm.IsSmall())
return false ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// specchio i punti di controllo
for ( int i = 0 ; i <= m_nDeg ; ++ i)
m_aPtCtrl[i].Mirror( ptOn, vtNorm) ;
// specchio il vettore estrusione
m_VtExtr.Mirror( vtNorm) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Shear( const Point3d& ptOn, const Vector3d& vtNorm, const Vector3d& vtDir, double dCoeff)
{
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico validità dei parametri
if ( vtNorm.IsSmall() || vtDir.IsSmall())
return false ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// eseguo scorrimento dei punti di controllo
for ( int i = 0 ; i <= m_nDeg ; ++ i)
m_aPtCtrl[i].Shear( ptOn, vtNorm, vtDir, dCoeff) ;
// eseguo scorrimento del vettore estrusione, lo normalizzo e aggiusto spessore
m_VtExtr.Shear( vtNorm, vtDir, dCoeff) ;
double dLen = m_VtExtr.Len() ;
if ( dLen > EPS_ZERO) {
m_VtExtr /= dLen ;
m_dThick *= dLen ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::ToGlob( const Frame3d& frRef)
{
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// trasformo i punti di controllo
for ( int i = 0 ; i <= m_nDeg ; ++ i)
m_aPtCtrl[i].ToGlob( frRef) ;
// trasformo il vettore estrusione
m_VtExtr.ToGlob( frRef) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::ToLoc( const Frame3d& frRef)
{
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// trasformo i punti di controllo
for ( int i = 0 ; i <= m_nDeg ; ++ i)
m_aPtCtrl[i].ToLoc( frRef) ;
// trasformo il vettore estrusione
m_VtExtr.ToLoc( frRef) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::LocToLoc( const Frame3d& frOri, const Frame3d& frDest)
{
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico validità dei frame
if ( frOri.GetType() == Frame3d::ERR || frDest.GetType() == Frame3d::ERR)
return false ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// trasformo i punti di controllo
for ( int i = 0 ; i <= m_nDeg ; ++ i)
m_aPtCtrl[i].LocToLoc( frOri, frDest) ;
// trasformo il vettore estrusione
m_VtExtr.LocToLoc( frOri, frDest) ;
return true ;
}