7cdc1ba5a3
- implementazione dell'approsimazione tramite curve di bezier.
186 lines
7.3 KiB
C
186 lines
7.3 KiB
C
//----------------------------------------------------------------------------
|
|
// EgalTech 2014-2014
|
|
//----------------------------------------------------------------------------
|
|
// File : CalcDerivate.h Data : 05.08.14 Versione : 1.5h1
|
|
// Contenuto : Funzioni per calcolo derivate secondo Bessel e Akima.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 05.08.14 DS Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#pragma once
|
|
|
|
#include "/EgtDev/Include/EGkPoint3d.h"
|
|
#include "/EgtDev/Include/EgtNumCollection.h"
|
|
#include "/EgtDev/Include/EGkGeoCollection.h"
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
CalcBesselStartDer( double dU0, const Point3d& ptP0, double dU1, const Point3d& ptP1,
|
|
double dU2, const Point3d& ptP2, Vector3d& vtDer)
|
|
{
|
|
// verifico che i parametri siano in ordine ascendente
|
|
if ( dU0 > dU1 - EPS_PARAM || dU1 > dU2 - EPS_PARAM)
|
|
return false ;
|
|
// calcolo la derivata
|
|
double dD0 = dU1 - dU0 ;
|
|
double dD1 = dU2 - dU1 ;
|
|
double dD01 = dU2 - dU0 ;
|
|
vtDer = ( 2 * dD0 + dD1) / ( dD0 * dD01) * ( ptP1 - ptP0) - dD0 / ( dD01 * dD1) * ( ptP2 - ptP1) ;
|
|
return ( ! vtDer.IsZero()) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
CalcBesselMidDer( double dU0, const Point3d& ptP0, double dU1, const Point3d& ptP1,
|
|
double dU2, const Point3d& ptP2, Vector3d& vtDer)
|
|
{
|
|
// verifico che i parametri siano in ordine ascendente
|
|
if ( dU0 > dU1 - EPS_PARAM || dU1 > dU2 - EPS_PARAM)
|
|
return false ;
|
|
// calcolo la derivata
|
|
double dD0 = dU1 - dU0 ;
|
|
double dD1 = dU2 - dU1 ;
|
|
double dD01 = dU2 - dU0 ;
|
|
vtDer = dD1 / ( dD0 * dD01) * ( ptP1 - ptP0) + dD0 / ( dD01 * dD1) * ( ptP2 - ptP1) ;
|
|
return ( ! vtDer.IsZero()) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
CalcBesselEndDer( double dU0, const Point3d& ptP0, double dU1, const Point3d& ptP1,
|
|
double dU2, const Point3d& ptP2, Vector3d& vtDer)
|
|
{
|
|
// verifico che i parametri siano in ordine ascendente
|
|
if ( dU0 > dU1 - EPS_PARAM || dU1 > dU2 - EPS_PARAM)
|
|
return false ;
|
|
// calcolo la derivata
|
|
double dD0 = dU1 - dU0 ;
|
|
double dD1 = dU2 - dU1 ;
|
|
double dD01 = dU2 - dU0 ;
|
|
vtDer = - dD1 / ( dD0 * dD01) * ( ptP1 - ptP0) + ( dD0 + 2 * dD1) / ( dD01 * dD1) * ( ptP2 - ptP1) ;
|
|
return ( ! vtDer.IsZero()) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
CalcCircleStartDer( double dU0, const Point3d& ptP0, double dU1, const Point3d& ptP1,
|
|
double dU2, const Point3d& ptP2, Vector3d& vtDer)
|
|
{
|
|
// verifico che i parametri siano in ordine ascendente
|
|
if ( dU0 > dU1 - EPS_PARAM || dU1 > dU2 - EPS_PARAM)
|
|
return false ;
|
|
// vettori dal primo punto agli altri due
|
|
Vector3d vtA = ptP1 - ptP0 ;
|
|
Vector3d vtB = ptP2 - ptP0 ;
|
|
// calcolo del versore normale
|
|
Vector3d vtN = vtA ^ vtB ;
|
|
double dNSqLen = vtN.SqLen() ;
|
|
// se i punti sono allineati calcolo con Bessel
|
|
if ( ! vtN.Normalize( EPS_ZERO))
|
|
return CalcBesselStartDer( dU0, ptP0, dU1, ptP1, dU2, ptP2, vtDer) ;
|
|
// calcolo del centro
|
|
Point3d ptCen = ptP0 + ( vtB.SqLen() * ( vtA.SqLen() - vtA * vtB) * vtA +
|
|
vtA.SqLen() * ( vtB.SqLen() - vtA * vtB) * vtB) / ( 2 * dNSqLen) ;
|
|
// calcolo la derivata
|
|
vtDer = ptP0 - ptCen ;
|
|
vtDer.Rotate( vtN, 0, 1) ;
|
|
if ( ( vtDer * vtA) < 0)
|
|
vtDer.Invert() ;
|
|
// ne aggiusto il modulo
|
|
if ( ! vtDer.Normalize())
|
|
return false ;
|
|
vtDer *= Dist( ptP0, ptP1) / ( dU1 - dU0) ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
CalcCircleEndDer( double dU0, const Point3d& ptP0, double dU1, const Point3d& ptP1,
|
|
double dU2, const Point3d& ptP2, Vector3d& vtDer)
|
|
{
|
|
// verifico che i parametri siano in ordine ascendente
|
|
if ( dU0 > dU1 - EPS_PARAM || dU1 > dU2 - EPS_PARAM)
|
|
return false ;
|
|
// vettori dal primo punto agli altri due
|
|
Vector3d vtA = ptP1 - ptP0 ;
|
|
Vector3d vtB = ptP2 - ptP0 ;
|
|
// calcolo del versore normale
|
|
Vector3d vtN = vtA ^ vtB ;
|
|
double dNSqLen = vtN.SqLen() ;
|
|
// se i punti sono allineati calcolo con Bessel
|
|
if ( ! vtN.Normalize( EPS_ZERO))
|
|
return CalcBesselEndDer( dU0, ptP0, dU1, ptP1, dU2, ptP2, vtDer) ;
|
|
// calcolo del centro
|
|
Point3d ptCen = ptP0 + ( vtB.SqLen() * ( vtA.SqLen() - vtA * vtB) * vtA +
|
|
vtA.SqLen() * ( vtB.SqLen() - vtA * vtB) * vtB) / ( 2 * dNSqLen) ;
|
|
// calcolo la derivata
|
|
vtDer = ptP2 - ptCen ;
|
|
vtDer.Rotate( vtN, 0, 1) ;
|
|
if ( ( vtDer * ( ptP2 - ptP1)) < 0)
|
|
vtDer.Invert() ;
|
|
// ne aggiusto il modulo
|
|
if ( ! vtDer.Normalize())
|
|
return false ;
|
|
vtDer *= Dist( ptP1, ptP2) / ( dU2 - dU1) ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
CalcCircleMidDer( double dU0, const Point3d& ptP0, double dU1, const Point3d& ptP1,
|
|
double dU2, const Point3d& ptP2, Vector3d& vtDer)
|
|
{
|
|
// la derivata Bessel coincide con la derivata circolare sul punto in mezzo
|
|
return CalcBesselMidDer( dU0, ptP0, dU1, ptP1, dU2, ptP2, vtDer) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
CalcAkimaMidDer( double dU0, const Point3d& ptP0, double dU1, const Point3d& ptP1,
|
|
double dU2, const Point3d& ptP2, double dU3, const Point3d& ptP3,
|
|
double dU4, const Point3d& ptP4, bool bDetectCorner,
|
|
Vector3d& vtPrevDer, Vector3d& vtNextDer)
|
|
{
|
|
// verifico che i parametri siano in ordine crescente
|
|
if ( dU0 > dU1 - EPS_PARAM || dU1 > dU2 - EPS_PARAM ||
|
|
dU2 > dU3 - EPS_PARAM || dU3 > dU4 - EPS_PARAM)
|
|
return false ;
|
|
// calcolo la derivata
|
|
Vector3d vtV0 = ( ptP1 - ptP0) / ( dU1 - dU0) ;
|
|
Vector3d vtV1 = ( ptP2 - ptP1) / ( dU2 - dU1) ;
|
|
Vector3d vtV2 = ( ptP3 - ptP2) / ( dU3 - dU2) ;
|
|
Vector3d vtV3 = ( ptP4 - ptP3) / ( dU4 - dU3) ;
|
|
Vector3d vtPV1 = vtV0 ^ vtV1 ;
|
|
Vector3d vtPV3 = vtV2 ^ vtV3 ;
|
|
double dPV1 = vtPV1.Len() ;
|
|
double dPV3 = vtPV3.Len() ;
|
|
if ( ( dPV1 + dPV3) > EPS_SMALL && ( vtV1 * vtV2) > 0.5) {
|
|
if ( ! bDetectCorner || ( ( vtV0 * vtV1) > 0 && ( vtV2 * vtV3) > 0)) {
|
|
double dA = dPV1 / ( dPV1 + dPV3) ;
|
|
vtPrevDer = ( 1 - dA) * vtV1 + dA * vtV2 ;
|
|
}
|
|
else {
|
|
CalcCircleMidDer( dU1, ptP1, dU2, ptP2, dU3, ptP3, vtPrevDer) ;
|
|
}
|
|
vtNextDer = vtPrevDer ;
|
|
}
|
|
else {
|
|
if ( bDetectCorner) {
|
|
CalcCircleEndDer( dU0, ptP0, dU1, ptP1, dU2, ptP2, vtPrevDer) ;
|
|
CalcCircleStartDer( dU2, ptP2, dU3, ptP3, dU4, ptP4, vtNextDer) ;
|
|
}
|
|
else {
|
|
vtPrevDer = 0.5 * ( vtV1 + vtV2) ;
|
|
vtNextDer = vtPrevDer ;
|
|
}
|
|
}
|
|
return ( ! vtPrevDer.IsZero() && ! vtNextDer.IsZero()) ;
|
|
}
|
|
|
|
bool ComputeAkimaTangents( bool bDetectCorner, const DBLVECTOR& vPar, const PNTVECTOR& vPnt, VCT3DVECTOR& vPrevDer, VCT3DVECTOR& vNextDer) ;
|
|
bool ComputeBesselTangents( const DBLVECTOR& vPar, const PNTVECTOR& vPnt, VCT3DVECTOR& vPrevDer, VCT3DVECTOR& vNextDer) ; |