#![allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TrackAxis {
PosX,
NegX,
PosY,
NegY,
PosZ,
NegZ,
}
#[derive(Debug, Clone)]
pub struct TrackToConstraint {
pub target_position: [f32; 3],
pub track_axis: TrackAxis,
pub up_axis: TrackAxis,
pub influence: f32,
pub label: String,
}
pub fn new_track_to(target: [f32; 3], label: &str) -> TrackToConstraint {
TrackToConstraint {
target_position: target,
track_axis: TrackAxis::PosY,
up_axis: TrackAxis::PosZ,
influence: 1.0,
label: label.to_owned(),
}
}
pub fn set_track_axis(c: &mut TrackToConstraint, axis: TrackAxis) {
c.track_axis = axis;
}
pub fn set_up_axis(c: &mut TrackToConstraint, axis: TrackAxis) {
c.up_axis = axis;
}
fn normalize3(v: [f32; 3]) -> [f32; 3] {
let len = (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt();
if len < 1e-8 {
return [0.0, 1.0, 0.0];
}
[v[0] / len, v[1] / len, v[2] / len]
}
pub fn track_direction(c: &TrackToConstraint, origin: [f32; 3]) -> [f32; 3] {
let d = [
c.target_position[0] - origin[0],
c.target_position[1] - origin[1],
c.target_position[2] - origin[2],
];
normalize3(d)
}
pub fn target_distance(c: &TrackToConstraint, origin: [f32; 3]) -> f32 {
let d = [
c.target_position[0] - origin[0],
c.target_position[1] - origin[1],
c.target_position[2] - origin[2],
];
(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]).sqrt()
}
pub fn axis_name(axis: TrackAxis) -> &'static str {
match axis {
TrackAxis::PosX => "+X",
TrackAxis::NegX => "-X",
TrackAxis::PosY => "+Y",
TrackAxis::NegY => "-Y",
TrackAxis::PosZ => "+Z",
TrackAxis::NegZ => "-Z",
}
}
pub fn track_to_json(c: &TrackToConstraint) -> String {
format!(
r#"{{"label":"{}", "track_axis":"{}", "up_axis":"{}", "influence":{:.4}}}"#,
c.label,
axis_name(c.track_axis),
axis_name(c.up_axis),
c.influence
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_constraint_default_track_axis_is_pos_y() {
let c = new_track_to([0.0; 3], "cam");
assert_eq!(c.track_axis, TrackAxis::PosY);
}
#[test]
fn new_constraint_default_influence_one() {
let c = new_track_to([0.0; 3], "cam");
assert!((c.influence - 1.0).abs() < 1e-6);
}
#[test]
fn set_track_axis_changes_axis() {
let mut c = new_track_to([0.0; 3], "cam");
set_track_axis(&mut c, TrackAxis::PosZ);
assert_eq!(c.track_axis, TrackAxis::PosZ);
}
#[test]
fn track_direction_normalized() {
let c = new_track_to([3.0, 4.0, 0.0], "t");
let d = track_direction(&c, [0.0, 0.0, 0.0]);
let len = (d[0] * d[0] + d[1] * d[1] + d[2] * d[2]).sqrt();
assert!((len - 1.0).abs() < 1e-5);
}
#[test]
fn target_distance_correct() {
let c = new_track_to([3.0, 4.0, 0.0], "t");
assert!((target_distance(&c, [0.0; 3]) - 5.0).abs() < 1e-4);
}
#[test]
fn axis_name_pos_x() {
assert_eq!(axis_name(TrackAxis::PosX), "+X");
}
#[test]
fn axis_name_neg_z() {
assert_eq!(axis_name(TrackAxis::NegZ), "-Z");
}
#[test]
fn json_contains_label() {
let c = new_track_to([1.0, 0.0, 0.0], "myLabel");
let j = track_to_json(&c);
assert!(j.contains("myLabel"));
}
#[test]
fn set_up_axis_updates_field() {
let mut c = new_track_to([0.0; 3], "u");
set_up_axis(&mut c, TrackAxis::NegY);
assert_eq!(c.up_axis, TrackAxis::NegY);
}
}