From 89dfb612722df2a3ca677c5e48b8c8597dc3a5b5 Mon Sep 17 00:00:00 2001 From: Dimitri Sabadie Date: Thu, 19 Mar 2020 01:22:26 +0100 Subject: [PATCH] Add rustfmt.toml and reformat. --- examples/hello-world.rs | 14 +- examples/serialization.rs | 42 +-- rustfmt.toml | 15 ++ src/cgmath.rs | 58 ++-- src/interpolate.rs | 324 +++++++++++----------- src/interpolation.rs | 98 +++---- src/iter.rs | 34 +-- src/key.rs | 26 +- src/nalgebra.rs | 2 +- src/spline.rs | 547 +++++++++++++++++++------------------- tests/mod.rs | 336 +++++++++++------------ 11 files changed, 751 insertions(+), 745 deletions(-) create mode 100644 rustfmt.toml diff --git a/examples/hello-world.rs b/examples/hello-world.rs index db994ff..f39e6c6 100644 --- a/examples/hello-world.rs +++ b/examples/hello-world.rs @@ -3,12 +3,12 @@ extern crate splines; use splines::{Interpolation, Key, Spline}; fn main() { - let keys = vec![ - Key::new(0., 0., Interpolation::default()), - Key::new(5., 1., Interpolation::default()), - ]; - let spline = Spline::from_vec(keys); + let keys = vec![ + Key::new(0., 0., Interpolation::default()), + Key::new(5., 1., Interpolation::default()), + ]; + let spline = Spline::from_vec(keys); - println!("value at 0: {:?}", spline.clamped_sample(0.)); - println!("value at 3: {:?}", spline.clamped_sample(3.)); + println!("value at 0: {:?}", spline.clamped_sample(0.)); + println!("value at 3: {:?}", spline.clamped_sample(3.)); } diff --git a/examples/serialization.rs b/examples/serialization.rs index db46cb2..530bb5b 100644 --- a/examples/serialization.rs +++ b/examples/serialization.rs @@ -6,26 +6,26 @@ use serde_json::from_value; use splines::Spline; fn main() { - let value = json! { - [ - { - "t": 0, - "interpolation": "linear", - "value": 0 - }, - { - "t": 1, - "interpolation": { "step": 0.5 }, - "value": 1 - }, - { - "t": 5, - "interpolation": "cosine", - "value": 10 - }, - ] - }; + let value = json! { + [ + { + "t": 0, + "interpolation": "linear", + "value": 0 + }, + { + "t": 1, + "interpolation": { "step": 0.5 }, + "value": 1 + }, + { + "t": 5, + "interpolation": "cosine", + "value": 10 + }, + ] + }; - let spline = from_value::>(value); - println!("{:?}", spline); + let spline = from_value::>(value); + println!("{:?}", spline); } diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..682e364 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,15 @@ +edition = "2018" + +fn_args_layout = "Tall" +force_explicit_abi = true +hard_tabs = false +max_width = 100 +merge_derives = true +newline_style = "Unix" +remove_nested_parens = true +reorder_imports = true +reorder_modules = true +tab_spaces = 2 +use_field_init_shorthand = true +use_small_heuristics = "Default" +use_try_shorthand = true diff --git a/src/cgmath.rs b/src/cgmath.rs index c67c8f5..958c512 100644 --- a/src/cgmath.rs +++ b/src/cgmath.rs @@ -1,9 +1,9 @@ use cgmath::{ - BaseFloat, BaseNum, InnerSpace, Quaternion, Vector1, Vector2, Vector3, Vector4, VectorSpace, + BaseFloat, BaseNum, InnerSpace, Quaternion, Vector1, Vector2, Vector3, Vector4, VectorSpace, }; use crate::interpolate::{ - cubic_bezier_def, cubic_hermite_def, quadratic_bezier_def, Additive, Interpolate, Linear, One, + cubic_bezier_def, cubic_hermite_def, quadratic_bezier_def, Additive, Interpolate, Linear, One, }; macro_rules! impl_interpolate_vec { @@ -52,41 +52,41 @@ impl_interpolate_vec!(Vector4); impl Linear for Quaternion where - T: BaseFloat, + T: BaseFloat, { - #[inline(always)] - fn outer_mul(self, t: T) -> Self { - self * t - } + #[inline(always)] + fn outer_mul(self, t: T) -> Self { + self * t + } - #[inline(always)] - fn outer_div(self, t: T) -> Self { - self / t - } + #[inline(always)] + fn outer_div(self, t: T) -> Self { + self / t + } } impl Interpolate for Quaternion where - Self: InnerSpace, - T: Additive + BaseFloat + One, + Self: InnerSpace, + T: Additive + BaseFloat + One, { - #[inline(always)] - fn lerp(a: Self, b: Self, t: T) -> Self { - a.nlerp(b, t) - } + #[inline(always)] + fn lerp(a: Self, b: Self, t: T) -> Self { + a.nlerp(b, t) + } - #[inline(always)] - fn cubic_hermite(x: (Self, T), a: (Self, T), b: (Self, T), y: (Self, T), t: T) -> Self { - cubic_hermite_def(x, a, b, y, t) - } + #[inline(always)] + fn cubic_hermite(x: (Self, T), a: (Self, T), b: (Self, T), y: (Self, T), t: T) -> Self { + cubic_hermite_def(x, a, b, y, t) + } - #[inline(always)] - fn quadratic_bezier(a: Self, u: Self, b: Self, t: T) -> Self { - quadratic_bezier_def(a, u, b, t) - } + #[inline(always)] + fn quadratic_bezier(a: Self, u: Self, b: Self, t: T) -> Self { + quadratic_bezier_def(a, u, b, t) + } - #[inline(always)] - fn cubic_bezier(a: Self, u: Self, v: Self, b: Self, t: T) -> Self { - cubic_bezier_def(a, u, v, b, t) - } + #[inline(always)] + fn cubic_bezier(a: Self, u: Self, v: Self, b: Self, t: T) -> Self { + cubic_bezier_def(a, u, v, b, t) + } } diff --git a/src/interpolate.rs b/src/interpolate.rs index f97757c..2ef09ba 100644 --- a/src/interpolate.rs +++ b/src/interpolate.rs @@ -54,23 +54,23 @@ use std::ops::{Add, Mul, Sub}; /// /// [`Spline::sample`]: crate::spline::Spline::sample pub trait Interpolate: Sized + Copy + Linear { - /// Linear interpolation. - fn lerp(a: Self, b: Self, t: T) -> Self; + /// Linear interpolation. + fn lerp(a: Self, b: Self, t: T) -> Self; - /// Cubic hermite interpolation. - /// - /// Default to [`lerp`]. - /// - /// [`lerp`]: Interpolate::lerp - fn cubic_hermite(_: (Self, T), a: (Self, T), b: (Self, T), _: (Self, T), t: T) -> Self { - Self::lerp(a.0, b.0, t) - } + /// Cubic hermite interpolation. + /// + /// Default to [`lerp`]. + /// + /// [`lerp`]: Interpolate::lerp + fn cubic_hermite(_: (Self, T), a: (Self, T), b: (Self, T), _: (Self, T), t: T) -> Self { + Self::lerp(a.0, b.0, t) + } - /// Quadratic Bézier interpolation. - fn quadratic_bezier(a: Self, u: Self, b: Self, t: T) -> Self; + /// Quadratic Bézier interpolation. + fn quadratic_bezier(a: Self, u: Self, b: Self, t: T) -> Self; - /// Cubic Bézier interpolation. - fn cubic_bezier(a: Self, u: Self, v: Self, b: Self, t: T) -> Self; + /// Cubic Bézier interpolation. + fn cubic_bezier(a: Self, u: Self, v: Self, b: Self, t: T) -> Self; } /// Set of types that support additions and subtraction. @@ -82,44 +82,44 @@ impl Additive for T where T: Copy + Add + Sub: Additive { - /// Apply an outer multiplication law. - fn outer_mul(self, t: T) -> Self; + /// Apply an outer multiplication law. + fn outer_mul(self, t: T) -> Self; - /// Apply an outer division law. - fn outer_div(self, t: T) -> Self; + /// Apply an outer division law. + fn outer_div(self, t: T) -> Self; } macro_rules! impl_linear_simple { - ($t:ty) => { - impl Linear<$t> for $t { - fn outer_mul(self, t: $t) -> Self { - self * t - } + ($t:ty) => { + impl Linear<$t> for $t { + fn outer_mul(self, t: $t) -> Self { + self * t + } - /// Apply an outer division law. - fn outer_div(self, t: $t) -> Self { - self / t - } - } - }; + /// Apply an outer division law. + fn outer_div(self, t: $t) -> Self { + self / t + } + } + }; } impl_linear_simple!(f32); impl_linear_simple!(f64); macro_rules! impl_linear_cast { - ($t:ty, $q:ty) => { - impl Linear<$t> for $q { - fn outer_mul(self, t: $t) -> Self { - self * t as $q - } + ($t:ty, $q:ty) => { + impl Linear<$t> for $q { + fn outer_mul(self, t: $t) -> Self { + self * t as $q + } - /// Apply an outer division law. - fn outer_div(self, t: $t) -> Self { - self / t as $q - } - } - }; + /// Apply an outer division law. + fn outer_div(self, t: $t) -> Self { + self / t as $q + } + } + }; } impl_linear_cast!(f32, f64); @@ -127,19 +127,19 @@ impl_linear_cast!(f64, f32); /// Types with a neutral element for multiplication. pub trait One { - /// The neutral element for the multiplicative monoid — typically called `1`. - fn one() -> Self; + /// The neutral element for the multiplicative monoid — typically called `1`. + fn one() -> Self; } macro_rules! impl_one_float { - ($t:ty) => { - impl One for $t { - #[inline(always)] - fn one() -> Self { - 1. - } - } - }; + ($t:ty) => { + impl One for $t { + #[inline(always)] + fn one() -> Self { + 1. + } + } + }; } impl_one_float!(f32); @@ -147,51 +147,51 @@ impl_one_float!(f64); /// Types with a sane definition of π and cosine. pub trait Trigo { - /// π. - fn pi() -> Self; + /// π. + fn pi() -> Self; - /// Cosine of the argument. - fn cos(self) -> Self; + /// Cosine of the argument. + fn cos(self) -> Self; } impl Trigo for f32 { - #[inline(always)] - fn pi() -> Self { - f32::consts::PI + #[inline(always)] + fn pi() -> Self { + f32::consts::PI + } + + #[inline(always)] + fn cos(self) -> Self { + #[cfg(feature = "std")] + { + self.cos() } - #[inline(always)] - fn cos(self) -> Self { - #[cfg(feature = "std")] - { - self.cos() - } - - #[cfg(not(feature = "std"))] - { - unsafe { cosf32(self) } - } + #[cfg(not(feature = "std"))] + { + unsafe { cosf32(self) } } + } } impl Trigo for f64 { - #[inline(always)] - fn pi() -> Self { - f64::consts::PI + #[inline(always)] + fn pi() -> Self { + f64::consts::PI + } + + #[inline(always)] + fn cos(self) -> Self { + #[cfg(feature = "std")] + { + self.cos() } - #[inline(always)] - fn cos(self) -> Self { - #[cfg(feature = "std")] - { - self.cos() - } - - #[cfg(not(feature = "std"))] - { - unsafe { cosf64(self) } - } + #[cfg(not(feature = "std"))] + { + unsafe { cosf64(self) } } + } } /// Default implementation of [`Interpolate::cubic_hermite`]. @@ -199,28 +199,28 @@ impl Trigo for f64 { /// `V` is the value being interpolated. `T` is the sampling value (also sometimes called time). pub fn cubic_hermite_def(x: (V, T), a: (V, T), b: (V, T), y: (V, T), t: T) -> V where - V: Linear, - T: Additive + Mul + One, + V: Linear, + T: Additive + Mul + One, { - // some stupid generic constants, because Rust doesn’t have polymorphic literals… - let one_t = T::one(); - let two_t = one_t + one_t; // lolololol - let three_t = two_t + one_t; // megalol + // some stupid generic constants, because Rust doesn’t have polymorphic literals… + let one_t = T::one(); + let two_t = one_t + one_t; // lolololol + let three_t = two_t + one_t; // megalol - // sampler stuff - let t2 = t * t; - let t3 = t2 * t; - let two_t3 = t3 * two_t; - let three_t2 = t2 * three_t; + // sampler stuff + let t2 = t * t; + let t3 = t2 * t; + let two_t3 = t3 * two_t; + let three_t2 = t2 * three_t; - // tangents - let m0 = (b.0 - x.0).outer_div(b.1 - x.1); - let m1 = (y.0 - a.0).outer_div(y.1 - a.1); + // tangents + let m0 = (b.0 - x.0).outer_div(b.1 - x.1); + let m1 = (y.0 - a.0).outer_div(y.1 - a.1); - a.0.outer_mul(two_t3 - three_t2 + one_t) - + m0.outer_mul(t3 - t2 * two_t + t) - + b.0.outer_mul(three_t2 - two_t3) - + m1.outer_mul(t3 - t2) + a.0.outer_mul(two_t3 - three_t2 + one_t) + + m0.outer_mul(t3 - t2 * two_t + t) + + b.0.outer_mul(three_t2 - two_t3) + + m1.outer_mul(t3 - t2) } /// Default implementation of [`Interpolate::quadratic_bezier`]. @@ -228,12 +228,12 @@ where /// `V` is the value being interpolated. `T` is the sampling value (also sometimes called time). pub fn quadratic_bezier_def(a: V, u: V, b: V, t: T) -> V where - V: Linear, - T: Additive + Mul + One, + V: Linear, + T: Additive + Mul + One, { - let one_t = T::one() - t; - let one_t_2 = one_t * one_t; - u + (a - u).outer_mul(one_t_2) + (b - u).outer_mul(t * t) + let one_t = T::one() - t; + let one_t_2 = one_t * one_t; + u + (a - u).outer_mul(one_t_2) + (b - u).outer_mul(t * t) } /// Default implementation of [`Interpolate::cubic_bezier`]. @@ -241,83 +241,77 @@ where /// `V` is the value being interpolated. `T` is the sampling value (also sometimes called time). pub fn cubic_bezier_def(a: V, u: V, v: V, b: V, t: T) -> V where - V: Linear, - T: Additive + Mul + One, + V: Linear, + T: Additive + Mul + One, { - let one_t = T::one() - t; - let one_t_2 = one_t * one_t; - let one_t_3 = one_t_2 * one_t; - let three = T::one() + T::one() + T::one(); + let one_t = T::one() - t; + let one_t_2 = one_t * one_t; + let one_t_3 = one_t_2 * one_t; + let three = T::one() + T::one() + T::one(); - a.outer_mul(one_t_3) - + u.outer_mul(three * one_t_2 * t) - + v.outer_mul(three * one_t * t * t) - + b.outer_mul(t * t * t) + a.outer_mul(one_t_3) + + u.outer_mul(three * one_t_2 * t) + + v.outer_mul(three * one_t * t * t) + + b.outer_mul(t * t * t) } macro_rules! impl_interpolate_simple { - ($t:ty) => { - impl Interpolate<$t> for $t { - fn lerp(a: Self, b: Self, t: $t) -> Self { - a * (1. - t) + b * t - } + ($t:ty) => { + impl Interpolate<$t> for $t { + fn lerp(a: Self, b: Self, t: $t) -> Self { + a * (1. - t) + b * t + } - fn cubic_hermite( - x: (Self, $t), - a: (Self, $t), - b: (Self, $t), - y: (Self, $t), - t: $t, - ) -> Self { - cubic_hermite_def(x, a, b, y, t) - } + fn cubic_hermite(x: (Self, $t), a: (Self, $t), b: (Self, $t), y: (Self, $t), t: $t) -> Self { + cubic_hermite_def(x, a, b, y, t) + } - fn quadratic_bezier(a: Self, u: Self, b: Self, t: $t) -> Self { - quadratic_bezier_def(a, u, b, t) - } + fn quadratic_bezier(a: Self, u: Self, b: Self, t: $t) -> Self { + quadratic_bezier_def(a, u, b, t) + } - fn cubic_bezier(a: Self, u: Self, v: Self, b: Self, t: $t) -> Self { - cubic_bezier_def(a, u, v, b, t) - } - } - }; + fn cubic_bezier(a: Self, u: Self, v: Self, b: Self, t: $t) -> Self { + cubic_bezier_def(a, u, v, b, t) + } + } + }; } impl_interpolate_simple!(f32); impl_interpolate_simple!(f64); macro_rules! impl_interpolate_via { - ($t:ty, $v:ty) => { - impl Interpolate<$t> for $v { - fn lerp(a: Self, b: Self, t: $t) -> Self { - a * (1. - t as $v) + b * t as $v - } + ($t:ty, $v:ty) => { + impl Interpolate<$t> for $v { + fn lerp(a: Self, b: Self, t: $t) -> Self { + a * (1. - t as $v) + b * t as $v + } - fn cubic_hermite( - (x, xt): (Self, $t), - (a, at): (Self, $t), - (b, bt): (Self, $t), - (y, yt): (Self, $t), - t: $t, - ) -> Self { - cubic_hermite_def( - (x, xt as $v), - (a, at as $v), - (b, bt as $v), - (y, yt as $v), - t as $v, - ) - } + fn cubic_hermite( + (x, xt): (Self, $t), + (a, at): (Self, $t), + (b, bt): (Self, $t), + (y, yt): (Self, $t), + t: $t, + ) -> Self { + cubic_hermite_def( + (x, xt as $v), + (a, at as $v), + (b, bt as $v), + (y, yt as $v), + t as $v, + ) + } - fn quadratic_bezier(a: Self, u: Self, b: Self, t: $t) -> Self { - quadratic_bezier_def(a, u, b, t as $v) - } + fn quadratic_bezier(a: Self, u: Self, b: Self, t: $t) -> Self { + quadratic_bezier_def(a, u, b, t as $v) + } - fn cubic_bezier(a: Self, u: Self, v: Self, b: Self, t: $t) -> Self { - cubic_bezier_def(a, u, v, b, t as $v) - } - } - }; + fn cubic_bezier(a: Self, u: Self, v: Self, b: Self, t: $t) -> Self { + cubic_bezier_def(a, u, v, b, t as $v) + } + } + }; } impl_interpolate_via!(f32, f64); diff --git a/src/interpolation.rs b/src/interpolation.rs index 1fc57fa..031e99b 100644 --- a/src/interpolation.rs +++ b/src/interpolation.rs @@ -10,56 +10,56 @@ use serde_derive::{Deserialize, Serialize}; #[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))] #[cfg_attr(feature = "serialization", serde(rename_all = "snake_case"))] pub enum Interpolation { - /// Hold a [`Key`] until the sampling value passes the normalized step threshold, in which - /// case the next key is used. - /// - /// > Note: if you set the threshold to `0.5`, the first key will be used until half the time - /// > between the two keys; the second key will be in used afterwards. If you set it to `1.0`, the - /// > first key will be kept until the next key. Set it to `0.` and the first key will never be - /// > used. - /// - /// [`Key`]: crate::key::Key - Step(T), - /// Linear interpolation between a key and the next one. - Linear, - /// Cosine interpolation between a key and the next one. - Cosine, - /// Catmull-Rom interpolation, performing a cubic Hermite interpolation using four keys. - CatmullRom, - /// Bézier interpolation. - /// - /// A control point that uses such an interpolation is associated with an extra point. The segmant - /// connecting both is called the _tangent_ of this point. The part of the spline defined between - /// this control point and the next one will be interpolated across with Bézier interpolation. Two - /// cases are possible: - /// - /// - The next control point also has a Bézier interpolation mode. In this case, its tangent is - /// used for the interpolation process. This is called _cubic Bézier interpolation_ and it - /// kicks ass. - /// - The next control point doesn’t have a Bézier interpolation mode set. In this case, the - /// tangent used for the next control point is defined as the segment connecting that control - /// point and the current control point’s associated point. This is called _quadratic Bézer - /// interpolation_ and it kicks ass too, but a bit less than cubic. - Bezier(V), - /// A special Bézier interpolation using an _input tangent_ and an _output tangent_. - /// - /// With this kind of interpolation, a control point has an input tangent, which has the same role - /// as the one defined by [`Interpolation::Bezier`], and an output tangent, which has the same - /// role defined by the next key’s [`Interpolation::Bezier`] if present, normally. - /// - /// What it means is that instead of setting the output tangent as the next key’s Bézier tangent, - /// this interpolation mode allows you to manually set the output tangent. That will yield more - /// control on the tangents but might generate discontinuities. Use with care. - /// - /// Stroke Bézier interpolation is always a cubic Bézier interpolation by default. - StrokeBezier(V, V), - #[doc(hidden)] - __NonExhaustive, + /// Hold a [`Key`] until the sampling value passes the normalized step threshold, in which + /// case the next key is used. + /// + /// > Note: if you set the threshold to `0.5`, the first key will be used until half the time + /// > between the two keys; the second key will be in used afterwards. If you set it to `1.0`, the + /// > first key will be kept until the next key. Set it to `0.` and the first key will never be + /// > used. + /// + /// [`Key`]: crate::key::Key + Step(T), + /// Linear interpolation between a key and the next one. + Linear, + /// Cosine interpolation between a key and the next one. + Cosine, + /// Catmull-Rom interpolation, performing a cubic Hermite interpolation using four keys. + CatmullRom, + /// Bézier interpolation. + /// + /// A control point that uses such an interpolation is associated with an extra point. The segmant + /// connecting both is called the _tangent_ of this point. The part of the spline defined between + /// this control point and the next one will be interpolated across with Bézier interpolation. Two + /// cases are possible: + /// + /// - The next control point also has a Bézier interpolation mode. In this case, its tangent is + /// used for the interpolation process. This is called _cubic Bézier interpolation_ and it + /// kicks ass. + /// - The next control point doesn’t have a Bézier interpolation mode set. In this case, the + /// tangent used for the next control point is defined as the segment connecting that control + /// point and the current control point’s associated point. This is called _quadratic Bézer + /// interpolation_ and it kicks ass too, but a bit less than cubic. + Bezier(V), + /// A special Bézier interpolation using an _input tangent_ and an _output tangent_. + /// + /// With this kind of interpolation, a control point has an input tangent, which has the same role + /// as the one defined by [`Interpolation::Bezier`], and an output tangent, which has the same + /// role defined by the next key’s [`Interpolation::Bezier`] if present, normally. + /// + /// What it means is that instead of setting the output tangent as the next key’s Bézier tangent, + /// this interpolation mode allows you to manually set the output tangent. That will yield more + /// control on the tangents but might generate discontinuities. Use with care. + /// + /// Stroke Bézier interpolation is always a cubic Bézier interpolation by default. + StrokeBezier(V, V), + #[doc(hidden)] + __NonExhaustive, } impl Default for Interpolation { - /// [`Interpolation::Linear`] is the default. - fn default() -> Self { - Interpolation::Linear - } + /// [`Interpolation::Linear`] is the default. + fn default() -> Self { + Interpolation::Linear + } } diff --git a/src/iter.rs b/src/iter.rs index c92cfa8..c01f437 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -13,32 +13,32 @@ use crate::{Key, Spline}; /// This iterator type is guaranteed to iterate over sorted keys. pub struct Iter<'a, T, V> where - T: 'a, - V: 'a, + T: 'a, + V: 'a, { - spline: &'a Spline, - i: usize, + spline: &'a Spline, + i: usize, } impl<'a, T, V> Iterator for Iter<'a, T, V> { - type Item = &'a Key; + type Item = &'a Key; - fn next(&mut self) -> Option { - let r = self.spline.0.get(self.i); + fn next(&mut self) -> Option { + let r = self.spline.0.get(self.i); - if let Some(_) = r { - self.i += 1; - } - - r + if let Some(_) = r { + self.i += 1; } + + r + } } impl<'a, T, V> IntoIterator for &'a Spline { - type Item = &'a Key; - type IntoIter = Iter<'a, T, V>; + type Item = &'a Key; + type IntoIter = Iter<'a, T, V>; - fn into_iter(self) -> Self::IntoIter { - Iter { spline: self, i: 0 } - } + fn into_iter(self) -> Self::IntoIter { + Iter { spline: self, i: 0 } + } } diff --git a/src/key.rs b/src/key.rs index 890a931..aca16dc 100644 --- a/src/key.rs +++ b/src/key.rs @@ -22,21 +22,21 @@ use crate::interpolation::Interpolation; #[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))] #[cfg_attr(feature = "serialization", serde(rename_all = "snake_case"))] pub struct Key { - /// Interpolation parameter at which the [`Key`] should be reached. - pub t: T, - /// Carried value. - pub value: V, - /// Interpolation mode. - pub interpolation: Interpolation, + /// Interpolation parameter at which the [`Key`] should be reached. + pub t: T, + /// Carried value. + pub value: V, + /// Interpolation mode. + pub interpolation: Interpolation, } impl Key { - /// Create a new key. - pub fn new(t: T, value: V, interpolation: Interpolation) -> Self { - Key { - t, - value, - interpolation, - } + /// Create a new key. + pub fn new(t: T, value: V, interpolation: Interpolation) -> Self { + Key { + t, + value, + interpolation, } + } } diff --git a/src/nalgebra.rs b/src/nalgebra.rs index b692ebe..c90f195 100644 --- a/src/nalgebra.rs +++ b/src/nalgebra.rs @@ -4,7 +4,7 @@ use num_traits as nt; use std::ops::Mul; use crate::interpolate::{ - cubic_bezier_def, cubic_hermite_def, quadratic_bezier_def, Additive, Interpolate, Linear, One, + cubic_bezier_def, cubic_hermite_def, quadratic_bezier_def, Additive, Interpolate, Linear, One, }; macro_rules! impl_interpolate_vector { diff --git a/src/spline.rs b/src/spline.rs index 28a2b92..dd685b0 100644 --- a/src/spline.rs +++ b/src/spline.rs @@ -34,268 +34,265 @@ use crate::key::Key; pub struct Spline(pub(crate) Vec>); impl Spline { - /// Internal sort to ensure invariant of sorting keys is valid. - fn internal_sort(&mut self) - where - T: PartialOrd, - { - self.0 - .sort_by(|k0, k1| k0.t.partial_cmp(&k1.t).unwrap_or(Ordering::Less)); - } + /// Internal sort to ensure invariant of sorting keys is valid. + fn internal_sort(&mut self) + where + T: PartialOrd, + { + self + .0 + .sort_by(|k0, k1| k0.t.partial_cmp(&k1.t).unwrap_or(Ordering::Less)); + } - /// Create a new spline out of keys. The keys don’t have to be sorted even though it’s recommended - /// to provide ascending sorted ones (for performance purposes). - pub fn from_vec(keys: Vec>) -> Self - where - T: PartialOrd, - { - let mut spline = Spline(keys); - spline.internal_sort(); - spline - } + /// Create a new spline out of keys. The keys don’t have to be sorted even though it’s recommended + /// to provide ascending sorted ones (for performance purposes). + pub fn from_vec(keys: Vec>) -> Self + where + T: PartialOrd, + { + let mut spline = Spline(keys); + spline.internal_sort(); + spline + } - /// Create a new spline by consuming an `Iterater>`. They keys don’t have to be - /// sorted. - /// - /// # Note on iterators - /// - /// It’s valid to use any iterator that implements `Iterator>`. However, you should - /// use [`Spline::from_vec`] if you are passing a [`Vec`]. - pub fn from_iter(iter: I) -> Self - where - I: Iterator>, - T: PartialOrd, - { - Self::from_vec(iter.collect()) - } + /// Create a new spline by consuming an `Iterater>`. They keys don’t have to be + /// sorted. + /// + /// # Note on iterators + /// + /// It’s valid to use any iterator that implements `Iterator>`. However, you should + /// use [`Spline::from_vec`] if you are passing a [`Vec`]. + pub fn from_iter(iter: I) -> Self + where + I: Iterator>, + T: PartialOrd, + { + Self::from_vec(iter.collect()) + } - /// Retrieve the keys of a spline. - pub fn keys(&self) -> &[Key] { - &self.0 - } + /// Retrieve the keys of a spline. + pub fn keys(&self) -> &[Key] { + &self.0 + } - /// Number of keys. - #[inline(always)] - pub fn len(&self) -> usize { - self.0.len() - } + /// Number of keys. + #[inline(always)] + pub fn len(&self) -> usize { + self.0.len() + } - /// Check whether the spline has no key. - #[inline(always)] - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } + /// Check whether the spline has no key. + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } - /// Sample a spline at a given time, returning the interpolated value along with its associated - /// key. - /// - /// The current implementation, based on immutability, cannot perform in constant time. This means - /// that sampling’s processing complexity is currently *O(log n)*. It’s possible to achieve *O(1)* - /// performance by using a slightly different spline type. If you are interested by this feature, - /// an implementation for a dedicated type is foreseen yet not started yet. - /// - /// # Return - /// - /// `None` if you try to sample a value at a time that has no key associated with. That can also - /// happen if you try to sample between two keys with a specific interpolation mode that makes the - /// sampling impossible. For instance, [`Interpolation::CatmullRom`] requires *four* keys. If - /// you’re near the beginning of the spline or its end, ensure you have enough keys around to make - /// the sampling. - pub fn sample_with_key(&self, t: T) -> Option<(V, &Key, Option<&Key>)> - where - T: Additive + One + Trigo + Mul + Div + PartialOrd, - V: Additive + Interpolate, - { - let keys = &self.0; - let i = search_lower_cp(keys, t)?; - let cp0 = &keys[i]; + /// Sample a spline at a given time, returning the interpolated value along with its associated + /// key. + /// + /// The current implementation, based on immutability, cannot perform in constant time. This means + /// that sampling’s processing complexity is currently *O(log n)*. It’s possible to achieve *O(1)* + /// performance by using a slightly different spline type. If you are interested by this feature, + /// an implementation for a dedicated type is foreseen yet not started yet. + /// + /// # Return + /// + /// `None` if you try to sample a value at a time that has no key associated with. That can also + /// happen if you try to sample between two keys with a specific interpolation mode that makes the + /// sampling impossible. For instance, [`Interpolation::CatmullRom`] requires *four* keys. If + /// you’re near the beginning of the spline or its end, ensure you have enough keys around to make + /// the sampling. + pub fn sample_with_key(&self, t: T) -> Option<(V, &Key, Option<&Key>)> + where + T: Additive + One + Trigo + Mul + Div + PartialOrd, + V: Additive + Interpolate, + { + let keys = &self.0; + let i = search_lower_cp(keys, t)?; + let cp0 = &keys[i]; - match cp0.interpolation { - Interpolation::Step(threshold) => { - let cp1 = &keys[i + 1]; - let nt = normalize_time(t, cp0, cp1); - let value = if nt < threshold { cp0.value } else { cp1.value }; + match cp0.interpolation { + Interpolation::Step(threshold) => { + let cp1 = &keys[i + 1]; + let nt = normalize_time(t, cp0, cp1); + let value = if nt < threshold { cp0.value } else { cp1.value }; - Some((value, cp0, Some(cp1))) - } + Some((value, cp0, Some(cp1))) + } - Interpolation::Linear => { - let cp1 = &keys[i + 1]; - let nt = normalize_time(t, cp0, cp1); - let value = Interpolate::lerp(cp0.value, cp1.value, nt); + Interpolation::Linear => { + let cp1 = &keys[i + 1]; + let nt = normalize_time(t, cp0, cp1); + let value = Interpolate::lerp(cp0.value, cp1.value, nt); - Some((value, cp0, Some(cp1))) - } + Some((value, cp0, Some(cp1))) + } - Interpolation::Cosine => { - let two_t = T::one() + T::one(); - let cp1 = &keys[i + 1]; - let nt = normalize_time(t, cp0, cp1); - let cos_nt = (T::one() - (nt * T::pi()).cos()) / two_t; - let value = Interpolate::lerp(cp0.value, cp1.value, cos_nt); + Interpolation::Cosine => { + let two_t = T::one() + T::one(); + let cp1 = &keys[i + 1]; + let nt = normalize_time(t, cp0, cp1); + let cos_nt = (T::one() - (nt * T::pi()).cos()) / two_t; + let value = Interpolate::lerp(cp0.value, cp1.value, cos_nt); - Some((value, cp0, Some(cp1))) - } + Some((value, cp0, Some(cp1))) + } - Interpolation::CatmullRom => { - // We need at least four points for Catmull Rom; ensure we have them, otherwise, return - // None. - if i == 0 || i >= keys.len() - 2 { - None - } else { - let cp1 = &keys[i + 1]; - let cpm0 = &keys[i - 1]; - let cpm1 = &keys[i + 2]; - let nt = normalize_time(t, cp0, cp1); - let value = Interpolate::cubic_hermite( - (cpm0.value, cpm0.t), - (cp0.value, cp0.t), - (cp1.value, cp1.t), - (cpm1.value, cpm1.t), - nt, - ); - - Some((value, cp0, Some(cp1))) - } - } - - Interpolation::Bezier(u) | Interpolation::StrokeBezier(_, u) => { - // We need to check the next control point to see whether we want quadratic or cubic Bezier. - let cp1 = &keys[i + 1]; - let nt = normalize_time(t, cp0, cp1); - - let value = match cp1.interpolation { - Interpolation::Bezier(v) => Interpolate::cubic_bezier( - cp0.value, - u, - cp1.value + cp1.value - v, - cp1.value, - nt, - ), - - Interpolation::StrokeBezier(v, _) => { - Interpolate::cubic_bezier(cp0.value, u, v, cp1.value, nt) - } - - _ => Interpolate::quadratic_bezier(cp0.value, u, cp1.value, nt), - }; - - Some((value, cp0, Some(cp1))) - } - - Interpolation::__NonExhaustive => unreachable!(), - } - } - - /// Sample a spline at a given time. - /// - pub fn sample(&self, t: T) -> Option - where - T: Additive + One + Trigo + Mul + Div + PartialOrd, - V: Additive + Interpolate, - { - self.sample_with_key(t).map(|(v, _, _)| v) - } - - /// Sample a spline at a given time with clamping, returning the interpolated value along with its - /// associated key. - /// - /// # Return - /// - /// If you sample before the first key or after the last one, return the first key or the last - /// one, respectively. Otherwise, behave the same way as [`Spline::sample`]. - /// - /// # Error - /// - /// This function returns [`None`] if you have no key. - pub fn clamped_sample_with_key(&self, t: T) -> Option<(V, &Key, Option<&Key>)> - where - T: Additive + One + Trigo + Mul + Div + PartialOrd, - V: Additive + Interpolate, - { - if self.0.is_empty() { - return None; - } - - self.sample_with_key(t).or_else(move || { - let first = self.0.first().unwrap(); - if t <= first.t { - let second = if self.0.len() >= 2 { - Some(&self.0[1]) - } else { - None - }; - Some((first.value, &first, second)) - } else { - let last = self.0.last().unwrap(); - - if t >= last.t { - Some((last.value, &last, None)) - } else { - None - } - } - }) - } - - /// Sample a spline at a given time with clamping. - pub fn clamped_sample(&self, t: T) -> Option - where - T: Additive + One + Trigo + Mul + Div + PartialOrd, - V: Additive + Interpolate, - { - self.clamped_sample_with_key(t).map(|(v, _, _)| v) - } - - /// Add a key into the spline. - pub fn add(&mut self, key: Key) - where - T: PartialOrd, - { - self.0.push(key); - self.internal_sort(); - } - - /// Remove a key from the spline. - pub fn remove(&mut self, index: usize) -> Option> { - if index >= self.0.len() { - None + Interpolation::CatmullRom => { + // We need at least four points for Catmull Rom; ensure we have them, otherwise, return + // None. + if i == 0 || i >= keys.len() - 2 { + None } else { - Some(self.0.remove(index)) + let cp1 = &keys[i + 1]; + let cpm0 = &keys[i - 1]; + let cpm1 = &keys[i + 2]; + let nt = normalize_time(t, cp0, cp1); + let value = Interpolate::cubic_hermite( + (cpm0.value, cpm0.t), + (cp0.value, cp0.t), + (cp1.value, cp1.t), + (cpm1.value, cpm1.t), + nt, + ); + + Some((value, cp0, Some(cp1))) } + } + + Interpolation::Bezier(u) | Interpolation::StrokeBezier(_, u) => { + // We need to check the next control point to see whether we want quadratic or cubic Bezier. + let cp1 = &keys[i + 1]; + let nt = normalize_time(t, cp0, cp1); + + let value = match cp1.interpolation { + Interpolation::Bezier(v) => { + Interpolate::cubic_bezier(cp0.value, u, cp1.value + cp1.value - v, cp1.value, nt) + } + + Interpolation::StrokeBezier(v, _) => { + Interpolate::cubic_bezier(cp0.value, u, v, cp1.value, nt) + } + + _ => Interpolate::quadratic_bezier(cp0.value, u, cp1.value, nt), + }; + + Some((value, cp0, Some(cp1))) + } + + Interpolation::__NonExhaustive => unreachable!(), + } + } + + /// Sample a spline at a given time. + /// + pub fn sample(&self, t: T) -> Option + where + T: Additive + One + Trigo + Mul + Div + PartialOrd, + V: Additive + Interpolate, + { + self.sample_with_key(t).map(|(v, _, _)| v) + } + + /// Sample a spline at a given time with clamping, returning the interpolated value along with its + /// associated key. + /// + /// # Return + /// + /// If you sample before the first key or after the last one, return the first key or the last + /// one, respectively. Otherwise, behave the same way as [`Spline::sample`]. + /// + /// # Error + /// + /// This function returns [`None`] if you have no key. + pub fn clamped_sample_with_key(&self, t: T) -> Option<(V, &Key, Option<&Key>)> + where + T: Additive + One + Trigo + Mul + Div + PartialOrd, + V: Additive + Interpolate, + { + if self.0.is_empty() { + return None; } - /// Update a key and return the key already present. - /// - /// The key is updated — if present — with the provided function. - /// - /// # Notes - /// - /// That function makes sense only if you want to change the interpolator (i.e. [`Key::t`]) of - /// your key. If you just want to change the interpolation mode or the carried value, consider - /// using the [`Spline::get_mut`] method instead as it will be way faster. - pub fn replace(&mut self, index: usize, f: F) -> Option> - where - F: FnOnce(&Key) -> Key, - T: PartialOrd, - { - let key = self.remove(index)?; - self.add(f(&key)); - Some(key) - } + self.sample_with_key(t).or_else(move || { + let first = self.0.first().unwrap(); + if t <= first.t { + let second = if self.0.len() >= 2 { + Some(&self.0[1]) + } else { + None + }; + Some((first.value, &first, second)) + } else { + let last = self.0.last().unwrap(); - /// Get a key at a given index. - pub fn get(&self, index: usize) -> Option<&Key> { - self.0.get(index) - } + if t >= last.t { + Some((last.value, &last, None)) + } else { + None + } + } + }) + } - /// Mutably get a key at a given index. - pub fn get_mut(&mut self, index: usize) -> Option> { - self.0.get_mut(index).map(|key| KeyMut { - value: &mut key.value, - interpolation: &mut key.interpolation, - }) + /// Sample a spline at a given time with clamping. + pub fn clamped_sample(&self, t: T) -> Option + where + T: Additive + One + Trigo + Mul + Div + PartialOrd, + V: Additive + Interpolate, + { + self.clamped_sample_with_key(t).map(|(v, _, _)| v) + } + + /// Add a key into the spline. + pub fn add(&mut self, key: Key) + where + T: PartialOrd, + { + self.0.push(key); + self.internal_sort(); + } + + /// Remove a key from the spline. + pub fn remove(&mut self, index: usize) -> Option> { + if index >= self.0.len() { + None + } else { + Some(self.0.remove(index)) } + } + + /// Update a key and return the key already present. + /// + /// The key is updated — if present — with the provided function. + /// + /// # Notes + /// + /// That function makes sense only if you want to change the interpolator (i.e. [`Key::t`]) of + /// your key. If you just want to change the interpolation mode or the carried value, consider + /// using the [`Spline::get_mut`] method instead as it will be way faster. + pub fn replace(&mut self, index: usize, f: F) -> Option> + where + F: FnOnce(&Key) -> Key, + T: PartialOrd, + { + let key = self.remove(index)?; + self.add(f(&key)); + Some(key) + } + + /// Get a key at a given index. + pub fn get(&self, index: usize) -> Option<&Key> { + self.0.get(index) + } + + /// Mutably get a key at a given index. + pub fn get_mut(&mut self, index: usize) -> Option> { + self.0.get_mut(index).map(|key| KeyMut { + value: &mut key.value, + interpolation: &mut key.interpolation, + }) + } } /// A mutable [`Key`]. @@ -304,54 +301,54 @@ impl Spline { /// interpolator value as it would invalidate the internal structure of the [`Spline`]. If you /// want to achieve this, you’re advised to use [`Spline::replace`]. pub struct KeyMut<'a, T, V> { - /// Carried value. - pub value: &'a mut V, - /// Interpolation mode to use for that key. - pub interpolation: &'a mut Interpolation, + /// Carried value. + pub value: &'a mut V, + /// Interpolation mode to use for that key. + pub interpolation: &'a mut Interpolation, } // Normalize a time ([0;1]) given two control points. #[inline(always)] pub(crate) fn normalize_time(t: T, cp: &Key, cp1: &Key) -> T where - T: Additive + Div + PartialEq, + T: Additive + Div + PartialEq, { - assert!(cp1.t != cp.t, "overlapping keys"); - (t - cp.t) / (cp1.t - cp.t) + assert!(cp1.t != cp.t, "overlapping keys"); + (t - cp.t) / (cp1.t - cp.t) } // Find the lower control point corresponding to a given time. fn search_lower_cp(cps: &[Key], t: T) -> Option where - T: PartialOrd, + T: PartialOrd, { - let mut i = 0; - let len = cps.len(); + let mut i = 0; + let len = cps.len(); - if len < 2 { + if len < 2 { + return None; + } + + loop { + let cp = &cps[i]; + let cp1 = &cps[i + 1]; + + if t >= cp1.t { + if i >= len - 2 { return None; + } + + i += 1; + } else if t < cp.t { + if i == 0 { + return None; + } + + i -= 1; + } else { + break; // found } + } - loop { - let cp = &cps[i]; - let cp1 = &cps[i + 1]; - - if t >= cp1.t { - if i >= len - 2 { - return None; - } - - i += 1; - } else if t < cp.t { - if i == 0 { - return None; - } - - i -= 1; - } else { - break; // found - } - } - - Some(i) + Some(i) } diff --git a/tests/mod.rs b/tests/mod.rs index 3aa3827..4ff6aae 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -7,249 +7,249 @@ use nalgebra as na; #[test] fn step_interpolation_f32() { - let start = Key::new(0., 0., Interpolation::Step(0.)); - let end = Key::new(1., 10., Interpolation::default()); - let spline = Spline::::from_vec(vec![start, end]); + let start = Key::new(0., 0., Interpolation::Step(0.)); + let end = Key::new(1., 10., Interpolation::default()); + let spline = Spline::::from_vec(vec![start, end]); - assert_eq!(spline.sample(0.), Some(10.)); - assert_eq!(spline.sample(0.1), Some(10.)); - assert_eq!(spline.sample(0.2), Some(10.)); - assert_eq!(spline.sample(0.5), Some(10.)); - assert_eq!(spline.sample(0.9), Some(10.)); - assert_eq!(spline.sample(1.), None); - assert_eq!(spline.clamped_sample(1.), Some(10.)); - assert_eq!(spline.sample_with_key(0.2), Some((10., &start, Some(&end)))); - assert_eq!(spline.clamped_sample_with_key(1.), Some((10., &end, None))); + assert_eq!(spline.sample(0.), Some(10.)); + assert_eq!(spline.sample(0.1), Some(10.)); + assert_eq!(spline.sample(0.2), Some(10.)); + assert_eq!(spline.sample(0.5), Some(10.)); + assert_eq!(spline.sample(0.9), Some(10.)); + assert_eq!(spline.sample(1.), None); + assert_eq!(spline.clamped_sample(1.), Some(10.)); + assert_eq!(spline.sample_with_key(0.2), Some((10., &start, Some(&end)))); + assert_eq!(spline.clamped_sample_with_key(1.), Some((10., &end, None))); } #[test] fn step_interpolation_f64() { - let start = Key::new(0., 0., Interpolation::Step(0.)); - let end = Key::new(1., 10., Interpolation::default()); - let spline = Spline::::from_vec(vec![start, end]); + let start = Key::new(0., 0., Interpolation::Step(0.)); + let end = Key::new(1., 10., Interpolation::default()); + let spline = Spline::::from_vec(vec![start, end]); - assert_eq!(spline.sample(0.), Some(10.)); - assert_eq!(spline.sample(0.1), Some(10.)); - assert_eq!(spline.sample(0.2), Some(10.)); - assert_eq!(spline.sample(0.5), Some(10.)); - assert_eq!(spline.sample(0.9), Some(10.)); - assert_eq!(spline.sample(1.), None); - assert_eq!(spline.clamped_sample(1.), Some(10.)); - assert_eq!(spline.sample_with_key(0.2), Some((10., &start, Some(&end)))); - assert_eq!(spline.clamped_sample_with_key(1.), Some((10., &end, None))); + assert_eq!(spline.sample(0.), Some(10.)); + assert_eq!(spline.sample(0.1), Some(10.)); + assert_eq!(spline.sample(0.2), Some(10.)); + assert_eq!(spline.sample(0.5), Some(10.)); + assert_eq!(spline.sample(0.9), Some(10.)); + assert_eq!(spline.sample(1.), None); + assert_eq!(spline.clamped_sample(1.), Some(10.)); + assert_eq!(spline.sample_with_key(0.2), Some((10., &start, Some(&end)))); + assert_eq!(spline.clamped_sample_with_key(1.), Some((10., &end, None))); } #[test] fn step_interpolation_0_5() { - let start = Key::new(0., 0., Interpolation::Step(0.5)); - let end = Key::new(1., 10., Interpolation::default()); - let spline = Spline::from_vec(vec![start, end]); + let start = Key::new(0., 0., Interpolation::Step(0.5)); + let end = Key::new(1., 10., Interpolation::default()); + let spline = Spline::from_vec(vec![start, end]); - assert_eq!(spline.sample(0.), Some(0.)); - assert_eq!(spline.sample(0.1), Some(0.)); - assert_eq!(spline.sample(0.2), Some(0.)); - assert_eq!(spline.sample(0.5), Some(10.)); - assert_eq!(spline.sample(0.9), Some(10.)); - assert_eq!(spline.sample(1.), None); - assert_eq!(spline.clamped_sample(1.), Some(10.)); + assert_eq!(spline.sample(0.), Some(0.)); + assert_eq!(spline.sample(0.1), Some(0.)); + assert_eq!(spline.sample(0.2), Some(0.)); + assert_eq!(spline.sample(0.5), Some(10.)); + assert_eq!(spline.sample(0.9), Some(10.)); + assert_eq!(spline.sample(1.), None); + assert_eq!(spline.clamped_sample(1.), Some(10.)); } #[test] fn step_interpolation_0_75() { - let start = Key::new(0., 0., Interpolation::Step(0.75)); - let end = Key::new(1., 10., Interpolation::default()); - let spline = Spline::from_vec(vec![start, end]); + let start = Key::new(0., 0., Interpolation::Step(0.75)); + let end = Key::new(1., 10., Interpolation::default()); + let spline = Spline::from_vec(vec![start, end]); - assert_eq!(spline.sample(0.), Some(0.)); - assert_eq!(spline.sample(0.1), Some(0.)); - assert_eq!(spline.sample(0.2), Some(0.)); - assert_eq!(spline.sample(0.5), Some(0.)); - assert_eq!(spline.sample(0.9), Some(10.)); - assert_eq!(spline.sample(1.), None); - assert_eq!(spline.clamped_sample(1.), Some(10.)); + assert_eq!(spline.sample(0.), Some(0.)); + assert_eq!(spline.sample(0.1), Some(0.)); + assert_eq!(spline.sample(0.2), Some(0.)); + assert_eq!(spline.sample(0.5), Some(0.)); + assert_eq!(spline.sample(0.9), Some(10.)); + assert_eq!(spline.sample(1.), None); + assert_eq!(spline.clamped_sample(1.), Some(10.)); } #[test] fn step_interpolation_1() { - let start = Key::new(0., 0., Interpolation::Step(1.)); - let end = Key::new(1., 10., Interpolation::default()); - let spline = Spline::from_vec(vec![start, end]); + let start = Key::new(0., 0., Interpolation::Step(1.)); + let end = Key::new(1., 10., Interpolation::default()); + let spline = Spline::from_vec(vec![start, end]); - assert_eq!(spline.sample(0.), Some(0.)); - assert_eq!(spline.sample(0.1), Some(0.)); - assert_eq!(spline.sample(0.2), Some(0.)); - assert_eq!(spline.sample(0.5), Some(0.)); - assert_eq!(spline.sample(0.9), Some(0.)); - assert_eq!(spline.sample(1.), None); - assert_eq!(spline.clamped_sample(1.), Some(10.)); + assert_eq!(spline.sample(0.), Some(0.)); + assert_eq!(spline.sample(0.1), Some(0.)); + assert_eq!(spline.sample(0.2), Some(0.)); + assert_eq!(spline.sample(0.5), Some(0.)); + assert_eq!(spline.sample(0.9), Some(0.)); + assert_eq!(spline.sample(1.), None); + assert_eq!(spline.clamped_sample(1.), Some(10.)); } #[test] fn linear_interpolation() { - let start = Key::new(0., 0., Interpolation::Linear); - let end = Key::new(1., 10., Interpolation::default()); - let spline = Spline::from_vec(vec![start, end]); + let start = Key::new(0., 0., Interpolation::Linear); + let end = Key::new(1., 10., Interpolation::default()); + let spline = Spline::from_vec(vec![start, end]); - assert_eq!(spline.sample(0.), Some(0.)); - assert_eq!(spline.sample(0.1), Some(1.)); - assert_eq!(spline.sample(0.2), Some(2.)); - assert_eq!(spline.sample(0.5), Some(5.)); - assert_eq!(spline.sample(0.9), Some(9.)); - assert_eq!(spline.sample(1.), None); - assert_eq!(spline.clamped_sample(1.), Some(10.)); + assert_eq!(spline.sample(0.), Some(0.)); + assert_eq!(spline.sample(0.1), Some(1.)); + assert_eq!(spline.sample(0.2), Some(2.)); + assert_eq!(spline.sample(0.5), Some(5.)); + assert_eq!(spline.sample(0.9), Some(9.)); + assert_eq!(spline.sample(1.), None); + assert_eq!(spline.clamped_sample(1.), Some(10.)); } #[test] fn linear_interpolation_several_keys() { - let start = Key::new(0., 0., Interpolation::Linear); - let k1 = Key::new(1., 5., Interpolation::Linear); - let k2 = Key::new(2., 0., Interpolation::Linear); - let k3 = Key::new(3., 1., Interpolation::Linear); - let k4 = Key::new(10., 2., Interpolation::Linear); - let end = Key::new(11., 4., Interpolation::default()); - let spline = Spline::from_vec(vec![start, k1, k2, k3, k4, end]); + let start = Key::new(0., 0., Interpolation::Linear); + let k1 = Key::new(1., 5., Interpolation::Linear); + let k2 = Key::new(2., 0., Interpolation::Linear); + let k3 = Key::new(3., 1., Interpolation::Linear); + let k4 = Key::new(10., 2., Interpolation::Linear); + let end = Key::new(11., 4., Interpolation::default()); + let spline = Spline::from_vec(vec![start, k1, k2, k3, k4, end]); - assert_eq!(spline.sample(0.), Some(0.)); - assert_eq!(spline.sample(0.1), Some(0.5)); - assert_eq!(spline.sample(0.2), Some(1.)); - assert_eq!(spline.sample(0.5), Some(2.5)); - assert_eq!(spline.sample(0.9), Some(4.5)); - assert_eq!(spline.sample(1.), Some(5.)); - assert_eq!(spline.sample(1.5), Some(2.5)); - assert_eq!(spline.sample(2.), Some(0.)); - assert_eq!(spline.sample(2.75), Some(0.75)); - assert_eq!(spline.sample(3.), Some(1.)); - assert_eq!(spline.sample(6.5), Some(1.5)); - assert_eq!(spline.sample(10.), Some(2.)); - assert_eq!(spline.clamped_sample(11.), Some(4.)); + assert_eq!(spline.sample(0.), Some(0.)); + assert_eq!(spline.sample(0.1), Some(0.5)); + assert_eq!(spline.sample(0.2), Some(1.)); + assert_eq!(spline.sample(0.5), Some(2.5)); + assert_eq!(spline.sample(0.9), Some(4.5)); + assert_eq!(spline.sample(1.), Some(5.)); + assert_eq!(spline.sample(1.5), Some(2.5)); + assert_eq!(spline.sample(2.), Some(0.)); + assert_eq!(spline.sample(2.75), Some(0.75)); + assert_eq!(spline.sample(3.), Some(1.)); + assert_eq!(spline.sample(6.5), Some(1.5)); + assert_eq!(spline.sample(10.), Some(2.)); + assert_eq!(spline.clamped_sample(11.), Some(4.)); } #[test] fn several_interpolations_several_keys() { - let start = Key::new(0., 0., Interpolation::Step(0.5)); - let k1 = Key::new(1., 5., Interpolation::Linear); - let k2 = Key::new(2., 0., Interpolation::Step(0.1)); - let k3 = Key::new(3., 1., Interpolation::Linear); - let k4 = Key::new(10., 2., Interpolation::Linear); - let end = Key::new(11., 4., Interpolation::default()); - let spline = Spline::from_vec(vec![start, k1, k2, k3, k4, end]); + let start = Key::new(0., 0., Interpolation::Step(0.5)); + let k1 = Key::new(1., 5., Interpolation::Linear); + let k2 = Key::new(2., 0., Interpolation::Step(0.1)); + let k3 = Key::new(3., 1., Interpolation::Linear); + let k4 = Key::new(10., 2., Interpolation::Linear); + let end = Key::new(11., 4., Interpolation::default()); + let spline = Spline::from_vec(vec![start, k1, k2, k3, k4, end]); - assert_eq!(spline.sample(0.), Some(0.)); - assert_eq!(spline.sample(0.1), Some(0.)); - assert_eq!(spline.sample(0.2), Some(0.)); - assert_eq!(spline.sample(0.5), Some(5.)); - assert_eq!(spline.sample(0.9), Some(5.)); - assert_eq!(spline.sample(1.), Some(5.)); - assert_eq!(spline.sample(1.5), Some(2.5)); - assert_eq!(spline.sample(2.), Some(0.)); - assert_eq!(spline.sample(2.05), Some(0.)); - assert_eq!(spline.sample(2.099), Some(0.)); - assert_eq!(spline.sample(2.75), Some(1.)); - assert_eq!(spline.sample(3.), Some(1.)); - assert_eq!(spline.sample(6.5), Some(1.5)); - assert_eq!(spline.sample(10.), Some(2.)); - assert_eq!(spline.clamped_sample(11.), Some(4.)); + assert_eq!(spline.sample(0.), Some(0.)); + assert_eq!(spline.sample(0.1), Some(0.)); + assert_eq!(spline.sample(0.2), Some(0.)); + assert_eq!(spline.sample(0.5), Some(5.)); + assert_eq!(spline.sample(0.9), Some(5.)); + assert_eq!(spline.sample(1.), Some(5.)); + assert_eq!(spline.sample(1.5), Some(2.5)); + assert_eq!(spline.sample(2.), Some(0.)); + assert_eq!(spline.sample(2.05), Some(0.)); + assert_eq!(spline.sample(2.099), Some(0.)); + assert_eq!(spline.sample(2.75), Some(1.)); + assert_eq!(spline.sample(3.), Some(1.)); + assert_eq!(spline.sample(6.5), Some(1.5)); + assert_eq!(spline.sample(10.), Some(2.)); + assert_eq!(spline.clamped_sample(11.), Some(4.)); } #[cfg(feature = "cgmath")] #[test] fn stroke_bezier_straight() { - use float_cmp::approx_eq; + use float_cmp::approx_eq; - let keys = vec![ - Key::new( - 0.0, - cg::Vector2::new(0., 1.), - Interpolation::StrokeBezier(cg::Vector2::new(0., 1.), cg::Vector2::new(0., 1.)), - ), - Key::new( - 5.0, - cg::Vector2::new(5., 1.), - Interpolation::StrokeBezier(cg::Vector2::new(5., 1.), cg::Vector2::new(5., 1.)), - ), - ]; - let spline = Spline::from_vec(keys); + let keys = vec![ + Key::new( + 0.0, + cg::Vector2::new(0., 1.), + Interpolation::StrokeBezier(cg::Vector2::new(0., 1.), cg::Vector2::new(0., 1.)), + ), + Key::new( + 5.0, + cg::Vector2::new(5., 1.), + Interpolation::StrokeBezier(cg::Vector2::new(5., 1.), cg::Vector2::new(5., 1.)), + ), + ]; + let spline = Spline::from_vec(keys); - assert!(approx_eq!(f32, spline.clamped_sample(0.0).unwrap().y, 1.)); - assert!(approx_eq!(f32, spline.clamped_sample(1.0).unwrap().y, 1.)); - assert!(approx_eq!(f32, spline.clamped_sample(2.0).unwrap().y, 1.)); - assert!(approx_eq!(f32, spline.clamped_sample(3.0).unwrap().y, 1.)); - assert!(approx_eq!(f32, spline.clamped_sample(4.0).unwrap().y, 1.)); - assert!(approx_eq!(f32, spline.clamped_sample(5.0).unwrap().y, 1.)); + assert!(approx_eq!(f32, spline.clamped_sample(0.0).unwrap().y, 1.)); + assert!(approx_eq!(f32, spline.clamped_sample(1.0).unwrap().y, 1.)); + assert!(approx_eq!(f32, spline.clamped_sample(2.0).unwrap().y, 1.)); + assert!(approx_eq!(f32, spline.clamped_sample(3.0).unwrap().y, 1.)); + assert!(approx_eq!(f32, spline.clamped_sample(4.0).unwrap().y, 1.)); + assert!(approx_eq!(f32, spline.clamped_sample(5.0).unwrap().y, 1.)); } #[cfg(feature = "cgmath")] #[test] fn cgmath_vector_interpolation() { - use splines::Interpolate; + use splines::Interpolate; - let start = cg::Vector2::new(0.0, 0.0); - let mid = cg::Vector2::new(0.5, 0.5); - let end = cg::Vector2::new(1.0, 1.0); + let start = cg::Vector2::new(0.0, 0.0); + let mid = cg::Vector2::new(0.5, 0.5); + let end = cg::Vector2::new(1.0, 1.0); - assert_eq!(Interpolate::lerp(start, end, 0.0), start); - assert_eq!(Interpolate::lerp(start, end, 1.0), end); - assert_eq!(Interpolate::lerp(start, end, 0.5), mid); + assert_eq!(Interpolate::lerp(start, end, 0.0), start); + assert_eq!(Interpolate::lerp(start, end, 1.0), end); + assert_eq!(Interpolate::lerp(start, end, 0.5), mid); } #[cfg(feature = "nalgebra")] #[test] fn nalgebra_vector_interpolation() { - use splines::Interpolate; + use splines::Interpolate; - let start = na::Vector2::new(0.0, 0.0); - let mid = na::Vector2::new(0.5, 0.5); - let end = na::Vector2::new(1.0, 1.0); + let start = na::Vector2::new(0.0, 0.0); + let mid = na::Vector2::new(0.5, 0.5); + let end = na::Vector2::new(1.0, 1.0); - assert_eq!(Interpolate::lerp(start, end, 0.0), start); - assert_eq!(Interpolate::lerp(start, end, 1.0), end); - assert_eq!(Interpolate::lerp(start, end, 0.5), mid); + assert_eq!(Interpolate::lerp(start, end, 0.0), start); + assert_eq!(Interpolate::lerp(start, end, 1.0), end); + assert_eq!(Interpolate::lerp(start, end, 0.5), mid); } #[test] fn add_key_empty() { - let mut spline: Spline = Spline::from_vec(vec![]); - spline.add(Key::new(0., 0., Interpolation::Linear)); + let mut spline: Spline = Spline::from_vec(vec![]); + spline.add(Key::new(0., 0., Interpolation::Linear)); - assert_eq!(spline.keys(), &[Key::new(0., 0., Interpolation::Linear)]); + assert_eq!(spline.keys(), &[Key::new(0., 0., Interpolation::Linear)]); } #[test] fn add_key() { - let start = Key::new(0., 0., Interpolation::Step(0.5)); - let k1 = Key::new(1., 5., Interpolation::Linear); - let k2 = Key::new(2., 0., Interpolation::Step(0.1)); - let k3 = Key::new(3., 1., Interpolation::Linear); - let k4 = Key::new(10., 2., Interpolation::Linear); - let end = Key::new(11., 4., Interpolation::default()); - let new = Key::new(2.4, 40., Interpolation::Linear); - let mut spline = Spline::from_vec(vec![start, k1, k2.clone(), k3, k4, end]); + let start = Key::new(0., 0., Interpolation::Step(0.5)); + let k1 = Key::new(1., 5., Interpolation::Linear); + let k2 = Key::new(2., 0., Interpolation::Step(0.1)); + let k3 = Key::new(3., 1., Interpolation::Linear); + let k4 = Key::new(10., 2., Interpolation::Linear); + let end = Key::new(11., 4., Interpolation::default()); + let new = Key::new(2.4, 40., Interpolation::Linear); + let mut spline = Spline::from_vec(vec![start, k1, k2.clone(), k3, k4, end]); - assert_eq!(spline.keys(), &[start, k1, k2, k3, k4, end]); - spline.add(new); - assert_eq!(spline.keys(), &[start, k1, k2, new, k3, k4, end]); + assert_eq!(spline.keys(), &[start, k1, k2, k3, k4, end]); + spline.add(new); + assert_eq!(spline.keys(), &[start, k1, k2, new, k3, k4, end]); } #[test] fn remove_element_empty() { - let mut spline: Spline = Spline::from_vec(vec![]); - let removed = spline.remove(0); + let mut spline: Spline = Spline::from_vec(vec![]); + let removed = spline.remove(0); - assert_eq!(removed, None); - assert!(spline.is_empty()); + assert_eq!(removed, None); + assert!(spline.is_empty()); } #[test] fn remove_element() { - let start = Key::new(0., 0., Interpolation::Step(0.5)); - let k1 = Key::new(1., 5., Interpolation::Linear); - let k2 = Key::new(2., 0., Interpolation::Step(0.1)); - let k3 = Key::new(3., 1., Interpolation::Linear); - let k4 = Key::new(10., 2., Interpolation::Linear); - let end = Key::new(11., 4., Interpolation::default()); - let mut spline = Spline::from_vec(vec![start, k1, k2.clone(), k3, k4, end]); - let removed = spline.remove(2); + let start = Key::new(0., 0., Interpolation::Step(0.5)); + let k1 = Key::new(1., 5., Interpolation::Linear); + let k2 = Key::new(2., 0., Interpolation::Step(0.1)); + let k3 = Key::new(3., 1., Interpolation::Linear); + let k4 = Key::new(10., 2., Interpolation::Linear); + let end = Key::new(11., 4., Interpolation::default()); + let mut spline = Spline::from_vec(vec![start, k1, k2.clone(), k3, k4, end]); + let removed = spline.remove(2); - assert_eq!(removed, Some(k2)); - assert_eq!(spline.len(), 5); + assert_eq!(removed, Some(k2)); + assert_eq!(spline.len(), 5); }