///|
/// A piecewise curve used to choreograph a multi-stage motion.
pub struct CurveChain {
curves : Array[Curve]
weights : Array[Double]
total_weight : Double
} derive(Debug)
///|
pub fn CurveChain::new(
curves : Array[Curve],
weights? : Array[Double],
) -> CurveChain raise MotionError {
if curves.length() == 0 {
raise MotionError::EmptyTrack
}
let selected = match weights {
Some(values) => {
if values.length() != curves.length() {
raise MotionError::InvalidSampleCount(values.length())
}
values.copy()
}
None => Array::make(curves.length(), 1.0)
}
let mut total = 0.0
for value in selected {
if value <= 0.0 || value.is_nan() || value.is_inf() {
raise MotionError::InvalidTime(value)
}
total = total + value
}
{ curves: curves.copy(), weights: selected, total_weight: total }
}
///|
pub fn CurveChain::length(self : CurveChain) -> Int {
self.curves.length()
}
///|
fn CurveChain::locate(self : CurveChain, t : Double) -> (Int, Double) {
let distance = clamp01(t) * self.total_weight
let mut cursor = 0.0
for i in 0.. Double {
let (index, segment_t) = self.locate(t)
let segment_count = self.curves.length().to_double()
(index.to_double() + self.curves[index].apply(segment_t)) / segment_count
}
///|
pub fn CurveChain::derivative(self : CurveChain, t : Double) -> Double {
let (index, segment_t) = self.locate(t)
let segment_count = self.curves.length().to_double()
self.curves[index].derivative(segment_t) / segment_count
}
///|
pub fn CurveChain::sample_many(
self : CurveChain,
count : Int,
) -> Array[Double] raise MotionError {
if count < 2 {
raise MotionError::InvalidSampleCount(count)
}
let result : Array[Double] = []
for i in 0..