7cdc1ba5a3
- implementazione dell'approsimazione tramite curve di bezier.
233 lines
8.5 KiB
C++
233 lines
8.5 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2026
|
|
//----------------------------------------------------------------------------
|
|
// File : CalcDerivate.cpp Data : 03.02.26 Versione : 1.5h1
|
|
// Contenuto : Funzioni per calcolo derivate secondo Bessel e Akima.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 03.02.26 DB Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#pragma once
|
|
|
|
#include "stdafx.h"
|
|
#include "CalcDerivate.h"
|
|
#include "/EgtDev/Include/EGkPoint3d.h"
|
|
#include "/EgtDev/Include/EgtNumCollection.h"
|
|
#include "/EgtDev/Include/EGkGeoCollection.h"
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
ComputeAkimaTangents( bool bDetectCorner, const DBLVECTOR& vPar, const PNTVECTOR& vPnt, VCT3DVECTOR& vPrevDer, VCT3DVECTOR& vNextDer)
|
|
{
|
|
// pulisco i vettori dei parametri e delle tangenti
|
|
vPrevDer.clear() ;
|
|
vNextDer.clear() ;
|
|
|
|
// numero di punti
|
|
int nSize = int( vPnt.size()) ;
|
|
|
|
// sono necessari almeno due punti
|
|
if ( nSize < 2)
|
|
return false ;
|
|
|
|
// calcolo le derivate
|
|
vPrevDer.reserve( nSize) ;
|
|
vNextDer.reserve( nSize) ;
|
|
// se ci sono solo 2 punti, le tangenti devono essere dirette lungo la linea che li unisce
|
|
if ( nSize == 2) {
|
|
// non esiste derivata prima del primo punto
|
|
vPrevDer.emplace_back( 0, 0, 0) ;
|
|
vNextDer.push_back( ( vPnt[1] - vPnt[0]) / ( vPar[1] - vPar[0])) ;
|
|
vPrevDer.push_back( vNextDer[0]) ;
|
|
// non esiste derivata dopo il secondo e ultimo punto
|
|
vNextDer.emplace_back( 0, 0, 0) ;
|
|
return true ;
|
|
}
|
|
// verifico se curva chiusa (primo e ultimo punto coincidono)
|
|
bool bClosed = AreSamePointApprox( vPnt.front(), vPnt.back()) ;
|
|
// calcolo le derivate
|
|
for ( int i = 0 ; i < nSize ; ++ i) {
|
|
Vector3d vtPrevDer ;
|
|
Vector3d vtNextDer ;
|
|
// primo punto
|
|
if ( i == 0) {
|
|
// se curva chiusa, come precedente uso il penultimo punto
|
|
if ( bClosed) {
|
|
// se non ci sono almeno 5 punti
|
|
if ( nSize < 5) {
|
|
if ( ! CalcCircleMidDer( vPar[nSize-2] - vPar[nSize-1], vPnt[nSize-2], vPar[i], vPnt[i],
|
|
vPar[i+1], vPnt[i+1], vtNextDer))
|
|
return false ;
|
|
vtPrevDer = vtNextDer ;
|
|
}
|
|
// altrimenti
|
|
else {
|
|
if ( ! CalcAkimaMidDer( vPar[nSize-3] - vPar[nSize-1], vPnt[nSize-3], vPar[nSize-2] - vPar[nSize-1], vPnt[nSize-2],
|
|
vPar[i], vPnt[i], vPar[i+1], vPnt[i+1],
|
|
vPar[i+2], vPnt[i+2], bDetectCorner,
|
|
vtPrevDer, vtNextDer))
|
|
return false ;
|
|
}
|
|
}
|
|
// altrimenti, uso arco sui primi tre punti
|
|
else {
|
|
if ( ! CalcCircleStartDer( vPar[i], vPnt[i], vPar[i+1], vPnt[i+1],
|
|
vPar[i+2], vPnt[i+2], vtNextDer))
|
|
return false ;
|
|
vtPrevDer = Vector3d( 0, 0, 0) ;
|
|
}
|
|
}
|
|
// ultimo punto
|
|
else if ( i == nSize - 1) {
|
|
// se curva chiusa, le tg devono coincidere con quelle del primo
|
|
if ( bClosed) {
|
|
vtPrevDer = vPrevDer[0] ;
|
|
vtNextDer = vNextDer[0] ;
|
|
}
|
|
// altrimenti, uso arco sugli ultimi tre punti
|
|
else {
|
|
if ( ! CalcCircleEndDer( vPar[i-2], vPnt[i-2], vPar[i-1], vPnt[i-1],
|
|
vPar[i], vPnt[i], vtPrevDer))
|
|
return false ;
|
|
vtNextDer = Vector3d( 0, 0, 0) ;
|
|
}
|
|
}
|
|
// punti intermedi
|
|
else {
|
|
// se secondo punto
|
|
if ( i == 1) {
|
|
// se curva aperta o non ci sono almeno 5 punti
|
|
if ( ! bClosed || nSize < 5) {
|
|
if ( ! CalcCircleMidDer( vPar[i-1], vPnt[i-1], vPar[i], vPnt[i],
|
|
vPar[i+1], vPnt[i+1], vtPrevDer))
|
|
return false ;
|
|
vtNextDer = vtPrevDer ;
|
|
}
|
|
// altrimenti
|
|
else {
|
|
if ( ! CalcAkimaMidDer( vPar[nSize-2] - vPar[nSize-1], vPnt[nSize-2], vPar[i-1], vPnt[i-1],
|
|
vPar[i], vPnt[i], vPar[i+1], vPnt[i+1],
|
|
vPar[i+2], vPnt[i+2], bDetectCorner,
|
|
vtPrevDer, vtNextDer))
|
|
return false ;
|
|
}
|
|
}
|
|
// se penultimo punto
|
|
else if ( i == nSize - 2) {
|
|
// se curva aperta o non ci sono almeno 5 punti
|
|
if ( ! bClosed || nSize < 5) {
|
|
if ( ! CalcCircleMidDer( vPar[i-1], vPnt[i-1], vPar[i], vPnt[i],
|
|
vPar[i+1], vPnt[i+1], vtPrevDer))
|
|
return false ;
|
|
vtNextDer = vtPrevDer ;
|
|
}
|
|
// altrimenti
|
|
else {
|
|
if ( ! CalcAkimaMidDer( vPar[i-2], vPnt[i-2], vPar[i-1], vPnt[i-1],
|
|
vPar[i], vPnt[i], vPar[i+1], vPnt[i+1],
|
|
vPar[1] + vPar[i+1], vPnt[1], bDetectCorner,
|
|
vtPrevDer, vtNextDer))
|
|
return false ;
|
|
}
|
|
}
|
|
// altrimenti
|
|
else {
|
|
if ( ! CalcAkimaMidDer( vPar[i-2], vPnt[i-2], vPar[i-1], vPnt[i-1],
|
|
vPar[i], vPnt[i], vPar[i+1], vPnt[i+1],
|
|
vPar[i+2], vPnt[i+2], bDetectCorner,
|
|
vtPrevDer, vtNextDer))
|
|
return false ;
|
|
}
|
|
}
|
|
// salvo la derivata
|
|
vPrevDer.push_back( vtPrevDer) ;
|
|
vNextDer.push_back( vtNextDer) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
ComputeBesselTangents( const DBLVECTOR& vPar, const PNTVECTOR& vPnt, VCT3DVECTOR& vPrevDer, VCT3DVECTOR& vNextDer)
|
|
{
|
|
// pulisco i vettori dei parametri e delle tangenti
|
|
vPrevDer.clear() ;
|
|
vNextDer.clear() ;
|
|
|
|
// numero di punti
|
|
int nSize = int( vPnt.size()) ;
|
|
|
|
// sono necessari almeno due punti
|
|
if ( nSize < 2)
|
|
return false ;
|
|
|
|
// calcolo le derivate
|
|
vPrevDer.reserve( nSize) ;
|
|
vNextDer.reserve( nSize) ;
|
|
// se ci sono solo 2 punti, le tangenti devono essere dirette lungo la linea che li unisce
|
|
if ( nSize == 2) {
|
|
// non esiste derivata prima del primo punto
|
|
vPrevDer.emplace_back( 0, 0, 0) ;
|
|
vNextDer.push_back( ( vPnt[1] - vPnt[0]) / ( vPar[1] - vPar[0])) ;
|
|
vPrevDer.push_back( vNextDer[0]) ;
|
|
// non esiste derivata dopo il secondo e ultimo punto
|
|
vNextDer.emplace_back( 0, 0, 0) ;
|
|
return true ;
|
|
}
|
|
// verifico se curva chiusa (primo e ultimo punto coincidono)
|
|
bool bClosed = AreSamePointApprox( vPnt.front(), vPnt.back()) ;
|
|
// calcolo le derivate
|
|
for ( int i = 0 ; i < nSize ; ++ i) {
|
|
Vector3d vtPrevDer ;
|
|
Vector3d vtNextDer ;
|
|
// primo punto
|
|
if ( i == 0) {
|
|
// se curva chiusa, come precedente uso il penultimo punto
|
|
if ( bClosed) {
|
|
if ( ! CalcBesselMidDer( vPar[nSize-2] - vPar[nSize-1], vPnt[nSize-2], vPar[i], vPnt[i],
|
|
vPar[i+1], vPnt[i+1], vtNextDer))
|
|
return false ;
|
|
vtPrevDer = vtNextDer ;
|
|
}
|
|
// altrimenti, uso i primi tre punti
|
|
else {
|
|
if ( ! CalcBesselStartDer( vPar[i], vPnt[i], vPar[i+1], vPnt[i+1],
|
|
vPar[i+2], vPnt[i+2], vtNextDer))
|
|
return false ;
|
|
vtPrevDer = Vector3d( 0, 0, 0) ;
|
|
}
|
|
}
|
|
// ultimo punto
|
|
else if ( i == nSize - 1) {
|
|
// se curva chiusa, le tg devono coincidere con quelle del primo
|
|
if ( bClosed) {
|
|
vtPrevDer = vPrevDer[0] ;
|
|
vtNextDer = vNextDer[0] ;
|
|
}
|
|
// altrimenti, uso gli ultimi tre punti
|
|
else {
|
|
if ( ! CalcBesselEndDer( vPar[i-2], vPnt[i-2], vPar[i-1], vPnt[i-1],
|
|
vPar[i], vPnt[i], vtPrevDer))
|
|
return false ;
|
|
vtNextDer = Vector3d( 0, 0, 0) ;
|
|
}
|
|
}
|
|
// punti intermedi
|
|
else {
|
|
if ( ! CalcBesselMidDer( vPar[i-1], vPnt[i-1], vPar[i], vPnt[i],
|
|
vPar[i+1], vPnt[i+1], vtPrevDer))
|
|
return false ;
|
|
vtNextDer = vtPrevDer ;
|
|
}
|
|
// salvo la derivata
|
|
vPrevDer.push_back( vtPrevDer) ;
|
|
vNextDer.push_back( vtNextDer) ;
|
|
}
|
|
|
|
return true ;
|
|
} |