1#![warn(missing_docs)]
7#![cfg_attr(not(feature = "std"), no_std)]
8extern crate alloc;
9use alloc::{vec, vec::Vec};
10use core::cmp::max;
11use core::ops::*;
12#[derive(Clone, Copy, Debug, Default, PartialEq)]
14pub struct PointXY {
15 pub x: f64,
17 pub y: f64,
19}
20impl PointXY {
21 #[inline]
23 pub fn new(x: f64, y: f64) -> Self {
24 Self { x, y }
25 }
26}
27pub fn newtons_method<F: Fn(f64) -> f64, D: Fn(f64) -> f64>(
34 function: F,
35 derivative: D,
36 y: f64,
37 x_guess: f64,
38 max_iterations: u16,
39) -> PointXY {
40 let mut x = x_guess;
41 for _ in 0..max_iterations {
42 let function_evaluation_minus_y = function(x) - y;
43 if function_evaluation_minus_y == 0.0 {
44 break;
45 }
46 x -= function_evaluation_minus_y / derivative(x);
47 }
48 PointXY::new(x, function(x))
49}
50#[derive(Clone, Debug, Default, PartialEq)]
52pub struct Polynomial {
53 coefficients: Vec<f64>,
54}
55impl Polynomial {
56 #[inline]
60 pub fn new(coefficients: Vec<f64>) -> Self {
61 let mut coefficients = coefficients;
62 while coefficients.last() == Some(&0.0) {
63 coefficients.pop();
64 }
65 Self { coefficients }
66 }
67 pub fn from_zeros(zeros: Vec<f64>) -> Self {
70 let mut new_self = Polynomial::new(vec![1.0]);
71 for x in zeros {
72 new_self = new_self * Polynomial::new(vec![-x, 1.0]);
73 }
74 new_self
75 }
76 pub fn interpolate(points: Vec<PointXY>) -> Self {
79 let mut zeroing_polynomials = Vec::with_capacity(points.len());
83 for i in 0..points.len() {
84 let mut new_zeros = Vec::with_capacity(i);
85 for j in 0..i {
86 new_zeros.push(points[j].x);
87 }
88 zeroing_polynomials.push(Self::from_zeros(new_zeros));
89 }
90 let mut coefficients = Vec::with_capacity(points.len());
99 for i in 0..points.len() {
100 let mut numerator = points[i].y;
101 for j in 0..i {
102 numerator -= zeroing_polynomials[j].evaluate(points[i].x).y * coefficients[j];
103 }
104 coefficients.push(numerator / zeroing_polynomials[i].evaluate(points[i].x).y);
105 }
106 let mut final_polynomial = Self::default();
109 for (i, zeroing_polynomial) in zeroing_polynomials.into_iter().enumerate() {
110 final_polynomial = final_polynomial + zeroing_polynomial * coefficients[i];
111 }
112 final_polynomial
113 }
114 pub fn evaluate(&self, x: f64) -> PointXY {
117 let mut y = 0.0;
118 let mut x_power = 1.0;
119 for coefficient in &self.coefficients {
120 y += coefficient * x_power;
121 x_power *= x;
122 }
123 PointXY::new(x, y)
124 }
125 pub fn derivative(&self) -> Polynomial {
127 let mut derivative_coefficients = Vec::with_capacity(self.coefficients.len() - 1);
128 for (i, coefficient) in self.coefficients.iter().enumerate().skip(1) {
129 derivative_coefficients.push(i as f64 * coefficient);
130 }
131 Self::new(derivative_coefficients)
132 }
133 pub fn integral(&self, c: f64) -> Polynomial {
136 let mut integral_coefficients = Vec::with_capacity(self.coefficients.len() + 1);
137 integral_coefficients.push(c);
138 for (i, coefficient) in self.coefficients.iter().enumerate() {
139 integral_coefficients.push(coefficient / (i + 1) as f64)
140 }
141 Polynomial::new(integral_coefficients)
142 }
143 pub fn newtons_method(&self, y: f64, x_guess: f64, max_iterations: u16) -> PointXY {
148 let derivative = self.derivative();
149 newtons_method(
150 |x| self.evaluate(x).y,
151 |x| derivative.evaluate(x).y,
152 y,
153 x_guess,
154 max_iterations,
155 )
156 }
157}
158impl From<f64> for Polynomial {
159 fn from(was: f64) -> Self {
160 Self::new(vec![was])
161 }
162}
163impl Neg for Polynomial {
164 type Output = Self;
165 fn neg(self) -> Self {
166 let mut coefficients = self.coefficients;
167 for coefficient in &mut coefficients {
168 *coefficient *= -1.0;
169 }
170 Self::new(coefficients)
171 }
172}
173impl Add for Polynomial {
174 type Output = Self;
175 fn add(self, rhs: Self) -> Self {
176 let mut new_coefficients = vec![0.0; max(self.coefficients.len(), rhs.coefficients.len())];
177 for (i, coefficient) in self.coefficients.iter().enumerate() {
178 new_coefficients[i] += coefficient;
179 }
180 for (i, coefficient) in rhs.coefficients.iter().enumerate() {
181 new_coefficients[i] += coefficient;
182 }
183 Self::new(new_coefficients)
184 }
185}
186impl Sub for Polynomial {
187 type Output = Self;
188 fn sub(self, rhs: Self) -> Self {
189 self + -rhs
190 }
191}
192impl Mul<f64> for Polynomial {
193 type Output = Self;
194 fn mul(self, rhs: f64) -> Self {
195 let mut coefficients = self.coefficients;
196 for coefficient in &mut coefficients {
197 *coefficient *= rhs;
198 }
199 Self::new(coefficients)
200 }
201}
202impl Div<f64> for Polynomial {
203 type Output = Self;
204 fn div(self, rhs: f64) -> Self {
205 let mut coefficients = self.coefficients;
206 for coefficient in &mut coefficients {
207 *coefficient /= rhs;
208 }
209 Self::new(coefficients)
210 }
211}
212impl Mul for Polynomial {
213 type Output = Self;
214 fn mul(self, rhs: Self) -> Self {
215 let mut coefficients = vec![0.0; self.coefficients.len() + rhs.coefficients.len() - 1];
216 for (my_exponent, my_coefficient) in self.coefficients.iter().enumerate() {
217 for (rhs_exponent, rhs_coefficient) in rhs.coefficients.iter().enumerate() {
218 coefficients[my_exponent + rhs_exponent] += my_coefficient * rhs_coefficient;
219 }
220 }
221 Polynomial::new(coefficients)
222 }
223}
224#[derive(Clone, Copy, Debug, Default, PartialEq)]
226pub struct PointXYT {
227 pub x: f64,
229 pub y: f64,
231 pub t: f64,
233}
234impl PointXYT {
235 #[inline]
237 pub fn new(x: f64, y: f64, t: f64) -> Self {
238 Self { x, y, t }
239 }
240 #[inline]
242 pub fn xy(&self) -> PointXY {
243 PointXY::new(self.x, self.y)
244 }
245 #[inline]
247 pub fn tx(&self) -> PointXY {
248 PointXY::new(self.t, self.x)
249 }
250 #[inline]
252 pub fn ty(&self) -> PointXY {
253 PointXY::new(self.t, self.y)
254 }
255}
256#[derive(Clone, Debug, PartialEq)]
258pub struct XYTCurve {
259 x_polynomial: Polynomial,
260 y_polynomial: Polynomial,
261}
262impl XYTCurve {
263 pub fn new(points: Vec<PointXYT>) -> Self {
266 let mut x_polynomial_points = Vec::with_capacity(points.len());
267 for point in &points {
268 x_polynomial_points.push(point.tx());
269 }
270 let mut y_polynomial_points = Vec::with_capacity(points.len());
271 for point in points {
272 y_polynomial_points.push(point.ty());
273 }
274 Self {
275 x_polynomial: Polynomial::interpolate(x_polynomial_points),
276 y_polynomial: Polynomial::interpolate(y_polynomial_points),
277 }
278 }
279 #[inline]
281 pub fn evaluate(&self, t: f64) -> PointXYT {
282 PointXYT::new(
283 self.x_polynomial.evaluate(t).y,
284 self.y_polynomial.evaluate(t).y,
285 t,
286 )
287 }
288 #[inline]
291 pub fn derivative(&self) -> Self {
292 Self {
293 x_polynomial: self.x_polynomial.derivative(),
294 y_polynomial: self.y_polynomial.derivative(),
295 }
296 }
297 pub fn newtons_method_x(&self, x: f64, t_guess: f64, max_iterations: u16) -> PointXYT {
302 let newton_output = self.x_polynomial.newtons_method(x, t_guess, max_iterations);
303 let x = newton_output.y;
304 let t = newton_output.x;
305 let y = self.y_polynomial.evaluate(t).y;
306 PointXYT::new(x, y, t)
307 }
308 pub fn newtons_method_y(&self, y: f64, t_guess: f64, max_iterations: u16) -> PointXYT {
313 let newton_output = self.y_polynomial.newtons_method(y, t_guess, max_iterations);
314 let y = newton_output.y;
315 let t = newton_output.x;
316 let x = self.x_polynomial.evaluate(t).y;
317 PointXYT::new(x, y, t)
318 }
319 #[cfg(feature = "std")]
322 fn t_to_speed_squared(&self, t: f64) -> f64 {
323 let derivative = self.derivative();
324 let x = derivative.x_polynomial.evaluate(t).y;
325 let y = derivative.y_polynomial.evaluate(t).y;
326 x.powi(2) + y.powi(2)
327 }
328 #[cfg(feature = "std")]
330 pub fn t_to_distance(&self, t: f64) -> f64 {
331 self.t_to_speed_squared(t).powf(1.5) / 1.5
333 }
334 #[cfg(feature = "std")]
339 pub fn newtons_method_distance_to_t(
340 &self,
341 distance: f64,
342 t_guess: f64,
343 max_iterations: u16,
344 ) -> f64 {
345 newtons_method(
346 |t| self.t_to_distance(t),
347 |t| self.t_to_speed_squared(t).sqrt(),
348 distance,
349 t_guess,
350 max_iterations,
351 )
352 .y
353 }
354}