Compare commits

..

No commits in common. "master" and "4.1" have entirely different histories.
master ... 4.1

7 changed files with 69 additions and 118 deletions

View File

@ -1,9 +1,7 @@
# Changelog # Changelog
* [4.3.1](#431) <!-- vim-markdown-toc GFM -->
* [4.3](#43)
* [4.2](#42)
* [4.1.1](#411)
* [4.1](#41) * [4.1](#41)
* [4.0.3](#403) * [4.0.3](#403)
* [4.0.2](#402) * [4.0.2](#402)
@ -43,38 +41,7 @@
* [0.1.1](#011) * [0.1.1](#011)
* [0.1](#01) * [0.1](#01)
# 4.3.1 <!-- vim-markdown-toc -->
> Nov 22, 2023
- Add `Default` implementation for `Spline`. [c6ba847](https://github.com/phaazon/splines/commit/c6ba847)
# 4.3
> Sep 23, 2023
- Add support for `glam-0.23` and `glam-0.24`. [cdc48a4](https://github.com/phaazon/splines/commit/cdc48a4)
- Add `Spline::clear` to clear a spline keys without deallocating its internal storage. [eca09f1](https://github.com/phaazon/splines/commit/eca09f1)
# 4.2
> Feb 1, 2023
- Add support for `glam-0.22`.
- Add support for `nalgebra-0.32`.
- Add deprecation lints for `impl-*` feature gates. Those shouldnt be used anymore and the `*` variant should be
preferred. For instance, if you used `impl-cgmath`, you should just use the `cgmath` feature gate now.
# 4.1.1
> Jul 27, 2022
- Internal enhancement of sampling splines by looking for control points. That brings the lookup from _O(N)_ to
_O(log(N))_. That is super embarassing because it should have been the default from the very first commit. Sorry
about that.
- Fix hermite cubic interpolation.
- Add support for `glam-0.21`.
- Add support for `nalgebra-0.31`.
# 4.1 # 4.1

View File

@ -1,6 +1,6 @@
[package] [package]
name = "splines" name = "splines"
version = "4.3.1" version = "4.1.0"
license = "BSD-3-Clause" license = "BSD-3-Clause"
authors = ["Dimitri Sabadie <dimitri.sabadie@gmail.com>"] authors = ["Dimitri Sabadie <dimitri.sabadie@gmail.com>"]
description = "Spline interpolation made easy" description = "Spline interpolation made easy"
@ -13,26 +13,32 @@ readme = "README.md"
edition = "2021" edition = "2021"
[badges]
travis-ci = { repository = "phaazon/splines", branch = "master" }
is-it-maintained-issue-resolution = { repository = "phaazon/splines" }
is-it-maintained-open-issues = { repository = "phaazon/splines" }
maintenance = { status = "actively-developed" }
[features] [features]
default = ["std"] default = ["std"]
impl-cgmath = ["cgmath"] impl-cgmath = ["cgmath"]
impl-glam = ["glam"] impl-glam = ["glam"]
impl-nalgebra = ["nalgebra"] impl-nalgebra = ["nalgebra"]
serialization = ["serde"] serialization = ["serde"]
std = ["nalgebra/std"] std = []
[dependencies] [dependencies]
cgmath = { version = ">=0.17, <0.19", optional = true } cgmath = { version = ">=0.17, <0.19", optional = true }
glam = { version = ">=0.10, <0.25", optional = true } glam = { version = ">=0.10, <0.21", optional = true }
nalgebra = { version = ">=0.21, <0.33", default-features = false, optional = true } nalgebra = { version = ">=0.21, <0.31", optional = true }
serde = { version = "1", features = ["derive"], optional = true } serde = { version = "1", features = ["derive"], optional = true }
[dev-dependencies] [dev-dependencies]
float-cmp = ">=0.6, < 0.10" float-cmp = ">=0.6, < 0.10"
serde_json = "1" serde_json = "1"
[package.metadata.docs.rs] [package.metadata.docs.rs]
features = ["std", "cgmath", "glam", "nalgebra", "serde"] all-features = true
[[example]] [[example]]
name = "hello-world" name = "hello-world"

View File

@ -1,6 +1,6 @@
edition = "2018" edition = "2018"
fn_params_layout = "Tall" fn_args_layout = "Tall"
force_explicit_abi = true force_explicit_abi = true
hard_tabs = false hard_tabs = false
max_width = 100 max_width = 100

View File

@ -112,15 +112,10 @@ macro_rules! impl_Interpolate {
} }
} }
#[cfg(feature = "std")]
fn cosine(t: $t, a: Self, b: Self) -> Self { fn cosine(t: $t, a: Self, b: Self) -> Self {
let cos_nt = (1. - (t * $pi).cos()) * 0.5; let cos_nt = (1. - (t * $pi).cos()) * 0.5;
<Self as $crate::interpolate::Interpolate<$t>>::lerp(cos_nt, a, b) <Self as $crate::interpolate::Interpolate<$t>>::lerp(cos_nt, a, b)
} }
#[cfg(not(feature = "std"))]
fn cosine(t: $t, a: Self, b: Self) -> Self {
unimplemented!();
}
fn lerp(t: $t, a: Self, b: Self) -> Self { fn lerp(t: $t, a: Self, b: Self) -> Self {
a * (1. - t) + b * t a * (1. - t) + b * t
@ -132,16 +127,15 @@ macro_rules! impl_Interpolate {
let three_t = t * 3.; let three_t = t * 3.;
let t2 = t * t; let t2 = t * t;
let t3 = t2 * t; let t3 = t2 * t;
let two_t3 = t2 * two_t; let two_t3 = t3 * two_t;
let two_t2 = t * two_t; let three_t2 = t2 * three_t;
let three_t2 = t * three_t;
// tangents // tangents
let m0 = (b.1 - x.1) / (b.0 - x.0) * (b.0 - a.0); let m0 = (b.1 - x.1) / (b.0 - x.0);
let m1 = (y.1 - a.1) / (y.0 - a.0) * (b.0 - a.0); let m1 = (y.1 - a.1) / (y.0 - a.0);
a.1 * (two_t3 - three_t2 + 1.) a.1 * (two_t3 - three_t2 + 1.)
+ m0 * (t3 - two_t2 + t) + m0 * (t3 - t2 * two_t + t)
+ b.1 * (three_t2 - two_t3) + b.1 * (three_t2 - two_t3)
+ m1 * (t3 - t2) + m1 * (t3 - t2)
} }
@ -181,15 +175,10 @@ macro_rules! impl_InterpolateT {
} }
} }
#[cfg(feature = "std")]
fn cosine(t: $t, a: Self, b: Self) -> Self { fn cosine(t: $t, a: Self, b: Self) -> Self {
let cos_nt = (1. - (t * $pi).cos()) * 0.5; let cos_nt = (1. - (t * $pi).cos()) * 0.5;
<Self as $crate::interpolate::Interpolate<$t>>::lerp(cos_nt, a, b) <Self as $crate::interpolate::Interpolate<$t>>::lerp(cos_nt, a, b)
} }
#[cfg(not(feature = "std"))]
fn cosine(t: $t, a: Self, b: Self) -> Self {
unimplemented!()
}
fn lerp(t: $t, a: Self, b: Self) -> Self { fn lerp(t: $t, a: Self, b: Self) -> Self {
let t = Self::from(t); let t = Self::from(t);
@ -203,16 +192,15 @@ macro_rules! impl_InterpolateT {
let three_t = t * 3.; let three_t = t * 3.;
let t2 = t * t; let t2 = t * t;
let t3 = t2 * t; let t3 = t2 * t;
let two_t3 = t2 * two_t; let two_t3 = t3 * two_t;
let two_t2 = t * two_t; let three_t2 = t2 * three_t;
let three_t2 = t * three_t;
// tangents // tangents
let m0 = (b.1 - x.1) / (Self::from(b.0 - x.0)) * (Self::from(b.0 - a.0)); let m0 = (b.1 - x.1) / (Self::from(b.0 - x.0));
let m1 = (y.1 - a.1) / (Self::from(y.0 - a.0)) * (Self::from(b.0 - a.0)); let m1 = (y.1 - a.1) / (Self::from(y.0 - a.0));
a.1 * (two_t3 - three_t2 + 1.) a.1 * (two_t3 - three_t2 + 1.)
+ m0 * (t3 - two_t2 + t) + m0 * (t3 - t2 * two_t + t)
+ b.1 * (three_t2 - two_t3) + b.1 * (three_t2 - two_t3)
+ m1 * (t3 - t2) + m1 * (t3 - t2)
} }
@ -242,6 +230,6 @@ macro_rules! impl_InterpolateT {
}; };
} }
impl_Interpolate!(f32, f32, f32::consts::PI); impl_Interpolate!(f32, f32, std::f32::consts::PI);
impl_Interpolate!(f64, f64, f64::consts::PI); impl_Interpolate!(f64, f64, std::f64::consts::PI);
impl_InterpolateT!(f32, f64, f32::consts::PI); impl_InterpolateT!(f32, f64, std::f32::consts::PI);

View File

@ -108,17 +108,6 @@
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(alloc))] #![cfg_attr(not(feature = "std"), feature(alloc))]
#![cfg_attr(not(feature = "std"), feature(core_intrinsics))] #![cfg_attr(not(feature = "std"), feature(core_intrinsics))]
#![cfg_attr(
any(
feature = "impl-cgmath",
feature = "impl-glam",
feature = "impl-nalgebra"
),
deprecated(
since = "4.2.0",
note = "you are using an impl-* feature gate; please switch to * (e.g. impl-cgmath becomes cgmath)"
)
)]
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
extern crate alloc; extern crate alloc;

View File

@ -1,27 +1,18 @@
#[cfg(not(feature = "std"))]
use core::f32;
#[cfg(not(feature = "std"))]
use core::f64;
#[cfg(feature = "std")]
use std::f32;
#[cfg(feature = "std")]
use std::f64;
use crate::impl_Interpolate; use crate::impl_Interpolate;
use nalgebra::{Quaternion, Vector1, Vector2, Vector3, Vector4, Vector5, Vector6}; use nalgebra::{Quaternion, Vector1, Vector2, Vector3, Vector4, Vector5, Vector6};
impl_Interpolate!(f32, Vector1<f32>, f32::consts::PI); impl_Interpolate!(f32, Vector1<f32>, std::f32::consts::PI);
impl_Interpolate!(f32, Vector2<f32>, f32::consts::PI); impl_Interpolate!(f32, Vector2<f32>, std::f32::consts::PI);
impl_Interpolate!(f32, Vector3<f32>, f32::consts::PI); impl_Interpolate!(f32, Vector3<f32>, std::f32::consts::PI);
impl_Interpolate!(f32, Vector4<f32>, f32::consts::PI); impl_Interpolate!(f32, Vector4<f32>, std::f32::consts::PI);
impl_Interpolate!(f32, Vector5<f32>, f32::consts::PI); impl_Interpolate!(f32, Vector5<f32>, std::f32::consts::PI);
impl_Interpolate!(f32, Vector6<f32>, f32::consts::PI); impl_Interpolate!(f32, Vector6<f32>, std::f32::consts::PI);
impl_Interpolate!(f32, Quaternion<f32>, f32::consts::PI); impl_Interpolate!(f32, Quaternion<f32>, std::f32::consts::PI);
impl_Interpolate!(f64, Vector1<f64>, f64::consts::PI); impl_Interpolate!(f64, Vector1<f64>, std::f64::consts::PI);
impl_Interpolate!(f64, Vector2<f64>, f64::consts::PI); impl_Interpolate!(f64, Vector2<f64>, std::f64::consts::PI);
impl_Interpolate!(f64, Vector3<f64>, f64::consts::PI); impl_Interpolate!(f64, Vector3<f64>, std::f64::consts::PI);
impl_Interpolate!(f64, Vector4<f64>, f64::consts::PI); impl_Interpolate!(f64, Vector4<f64>, std::f64::consts::PI);
impl_Interpolate!(f64, Vector5<f64>, f64::consts::PI); impl_Interpolate!(f64, Vector5<f64>, std::f64::consts::PI);
impl_Interpolate!(f64, Vector6<f64>, f64::consts::PI); impl_Interpolate!(f64, Vector6<f64>, std::f64::consts::PI);
impl_Interpolate!(f64, Quaternion<f64>, f64::consts::PI); impl_Interpolate!(f64, Quaternion<f64>, std::f64::consts::PI);

View File

@ -1,6 +1,6 @@
//! Spline curves and operations. //! Spline curves and operations.
// #[cfg(feature = "std")] #[cfg(feature = "std")]
use crate::interpolate::{Interpolate, Interpolator}; use crate::interpolate::{Interpolate, Interpolator};
use crate::interpolation::Interpolation; use crate::interpolation::Interpolation;
use crate::key::Key; use crate::key::Key;
@ -27,7 +27,7 @@ use std::cmp::Ordering;
/// for the required interpolation mode, you get `None`. /// for the required interpolation mode, you get `None`.
/// - [`Spline::clamped_sample`]: behaves like [`Spline::sample`] but will return either the first /// - [`Spline::clamped_sample`]: behaves like [`Spline::sample`] but will return either the first
/// or last key if out of bound; it will return `None` if not enough key. /// or last key if out of bound; it will return `None` if not enough key.
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone)]
#[cfg_attr( #[cfg_attr(
any(feature = "serialization", feature = "serde"), any(feature = "serialization", feature = "serde"),
derive(Deserialize, Serialize) derive(Deserialize, Serialize)
@ -56,13 +56,6 @@ impl<T, V> Spline<T, V> {
spline spline
} }
/// Clear the spline by removing all keys. Keeps the underlying allocated storage, so adding
/// new keys should be faster than creating a new [`Spline`]
#[inline]
pub fn clear(&mut self) {
self.0.clear()
}
/// Create a new spline by consuming an `Iterater<Item = Key<T>>`. They keys dont have to be /// Create a new spline by consuming an `Iterater<Item = Key<T>>`. They keys dont have to be
/// sorted. /// sorted.
/// ///
@ -325,20 +318,37 @@ pub struct KeyMut<'a, T, V> {
} }
// Find the lower control point corresponding to a given time. // Find the lower control point corresponding to a given time.
// It has the property to have a timestamp smaller or equal to t
fn search_lower_cp<T, V>(cps: &[Key<T, V>], t: T) -> Option<usize> fn search_lower_cp<T, V>(cps: &[Key<T, V>], t: T) -> Option<usize>
where where
T: PartialOrd, T: PartialOrd,
{ {
let mut i = 0;
let len = cps.len(); let len = cps.len();
if len < 2 { if len < 2 {
return None; return None;
} }
match cps.binary_search_by(|key| key.t.partial_cmp(&t).unwrap()) {
Err(i) if i >= len => None, loop {
Err(i) if i == 0 => None, let cp = &cps[i];
Err(i) => Some(i - 1), let cp1 = &cps[i + 1];
Ok(i) if i == len - 1 => None,
Ok(i) => Some(i), 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)
} }