use super::*;
pub struct Clutch {
connected: bool,
node_a: NodeID,
node_b: NodeID,
}
impl Clutch {
#[inline]
pub const fn new(node_a: NodeID, node_b: NodeID) -> Self {
Self {
connected: false,
node_a,
node_b,
}
}
#[inline]
pub const fn set_connected(&mut self, value: bool) {
self.connected = value;
}
}
impl<E> DeviceUpdatable<E> for Clutch {
fn device_update<const N: usize>(&mut self, system: &mut System<N>) -> NothingOrError<E> {
if self.connected {
system.set_state_local(self.node_a, system.get_state_connected(self.node_b));
system.set_state_local(self.node_b, system.get_state_connected(self.node_a));
} else {
system.set_state_local(self.node_a, None);
system.set_state_local(self.node_b, None);
}
Ok(())
}
}
pub struct Differential {
node_left: NodeID,
node_right: NodeID,
node_sum: NodeID,
}
impl Differential {
#[inline]
pub const fn new(node_left: NodeID, node_right: NodeID, node_sum: NodeID) -> Self {
Self {
node_left,
node_right,
node_sum,
}
}
}
impl<E> DeviceUpdatable<E> for Differential {
fn device_update<const N: usize>(&mut self, system: &mut System<N>) -> NothingOrError<E> {
let state_left = system.get_state_connected(self.node_left);
let state_right = system.get_state_connected(self.node_right);
let state_sum = system.get_state_connected(self.node_sum);
system.set_state_local(
self.node_sum,
if let Some(state_left) = state_left
&& let Some(state_right) = state_right
{
Some(state_left + state_right)
} else {
None
},
);
system.set_state_local(
self.node_right,
if let Some(state_left) = state_left
&& let Some(state_sum) = state_sum
{
Some(state_sum - state_left)
} else {
None
},
);
system.set_state_local(
self.node_left,
if let Some(state_right) = state_right
&& let Some(state_sum) = state_sum
{
Some(state_sum - state_right)
} else {
None
},
);
Ok(())
}
}
pub struct GearTrain {
node_a: NodeID,
node_b: NodeID,
ratio: Dimensionless<f32>,
}
impl GearTrain {
#[inline]
pub const fn new(node_a: NodeID, node_b: NodeID, ratio: Dimensionless<f32>) -> Self {
Self {
node_a,
node_b,
ratio,
}
}
pub const fn from_teeth<const N: usize>(
node_a: NodeID,
node_b: NodeID,
teeth: [f32; N],
) -> Self {
if N < 2 {
panic!("At least 2 gears are required to construct an RRTK GearTrain.");
}
let ratio = teeth[0] / teeth[N - 1];
let direction = if N.is_multiple_of(2) { -1.0 } else { 1.0 };
Self::new(node_a, node_b, Dimensionless::new(ratio * direction))
}
}
impl<E> DeviceUpdatable<E> for GearTrain {
fn device_update<const N: usize>(&mut self, system: &mut System<N>) -> NothingOrError<E> {
system.set_state_local(
self.node_b,
if let Some(a_state) = system.get_state_connected(self.node_a) {
Some(a_state * self.ratio)
} else {
None
},
);
system.set_state_local(
self.node_a,
if let Some(b_state) = system.get_state_connected(self.node_b) {
Some(b_state / self.ratio)
} else {
None
},
);
Ok(())
}
}
#[test]
fn ratio_from_teeth() {
let mut system = System::<2>::new();
let node_a = system.new_node().unwrap();
let node_b = system.new_node().unwrap();
let gear_train_1 = GearTrain::from_teeth(node_a, node_b, [100.0, 50.0]);
assert_eq!(gear_train_1.ratio.into_inner(), -2.0);
let gear_train_2 = GearTrain::from_teeth(node_a, node_b, [20.0, 8.0, 60.0]);
assert_eq!(gear_train_2.ratio.into_inner(), 1.0 / 3.0);
}
#[test]
#[should_panic]
fn not_enough_teeth() {
let mut system = System::<2>::new();
#[rustfmt::skip]
let node_a = if let Some(node) = system.new_node() { node } else { return; };
#[rustfmt::skip]
let node_b = if let Some(node) = system.new_node() { node } else { return; };
let _gear_train = GearTrain::from_teeth(node_a, node_b, [100.0]);
}