1pub struct Spline{
3 x: Vec<f64>,
6
7 coefficients: Vec<(f64, f64, f64, f64)>
10}
11
12impl Spline{
13 pub fn from_vec(points: Vec<(f64, f64)>)->Spline{
32 assert!(points.len() > 1, "Only one point. No Interpolation possible");
33 let mut points = points;
34 points.sort_by(|(x0, _), (x1, _)| x0.partial_cmp(x1).unwrap());
35 let mut m = Vec::<f64>::with_capacity(points.len()+3);
37 for i in 0..points.len()-1{
38 m.push((points[i+1].1 - points[i].1)/(points[i+1].0-points[i].0));
39 }
40 if m.len() == 1{
41 let p1 = points[0];
43 let p2 = points[1];
44 let coefficients = vec![(p1.1, m[0], 0., 0.)];
45 return Spline{x: vec![p1.0, p2.0], coefficients}
46 }
47 m.insert(0, 2.0*m[0]-m[1]);
49 m.insert(0, 2.0*m[0]-m[1]);
50 m.push(2.0*m[m.len()-1]-m[m.len()-2]);
52 m.push(2.0*m[m.len()-1]-m[m.len()-2]);
53 let m = m; let mut t= Vec::<f64>::with_capacity(points.len()-1);
57 for i in 0..points.len(){
58 let i = i + 2; let w1 = (m[i+1]-m[i]).abs() + (m[i+1]+m[i]).abs()/2.;
60 let w2 = (m[i-1]-m[i-2]).abs() + (m[i-1]+m[i-2]).abs()/2.;
61 let nominator = w1*m[i-1] + w2*m[i];
62 if nominator == 0.0{
63 t.push(0.0)
64 }else{
65 t.push(nominator/(w1+w2))
66 }
67
68 }
69 let t = t; let mut coefficients = Vec::<(f64, f64, f64, f64)>::with_capacity(points.len()-1);
73 for i in 0..points.len()-1{
74 let (xi, yi) = points[i];
75 let (xi1, _) = points[i+1];
76 let z = xi1-xi;
77 let a = yi;
78 let b = t[i];
79 let c = (3.*m[i+2] - 2.*t[i]-t[i+1])/z;
80 let d = (t[i]+t[i+1] - 2.*m[i+2])/z.powi(2);
81 coefficients.push((a, b, c, d));
82 }
83
84 let x = points.iter().map(|p|{
86 p.0
87 }).collect();
88 Spline{x, coefficients}
89 }
90
91 fn segment(&self, pos: f64) -> (f64, f64, f64, f64, f64){
95 if pos <= self.x[0]{
96 let (a, b, _, _) = self.coefficients[0];
98 let xi = self.x[0];
99 return (a, b, 0.0, 0.0, xi);
100 }
101 if pos >= self.x[self.x.len()-1]{
102 let (a, b, c, d) = self.coefficients[self.coefficients.len()-1];
104 let xi = self.x[self.x.len()-2];
105 let xi1 = self.x[self.x.len()-1];
106 let dx = xi1-xi;
107 let y1 = a + b*dx + c*dx*dx + d*dx*dx*dx;
108 let m = b + 2.*c*dx + 3.*d*dx*dx;
109 return (y1, m, 0.0, 0.0, xi1);
110 }
111 let mut upper = self.x.len();
113 let mut lower = 0;
114 while upper-lower > 1{
115 let center = (upper+lower)/2;
116 if pos > self.x[center]{
117 lower = center;
118 }else{
119 upper = center;
120 }
121 }
122 let coef = self.coefficients[lower];
123 (coef.0, coef.1, coef.2, coef.3, self.x[lower])
124 }
125
126 pub fn sample(&self, pos: f64)-> f64{
137 let (a, b, c, d, xi) = self.segment(pos);
138
139 let dx = pos-xi;
140 a + b*dx + c*dx*dx + d*dx*dx*dx
141 }
142
143 pub fn derivative_1(&self, pos: f64) -> f64{
145 let (_, b, c, d, xi) = self.segment(pos);
146 let dx = pos-xi;
147 b + 2.*c*dx + 3.*d*dx*dx
148 }
149
150 pub fn derivative_2(&self, pos: f64) -> f64{
154 let (_, _, c, d, xi) = self.segment(pos);
155 let dx = pos-xi;
156 2.*c + 6.*d*dx
157 }
158
159 pub fn derivative_3(&self, pos: f64) -> f64{
163 let (_, _, _, d, _) = self.segment(pos);
164 6.0*d
165 }
166}
167
168pub fn vec_to_points(x: &Vec<f64>, y: &Vec<f64>) -> Vec<(f64, f64)>{
177 assert!(x.len() == y.len());
178 let mut points = Vec::<(f64, f64)>::with_capacity(x.len());
179 for i in 0..x.len(){
180 points.push((x[i], y[i]))
181 }
182 points
183}
184
185#[cfg(feature = "n_dimensional")]
186pub mod n_dimensional;
187
188mod tests;