#![allow(dead_code)]
#[derive(Debug, Clone)]
pub struct McapJoint {
pub name: String,
pub position: [f32; 3],
pub rotation: [f32; 4],
}
#[derive(Debug, Clone)]
pub struct McapFrame {
pub time: f32,
pub joints: Vec<McapJoint>,
}
#[derive(Debug, Clone)]
pub struct McapClip {
pub name: String,
pub fps: f32,
pub frames: Vec<McapFrame>,
}
#[allow(dead_code)]
pub fn new_mcap_clip(name: &str, fps: f32) -> McapClip {
McapClip {
name: name.to_string(),
fps,
frames: Vec::new(),
}
}
#[allow(dead_code)]
pub fn add_frame(clip: &mut McapClip, time: f32, joints: Vec<McapJoint>) {
clip.frames.push(McapFrame { time, joints });
}
#[allow(dead_code)]
pub fn mcap_duration(clip: &McapClip) -> f32 {
clip.frames
.iter()
.map(|f| f.time)
.fold(0.0f32, f32::max)
}
#[allow(dead_code)]
pub fn frame_at_time(clip: &McapClip, time: f32) -> Option<&McapFrame> {
clip.frames
.iter()
.min_by(|a, b| {
(a.time - time)
.abs()
.partial_cmp(&(b.time - time).abs())
.unwrap_or(std::cmp::Ordering::Equal)
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_clip_empty() {
let c = new_mcap_clip("test", 30.0);
assert_eq!(c.name, "test");
assert!(c.frames.is_empty());
}
#[test]
fn test_fps_stored() {
let c = new_mcap_clip("clip", 60.0);
assert!((c.fps - 60.0).abs() < 1e-6);
}
#[test]
fn test_add_frame() {
let mut c = new_mcap_clip("clip", 30.0);
add_frame(&mut c, 0.0, vec![]);
assert_eq!(c.frames.len(), 1);
}
#[test]
fn test_mcap_duration_empty() {
let c = new_mcap_clip("clip", 30.0);
assert!((mcap_duration(&c)).abs() < 1e-6);
}
#[test]
fn test_mcap_duration_nonempty() {
let mut c = new_mcap_clip("clip", 30.0);
add_frame(&mut c, 0.0, vec![]);
add_frame(&mut c, 1.0, vec![]);
add_frame(&mut c, 2.0, vec![]);
assert!((mcap_duration(&c) - 2.0).abs() < 1e-6);
}
#[test]
fn test_frame_at_time_none_empty() {
let c = new_mcap_clip("clip", 30.0);
assert!(frame_at_time(&c, 1.0).is_none());
}
#[test]
fn test_frame_at_time_exact() {
let mut c = new_mcap_clip("clip", 30.0);
add_frame(&mut c, 0.5, vec![]);
add_frame(&mut c, 1.0, vec![]);
let f = frame_at_time(&c, 1.0).expect("should succeed");
assert!((f.time - 1.0).abs() < 1e-6);
}
#[test]
fn test_frame_at_time_nearest() {
let mut c = new_mcap_clip("clip", 30.0);
add_frame(&mut c, 0.0, vec![]);
add_frame(&mut c, 1.0, vec![]);
let f = frame_at_time(&c, 0.4).expect("should succeed");
assert!((f.time - 0.0).abs() < 1e-6);
}
#[test]
fn test_joint_data_stored() {
let mut c = new_mcap_clip("clip", 30.0);
let j = McapJoint {
name: "Hips".to_string(),
position: [1.0, 2.0, 3.0],
rotation: [0.0, 0.0, 0.0, 1.0],
};
add_frame(&mut c, 0.0, vec![j]);
assert_eq!(c.frames[0].joints[0].name, "Hips");
}
}