99 "Cardinal" cubic cardinal splines, uses tension parameter which must be between [0,1]
1010 cubin cardinal splines can overshoot for non-monotonic data
1111 (increasing tension decreases overshoot)
12+ "Akima" monotonic - tangents are determined at each given point locally,
13+ the curve obtained is close to a manually drawn curve, can overshoot for non-monotonic data
1214 "FritschCarlson" monotonic - tangents are first initialized, then adjusted if they are not monotonic
1315 can overshoot for non-monotonic data
1416 "FritschButland" monotonic - faster algorithm (only requires one pass) but somewhat higher apparent "tension"
1517 "Steffen" monotonic - also only one pass, results usually between FritschCarlson and FritschButland
1618 Sources:
19+ Akima (1970), "A New Method of Interpolation and Smooth Curve Fitting Based on Local Procedures", doi:10.1145/321607.321609
1720 Fritsch & Carlson (1980), "Monotone Piecewise Cubic Interpolation", doi:10.1137/0717021.
1821 Fritsch & Butland (1984), "A Method for Constructing Local Monotone Piecewise Cubic Interpolants", doi:10.1137/0905021.
1922 Steffen (1990), "A Simple Method for Monotonic Interpolation in One Dimension", http://adsabs.harvard.edu/abs/1990A%26A...239..443S
2528 LinearMonotonicInterpolation,
2629 FiniteDifferenceMonotonicInterpolation,
2730 CardinalMonotonicInterpolation,
31+ AkimaMonotonicInterpolation,
2832 FritschCarlsonMonotonicInterpolation,
2933 FritschButlandMonotonicInterpolation,
3034 SteffenMonotonicInterpolation
@@ -64,6 +68,19 @@ struct CardinalMonotonicInterpolation{TTension<:Number} <: MonotonicInterpolatio
6468 tension :: TTension # must be in [0, 1]
6569end
6670
71+ """
72+ AkimaMonotonicInterpolation
73+
74+ Monotonic interpolation based on Akima (1970),
75+ "A New Method of Interpolation and Smooth Curve Fitting Based on Local Procedures",
76+ doi:10.1145/321607.321609.
77+
78+ Tagents are dertermined at each given point locally,
79+ results are close to manual drawn curves
80+ """
81+ struct AkimaMonotonicInterpolation <: MonotonicInterpolationType
82+ end
83+
6784"""
6885 FritschCarlsonMonotonicInterpolation
6986
@@ -161,7 +178,7 @@ function interpolate(::Type{TWeights}, ::Type{TCoeffs1},::Type{TCoeffs2},::Type{
161178 m, Δ = calcTangents (TCoeffs1, knots, A, it)
162179 c = Vector {TCoeffs2} (undef, n- 1 )
163180 d = Vector {TCoeffs3} (undef, n- 1 )
164- for k ∈ 1 : n - 1
181+ for k ∈ eachindex (c)
165182 if TInterpolationType == LinearMonotonicInterpolation
166183 c[k] = zero (TCoeffs2)
167184 d[k] = zero (TCoeffs3)
@@ -232,10 +249,9 @@ function calcTangents(::Type{TCoeffs}, x::AbstractVector{<:Number},
232249 n = length (x)
233250 Δ = Vector {TCoeffs} (undef, n- 1 )
234251 m = Vector {TCoeffs} (undef, n)
235- for k in 1 : n- 1
236- Δk = (y[k+ 1 ] - y[k]) / (x[k+ 1 ] - x[k])
237- Δ[k] = Δk
238- m[k] = Δk
252+ for k ∈ eachindex (Δ)
253+ Δ[k] = (y[k+ 1 ] - y[k]) / (x[k+ 1 ] - x[k])
254+ m[k] = Δ[k]
239255 end
240256 m[n] = Δ[n- 1 ]
241257 return (m, Δ)
@@ -247,13 +263,12 @@ function calcTangents(::Type{TCoeffs}, x::AbstractVector{<:Number},
247263 n = length (x)
248264 Δ = Vector {TCoeffs} (undef, n- 1 )
249265 m = Vector {TCoeffs} (undef, n)
250- for k in 1 : n- 1
251- Δk = (y[k+ 1 ] - y[k]) / (x[k+ 1 ] - x[k])
252- Δ[k] = Δk
266+ for k ∈ eachindex (Δ)
267+ Δ[k] = (y[k+ 1 ] - y[k]) / (x[k+ 1 ] - x[k])
253268 if k == 1 # left endpoint
254- m[k] = Δk
269+ m[k] = Δ[k]
255270 else
256- m[k] = (Δ[k- 1 ] + Δk ) / 2
271+ m[k] = (Δ[k- 1 ] + Δ[k] ) / 2
257272 end
258273 end
259274 m[n] = Δ[n- 1 ]
@@ -266,11 +281,10 @@ function calcTangents(::Type{TCoeffs}, x::AbstractVector{<:Number},
266281 n = length (x)
267282 Δ = Vector {TCoeffs} (undef, n- 1 )
268283 m = Vector {TCoeffs} (undef, n)
269- for k in 1 : n- 1
270- Δk = (y[k+ 1 ] - y[k]) / (x[k+ 1 ] - x[k])
271- Δ[k] = Δk
284+ for k ∈ eachindex (Δ)
285+ Δ[k] = (y[k+ 1 ] - y[k]) / (x[k+ 1 ] - x[k])
272286 if k == 1 # left endpoint
273- m[k] = Δk
287+ m[k] = Δ[k]
274288 else
275289 m[k] = (oneunit (TTension) - method. tension) * (y[k+ 1 ] - y[k- 1 ]) / (x[k+ 1 ] - x[k- 1 ])
276290 end
@@ -279,25 +293,50 @@ function calcTangents(::Type{TCoeffs}, x::AbstractVector{<:Number},
279293 return (m, Δ)
280294end
281295
296+ function calcTangents (:: Type{TCoeffs} , x:: AbstractVector{<:Number} ,
297+ y:: AbstractVector{TEl} , method:: AkimaMonotonicInterpolation ) where {TCoeffs, TEl}
298+
299+ # based on Akima (1970),
300+ # "A New Method of Interpolation and Smooth Curve Fitting Based on Local Procedures",
301+ # doi:10.1145/321607.321609.
302+
303+ n = length (x)
304+ Δ = Vector {TCoeffs} (undef, n- 1 )
305+ m = Vector {TCoeffs} (undef, n)
306+ for k ∈ eachindex (Δ)
307+ Δ[k] = (y[k+ 1 ] - y[k]) / (x[k+ 1 ] - x[k])
308+ end
309+ Γ = [3 Δ[1 ] - 2 Δ[2 ]; 2 Δ[1 ] - Δ[2 ]; Δ; 2 Δ[n- 1 ] - Δ[n- 2 ]; 3 Δ[n- 1 ] - 2 Δ[n- 2 ]]
310+ for k ∈ eachindex (m)
311+ δ = abs (Γ[k+ 3 ] - Γ[k+ 2 ]) + abs (Γ[k+ 1 ] - Γ[k])
312+ if δ > zero (δ)
313+ α = abs (Γ[k+ 1 ] - Γ[k]) / δ
314+ m[k] = (1 - α) * Γ[k+ 1 ] + α * Γ[k+ 2 ]
315+ else
316+ m[k] = 0.5 * Γ[k+ 1 ] + 0.5 * Γ[k+ 2 ]
317+ end
318+ end
319+ return (m, Δ)
320+ end
321+
282322function calcTangents (:: Type{TCoeffs} , x:: AbstractVector{<:Number} ,
283323 y:: AbstractVector{TEl} , method:: FritschCarlsonMonotonicInterpolation ) where {TCoeffs, TEl}
284324
285325 n = length (x)
286326 Δ = Vector {TCoeffs} (undef, n- 1 )
287327 m = Vector {TCoeffs} (undef, n)
288328 buff = Vector {typeof(first(Δ)^2)} (undef, n)
289- for k in 1 : n- 1
290- Δk = (y[k+ 1 ] - y[k]) / (x[k+ 1 ] - x[k])
291- Δ[k] = Δk
329+ for k ∈ eachindex (Δ)
330+ Δ[k] = (y[k+ 1 ] - y[k]) / (x[k+ 1 ] - x[k])
292331 if k == 1 # left endpoint
293- m[k] = Δk
332+ m[k] = Δ[k]
294333 else
295334 # If any consecutive secant lines change sign (i.e. curve changes direction), initialize the tangent to zero.
296335 # This is needed to make the interpolation monotonic. Otherwise set tangent to the average of the secants.
297- if Δ[k- 1 ] * Δk <= zero (Δk ^ 2 )
336+ if Δ[k- 1 ] * Δ[k] <= zero (Δ[k] ^ 2 )
298337 m[k] = zero (TCoeffs)
299338 else
300- m[k] = (Δ[k- 1 ] + Δk ) / 2.0
339+ m[k] = (Δ[k- 1 ] + Δ[k] ) / 2.0
301340 end
302341 end
303342 end
@@ -312,19 +351,18 @@ function calcTangents(::Type{TCoeffs}, x::AbstractVector{<:Number},
312351 =#
313352
314353 # Second pass of FritschCarlson: adjust any non-monotonic tangents.
315- for k in 1 : n- 1
316- Δk = Δ[k]
317- if Δk == zero (TCoeffs)
354+ for k ∈ eachindex (Δ)
355+ if Δ[k] == zero (TCoeffs)
318356 m[k] = zero (TCoeffs)
319357 m[k+ 1 ] = zero (TCoeffs)
320358 continue
321359 end
322- α = m[k] / Δk
323- β = m[k+ 1 ] / Δk
360+ α = m[k] / Δ[k]
361+ β = m[k+ 1 ] / Δ[k]
324362 τ = 3.0 * oneunit (α) / sqrt (α^ 2 + β^ 2 )
325363 if τ < 1.0 # if we're outside the circle with radius 3 then move onto the circle
326- m[k] = τ * α * Δk
327- m[k+ 1 ] = τ * β * Δk
364+ m[k] = τ * α * Δ[k]
365+ m[k+ 1 ] = τ * β * Δ[k]
328366 end
329367 end
330368 return (m, Δ)
@@ -340,16 +378,15 @@ function calcTangents(::Type{TCoeffs}, x::AbstractVector{<:Number},
340378 n = length (x)
341379 Δ = Vector {TCoeffs} (undef, n- 1 )
342380 m = Vector {TCoeffs} (undef, n)
343- for k in 1 : n- 1
344- Δk = (y[k+ 1 ] - y[k]) / (x[k+ 1 ] - x[k])
345- Δ[k] = Δk
381+ for k ∈ eachindex (Δ)
382+ Δ[k] = (y[k+ 1 ] - y[k]) / (x[k+ 1 ] - x[k])
346383 if k == 1 # left endpoint
347- m[k] = Δk
348- elseif Δ[k- 1 ] * Δk <= zero (Δk ^ 2 )
384+ m[k] = Δ[k]
385+ elseif Δ[k- 1 ] * Δ[k] <= zero (Δ[k] ^ 2 )
349386 m[k] = zero (TCoeffs)
350387 else
351388 α = (1.0 + (x[k+ 1 ] - x[k]) / (x[k+ 1 ] - x[k- 1 ])) / 3.0
352- m[k] = Δ[k- 1 ] * Δk / (α* Δk + (1.0 - α)* Δ[k- 1 ])
389+ m[k] = Δ[k- 1 ] * Δ[k] / (α* Δ[k] + (1.0 - α)* Δ[k- 1 ])
353390 end
354391 end
355392 m[n] = Δ[n- 1 ]
@@ -366,15 +403,14 @@ function calcTangents(::Type{TCoeffs}, x::AbstractVector{<:Number},
366403 n = length (x)
367404 Δ = Vector {TCoeffs} (undef, n- 1 )
368405 m = Vector {TCoeffs} (undef, n)
369- for k in 1 : n- 1
370- Δk = (y[k+ 1 ] - y[k]) / (x[k+ 1 ] - x[k])
371- Δ[k] = Δk
406+ for k ∈ eachindex (Δ)
407+ Δ[k] = (y[k+ 1 ] - y[k]) / (x[k+ 1 ] - x[k])
372408 if k == 1 # left endpoint
373- m[k] = Δk
409+ m[k] = Δ[k]
374410 else
375- p = ((x[k+ 1 ] - x[k]) * Δ[k- 1 ] + (x[k] - x[k- 1 ]) * Δk ) / (x[k+ 1 ] - x[k- 1 ])
376- m[k] = (sign (Δ[k- 1 ]) + sign (Δk )) *
377- min (abs (Δ[k- 1 ]), abs (Δk ), 0.5 * abs (p))
411+ p = ((x[k+ 1 ] - x[k]) * Δ[k- 1 ] + (x[k] - x[k- 1 ]) * Δ[k] ) / (x[k+ 1 ] - x[k- 1 ])
412+ m[k] = (sign (Δ[k- 1 ]) + sign (Δ[k] )) *
413+ min (abs (Δ[k- 1 ]), abs (Δ[k] ), 0.5 * abs (p))
378414 end
379415 end
380416 m[n] = Δ[n- 1 ]
0 commit comments