use crate::body::BodyHandle;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct JointHandle(pub u64);
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum JointType {
Fixed,
Revolute {
anchor: [f64; 2],
limits: Option<[f64; 2]>,
},
Prismatic {
axis: [f64; 2],
limits: Option<[f64; 2]>,
},
Spring {
rest_length: f64,
stiffness: f64,
damping: f64,
},
Distance { length: f64 },
Wheel {
axis: [f64; 2],
stiffness: f64,
damping: f64,
},
Rope { max_length: f64 },
Mouse {
target: [f64; 3],
stiffness: f64,
damping: f64,
max_force: f64,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct JointMotor {
pub target_velocity: f64,
pub max_force: f64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct JointDesc {
pub body_a: BodyHandle,
pub body_b: BodyHandle,
pub joint_type: JointType,
pub local_anchor_a: [f64; 2],
pub local_anchor_b: [f64; 2],
#[serde(default)]
pub motor: Option<JointMotor>,
#[serde(default)]
pub damping: f64,
#[serde(default)]
pub break_force: Option<f64>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fixed_joint_serde() {
let desc = JointDesc {
body_a: BodyHandle(0),
body_b: BodyHandle(1),
joint_type: JointType::Fixed,
local_anchor_a: [0.0, 0.0],
local_anchor_b: [1.0, 0.0],
motor: None,
damping: 0.0,
break_force: None,
};
let json = serde_json::to_string(&desc).unwrap();
let back: JointDesc = serde_json::from_str(&json).unwrap();
assert_eq!(desc, back);
}
#[test]
fn spring_joint_serde() {
let desc = JointDesc {
body_a: BodyHandle(0),
body_b: BodyHandle(1),
joint_type: JointType::Spring {
rest_length: 2.0,
stiffness: 100.0,
damping: 5.0,
},
local_anchor_a: [0.0, 0.0],
local_anchor_b: [0.0, 0.0],
motor: None,
damping: 0.0,
break_force: None,
};
let json = serde_json::to_string(&desc).unwrap();
let back: JointDesc = serde_json::from_str(&json).unwrap();
assert_eq!(desc, back);
}
#[test]
fn revolute_with_limits() {
let jt = JointType::Revolute {
anchor: [1.0, 0.0],
limits: Some([-1.57, 1.57]),
};
let json = serde_json::to_string(&jt).unwrap();
let back: JointType = serde_json::from_str(&json).unwrap();
assert_eq!(jt, back);
}
#[test]
fn revolute_without_limits() {
let jt = JointType::Revolute {
anchor: [0.0, 0.0],
limits: None,
};
let json = serde_json::to_string(&jt).unwrap();
let back: JointType = serde_json::from_str(&json).unwrap();
assert_eq!(jt, back);
}
#[test]
fn prismatic_joint_serde() {
let jt = JointType::Prismatic {
axis: [1.0, 0.0],
limits: Some([-5.0, 5.0]),
};
let json = serde_json::to_string(&jt).unwrap();
let back: JointType = serde_json::from_str(&json).unwrap();
assert_eq!(jt, back);
}
#[test]
fn distance_joint_serde() {
let jt = JointType::Distance { length: 3.0 };
let json = serde_json::to_string(&jt).unwrap();
let back: JointType = serde_json::from_str(&json).unwrap();
assert_eq!(jt, back);
}
#[test]
fn joint_handle_eq() {
assert_eq!(JointHandle(0), JointHandle(0));
assert_ne!(JointHandle(0), JointHandle(1));
}
#[test]
fn wheel_joint_serde() {
let jt = JointType::Wheel {
axis: [0.0, 1.0],
stiffness: 500.0,
damping: 10.0,
};
let json = serde_json::to_string(&jt).unwrap();
let back: JointType = serde_json::from_str(&json).unwrap();
assert_eq!(jt, back);
}
#[test]
fn rope_joint_serde() {
let jt = JointType::Rope { max_length: 5.0 };
let json = serde_json::to_string(&jt).unwrap();
let back: JointType = serde_json::from_str(&json).unwrap();
assert_eq!(jt, back);
}
#[test]
fn mouse_joint_serde() {
let jt = JointType::Mouse {
target: [10.0, 20.0, 0.0],
stiffness: 1000.0,
damping: 50.0,
max_force: 500.0,
};
let json = serde_json::to_string(&jt).unwrap();
let back: JointType = serde_json::from_str(&json).unwrap();
assert_eq!(jt, back);
}
#[test]
fn break_force_serde() {
let desc = JointDesc {
body_a: BodyHandle(0),
body_b: BodyHandle(1),
joint_type: JointType::Fixed,
local_anchor_a: [0.0, 0.0],
local_anchor_b: [0.0, 0.0],
motor: None,
damping: 0.0,
break_force: Some(100.0),
};
let json = serde_json::to_string(&desc).unwrap();
let back: JointDesc = serde_json::from_str(&json).unwrap();
assert_eq!(desc, back);
assert_eq!(back.break_force, Some(100.0));
}
#[test]
fn break_force_default() {
let json = r#"{"body_a":0,"body_b":1,"joint_type":"Fixed","local_anchor_a":[0.0,0.0],"local_anchor_b":[0.0,0.0]}"#;
let desc: JointDesc = serde_json::from_str(json).unwrap();
assert_eq!(desc.break_force, None);
}
}