@@ -56,64 +56,65 @@ namespace Splines {
5656
5757 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5858
59- static
60- real_type
61- akima_one (
62- real_type const epsi,
63- real_type const di_m2,
64- real_type const di_m1,
65- real_type const di,
66- real_type const di_p1
67- ) {
68- real_type wl { abs (di_p1 - di) };
69- real_type wr { abs (di_m1 - di_m2) };
70- real_type den { wl + wr };
71- if ( den <= epsi ) { wl = wr = 0.5 ; den = 1 ; } // if epsi == 0
72- real_type const num{ wl * di_m1 + wr * di };
73- return num / den;
74- }
75-
76- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
77-
7859 void
7960 Akima_build (
8061 real_type const X[],
8162 real_type const Y[],
8263 real_type Yp[],
83- integer const npts
64+ real_type m[], // work vector dimension N
65+ integer N
8466 ) {
85-
86- UTILS_ASSERT ( npts >= 2 , " Akima_build require at least 2 points" );
8767
88- if ( npts == 2 ) { // solo 2 punti, niente da fare
68+ UTILS_ASSERT ( N >= 2 , " Akima_build require at least 2 points" );
69+
70+ if ( N == 2 ) { // solo 2 punti, niente da fare
8971 Yp[0 ] = Yp[1 ] = (Y[1 ]-Y[0 ])/(X[1 ]-X[0 ]);
90- } else {
91- Malloc_real mem (" Akima_build" );
92- real_type * m{ mem.malloc ( npts+3 ) };
93-
94- // calcolo slopes (npts-1) intervals + 4
95- for ( integer i{1 }; i < npts; ++i )
96- m[i+1 ] = (Y[i]-Y[i-1 ])/(X[i]-X[i-1 ]);
97-
98- // extra slope at the boundary
99- m[1 ] = 2 *m[2 ]-m[3 ];
100- m[0 ] = 2 *m[1 ]-m[2 ];
101- m[npts+1 ] = 2 *m[npts]-m[npts-1 ];
102- m[npts+2 ] = 2 *m[npts+1 ]-m[npts];
103-
104- // minimum delta slope
105- real_type epsi{0 };
106- for ( integer i{0 }; i < npts+2 ; ++i ) {
107- real_type const dm{ std::abs (m[i+1 ]-m[i]) };
108- if ( dm > epsi ) epsi = dm;
109- }
110- epsi *= 1E-8 ;
72+ return ;
73+ }
74+
75+ // 1. Calcola le pendenze m_i = (Y[i+1] - Y[i]) / (X[i+1] - X[i])
76+ for ( integer i{0 }; i < N-1 ; ++i ) {
77+ UTILS_ASSERT (
78+ X[i+1 ] > X[i],
79+ " Akima_build, X must be strictly increasing X[{}] = {}, X[{}] = {}" ,
80+ i, X[i], i+1 , X[i+1 ]
81+ );
82+ m[i] = (Y[i+1 ] - Y[i]) / (X[i+1 ] - X[i]);
83+ }
11184
112- // 0 1 2 3 4---- n-1 n n+1 n+2
113- // + + + + +
114- for ( integer i{0 }; i < npts; ++i )
115- Yp[i] = akima_one ( epsi, m[i], m[i+1 ], m[i+2 ], m[i+3 ] );
85+ // 2. Calcolo epsi
86+ real_type epsi{0 };
87+ for ( integer i{0 }; i < N-2 ; ++i ) {
88+ real_type const dm{ std::abs (m[i+1 ]-m[i]) };
89+ if ( dm > epsi ) epsi = dm;
90+ }
91+ epsi *= 1E-8 ;
92+
93+ // 3. Calcola le derivate nei punti interni (i = 1..N-2)
94+ for ( integer i{1 }; i < N-1 ; ++i ) {
95+ // Estrapola le pendenze se necessario (ai bordi)
96+ real_type const m_im2 { (i >= 2 ) ? m[i-2 ] : 2 *m[i-1 ] - m[i] }; // m_{i-2}
97+ real_type const m_im1 { m[i-1 ] }; // m_{i-1}
98+ real_type const m_i { m[i] }; // m_i
99+ real_type const m_ip1 { (i < N-2 ) ? m[i+1 ] : 2 *m[i] - m[i-1 ] }; // m_{i+1}
100+
101+ // Pesatura di Akima (come in MATLAB makima)
102+ // https://blogs.mathworks.com/cleve/2019/04/29/makima-piecewise-cubic-interpolation/#d9a97978-0b09-4a1f-a6a5-504d088631d0
103+ real_type const w_left { std::abs ( m_ip1 - m_i ) + std::abs ( m_ip1 + m_i ) / 2 };
104+ real_type const w_right { std::abs ( m_im1 - m_im2 ) + std::abs ( m_im1 + m_im2 ) / 2 };
105+ real_type const sum_w { w_left + w_right };
106+
107+ if ( sum_w > epsi ) {
108+ Yp[i] = (w_right * m_im1 + w_left * m_i) / sum_w;
109+ } else {
110+ Yp[i] = 0.5 *(m_im1 + m_i); // Caso speciale
111+ }
116112 }
113+
114+ // 4. Derivate ai bordi (i=0 e i=N-1)
115+ // Estrapolazione quadratica
116+ Yp[0 ] = m[0 ] + (m[0 ] - m[1 ]) * (X[0 ] - X[1 ]) / (X[2 ] - X[0 ]);
117+ Yp[N-1 ] = m[N-2 ] + (m[N-2 ] - m[N-3 ]) * (X[N-1 ] - X[N-2 ]) / (X[N-1 ] - X[N-3 ]);
117118 }
118119
119120 #endif
@@ -128,10 +129,14 @@ namespace Splines {
128129 Utils::check_NaN ( m_Y, msg+" Y " , m_npts, __LINE__, __FILE__ );
129130 integer ibegin{0 };
130131 integer iend{0 };
132+
133+ Malloc_real m_mem (" AkimaSpline::work memory" );
134+ real_type * m_work{ m_mem.malloc ( m_npts ) };
135+
131136 do {
132137 // cerca intervallo monotono strettamente crescente
133138 while ( ++iend < m_npts && m_X[iend-1 ] < m_X[iend] ) {}
134- Akima_build ( m_X+ibegin, m_Y+ibegin, m_Yp+ibegin, iend-ibegin );
139+ Akima_build ( m_X+ibegin, m_Y+ibegin, m_Yp+ibegin, m_work, iend-ibegin );
135140 ibegin = iend;
136141 } while ( iend < m_npts );
137142
0 commit comments