Line data Source code
1 4425 : ev(h::AbstractHermiteSpline{S, V}, t::S, ::X, idx::Int) where {V, S<:Real, X} =
2 : interpolate(h, X(), boundedindex(h, t, idx), t)
3 :
4 5863 : ev(h::AbstractHermiteSpline{S, V}, t::S, ::X = Value) where {V, S<:Real, X} =
5 : first(ev(h, t, X(), 1))
6 :
7 :
8 2498 : function interpolate(hs::AbstractHermiteSpline{S, V},
9 : ::TValueDerivative, idx::Int, t::S) where {S, V}
10 2498 : t0, x0, dx0 = hs[idx]
11 2498 : t1, x1, dx1 = hs[idx + 1]
12 :
13 2498 : (t == t0) && return (x0, dx0), idx
14 2497 : (t == t1) && return (x1, dx1), idx
15 :
16 2478 : h = t1 - t0
17 2478 : t = (t - t0) / h
18 2478 : @assert isfinite(t)
19 :
20 2478 : cx0, cdx0, cx1, cdx1 = hermitebasis(t)
21 2478 : x = x0*cx0 + dx0*(cdx0*h) + x1*cx1 + dx1*(cdx1*h)
22 :
23 2478 : ex0, edx0, ex1, edx1 = hermitederivativebasis(t)
24 2478 : dx = x0*(ex0/h) + dx0*edx0 + x1*(ex1/h) + dx1*edx1
25 :
26 2478 : (x, dx), idx
27 : end
28 :
29 2810 : function interpolate(hs::AbstractHermiteSpline{S, V},
30 : ::TValue, idx::Int, t::S) where {S, V}
31 2810 : t0, x0, dx0 = hs[idx]
32 2810 : t1, x1, dx1 = hs[idx + 1]
33 :
34 2810 : (t == t0) && return x0, idx
35 2803 : (t == t1) && return x1, idx
36 :
37 2796 : h = t1 - t0
38 2796 : t = (t - t0) / h
39 2796 : @assert isfinite(t)
40 :
41 2796 : cx0, cdx0, cx1, cdx1 = hermitebasis(t)
42 2796 : x = x0*cx0 + dx0*(cdx0*h) + x1*cx1 + dx1*(cdx1*h)
43 :
44 2796 : x, idx
45 : end
46 :
47 9 : function ev(h::AbstractHermiteSpline{S, V},
48 : ts::StepRangeLen{S}, ::X = Value) where {S, V, X}
49 9 : idx::Int = 1
50 144 : function f(t::S)
51 276 : out, idx = interpolate(h, X(), boundedindex(h, t, idx), t)
52 138 : out
53 : end
54 6 : (f(t) for t in ts)
55 : end
56 :
57 3 : _resultype(::TValue, ::Type{V}) where {V} = V
58 3 : _resultype(::TValueDerivative, ::Type{V}) where {V} = Tuple{V, V}
59 :
60 45 : function ev(h::AbstractHermiteSpline{S, V}, ts::Vector{S}, ::X = Value;
61 : sorted::Bool = false) where {S, V, X}
62 17 : sorted && return ev(h, Val(:sorted), ts, X())
63 11 : issorted(ts, rev=!isascending(h)) && return ev(h, Val(:sorted), ts, X())
64 :
65 6 : n = length(ts)
66 12 : p = sortperm(ts, rev = !isascending(h))
67 :
68 12 : x = Vector{_resultype(X(), V)}(undef, n)
69 6 : idx::Int = 1
70 6 : @inbounds for (i, ip) in enumerate(p)
71 138 : t = ts[ip]
72 138 : x[ip], idx = interpolate(h, X(), boundedindex(h, t, idx), t)
73 270 : end
74 :
75 6 : x
76 : end
77 :
78 11 : function ev(h::AbstractHermiteSpline{S, V}, ::Val{:sorted}, ts::Vector{S},
79 : ::X) where {S, V, X}
80 11 : idx::Int = 1
81 618 : function f(t::S)
82 816 : out, idx = interpolate(h, X(), boundedindex(h, t, idx), t)
83 607 : out
84 : end
85 :
86 11 : [ f(t) for t in ts ]
87 : end
88 :
89 :
90 : """
91 : (x, dx), idx = ev(h, t, ValueDerivative, idx) # value and derivative
92 : x, dx = ev(h, t, ValueDerivative)
93 : x_dx = collect(ev(h, range(t0, t1, length=n))) # from generator
94 : x_dx = ev(h, ts::Vector, ValueDerivative[; issorted=false])
95 :
96 : x, idx = ev(h, t, Value, idx) # value only
97 : x = ev(h, t, Value)
98 : x = collect(ev(h, range(t0, t1, length=n))) # from generator
99 : x = ev(h, ts::Vector, Value[; issorted=false])
100 :
101 : Evaluate [`AbstractHermiteSpline`](@ref) `h(t)`, provide (possibly
102 : reused) knot interval index `idx` from previous evaluation. Compute
103 : value and derivative `(x, dx)` or only value `x`.
104 :
105 : The evaluation at parameters `ts` in a `Vector` is more efficient if
106 : `ts` is sorted (w.r.t [`isascending`](@ref)) due to use of caches and
107 : because the current [`index`](@ref) is stored for lookup. *However*,
108 : sorting `ts` exclusively for a single pass of evaluation may be more
109 : expensive than point-location tests for an unsorted `ts`.
110 :
111 : - If `sorted = false` is passed, the `ev` sorts enforces sorting `ts`
112 : before evaluation (if `ts` are not already sorted). The returned
113 : values apprear in the order of `ts` as for input (i.e., in addition
114 : to `sort!` there is an extra overhead for using `sortperm!` and
115 : applying the permutation).
116 : - If `sorted = true` is passed, `ev`
117 : evaluates at parameters `ts` without assumptions on order.
118 :
119 : !!! note
120 : Passing `sorted = true` is *not an assertion* that parameters `ts`
121 : are sorted but rather a hint that `ev` shall not perform any sorting.
122 :
123 : # Alternative syntax
124 :
125 : [`AbstractHermiteSpline`](@ref) `h` is a *callable object*, which delegates
126 : arguments to `ev(h, t, ...)`.
127 :
128 : output = h(t, ...) # output: see above
129 : x = h(t) # default: value only
130 :
131 : """ ev
132 :
133 : """
134 : Evaluate [`AbstractHermiteSpline`](@ref) `h(t)`, delegates arguments
135 : to [`ev`](@ref).
136 :
137 :
138 : See [`ev`](@ref)
139 : """
140 2294 : (h::AbstractHermiteSpline{S, V})(t::S, ::X, args...) where {S, V, X} =
141 : ev(h, t, X(), args...)
142 2131 : (h::AbstractHermiteSpline{S, V})(t::S) where {S, V} = ev(h, t)
143 : # (h::AbstractHermiteSpline{S, V})(t::S, args...) where {S, V} = ev(h, t, args...) # NOTE: THis is slow!?!
144 12 : (h::AbstractHermiteSpline{S, V})(t::Vector{S}, ::X; sorted::Bool = false) where {S, V, X} =
145 : ev(h, t, X(); sorted)
146 22 : (h::AbstractHermiteSpline{S, V})(t::Vector{S}; sorted::Bool = false) where {S, V} =
147 : ev(h, t; sorted)
148 3 : (h::AbstractHermiteSpline{S, V})(t::StepRangeLen{S}, ::X) where {S, V, X} =
149 : ev(h, t, X())
150 3 : (h::AbstractHermiteSpline{S, V})(t::StepRangeLen{S}) where {S, V} =
151 : ev(h, t)
|