///|
/// Move a track in time while preserving its segment curves.
pub fn ScalarTrack::shift(
self : ScalarTrack,
offset : Double,
) -> ScalarTrack raise MotionError {
let frames : Array[Keyframe] = []
for frame in self.frames {
frames.push({
time: frame.time + offset,
value: frame.value,
curve: frame.curve,
})
}
ScalarTrack::new(frames)
}
///|
/// Scale a track's time axis around its first keyframe.
pub fn ScalarTrack::scale_time(
self : ScalarTrack,
factor : Double,
) -> ScalarTrack raise MotionError {
if factor <= 0.0 {
raise MotionError::InvalidDuration(factor)
}
let origin = self.start_time()
let frames : Array[Keyframe] = []
for frame in self.frames {
frames.push({
time: origin + (frame.time - origin) * factor,
value: frame.value,
curve: frame.curve,
})
}
ScalarTrack::new(frames)
}
///|
/// Transform values without changing timing or curves.
pub fn ScalarTrack::map_values(
self : ScalarTrack,
mapper : (Double) -> Double,
) -> ScalarTrack raise MotionError {
let frames : Array[Keyframe] = []
for frame in self.frames {
let value = mapper(frame.value)
ensure_finite(value)
frames.push({ time: frame.time, value, curve: frame.curve })
}
ScalarTrack::new(frames)
}
///|
/// Return a track with a replacement curve on every segment.
pub fn ScalarTrack::with_curve(
self : ScalarTrack,
curve : Curve,
) -> ScalarTrack raise MotionError {
let frames : Array[Keyframe] = []
for frame in self.frames {
frames.push({ time: frame.time, value: frame.value, curve })
}
ScalarTrack::new(frames)
}
///|
/// Copy a time range, adding interpolated boundary frames when needed.
pub fn ScalarTrack::trim(
self : ScalarTrack,
start : Double,
end : Double,
) -> ScalarTrack raise MotionError {
if end < start {
raise MotionError::InvalidTime(end)
}
let first_value = self.sample(start)
let last_value = self.sample(end)
let frames : Array[Keyframe] = []
frames.push({ time: start, value: first_value, curve: self.frames[0].curve })
for frame in self.frames {
if frame.time > start && frame.time < end {
frames.push(frame)
}
}
if end > start {
frames.push({
time: end,
value: last_value,
curve: self.frames[self.frames.length() - 1].curve,
})
}
ScalarTrack::new(frames)
}
///|
pub fn ScalarTrack::value_range(
self : ScalarTrack,
samples_per_segment : Int,
) -> (Double, Double) {
let count = if samples_per_segment < 2 { 2 } else { samples_per_segment }
let mut minimum = self.frames[0].value
let mut maximum = minimum
for segment in 0..<(self.frames.length() - 1) {
let left = self.frames[segment]
let right = self.frames[segment + 1]
for i in 0.. maximum {
maximum = value
}
}
}
(minimum, maximum)
}
///|
pub fn ScalarTrack::sample_values(
self : ScalarTrack,
times : Array[Double],
mode? : Extrapolation = Clamp,
) -> Array[Double] {
let result : Array[Double] = []
for time in times {
result.push(self.sample(time, mode~))
}
result
}