use rapier3d::prelude::*;
fn settle_angle(stiffness: Real, rest: Real, damping: Real, inertia: Real, steps: usize) -> Real {
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let mut impulse_joints = ImpulseJointSet::new();
let mut multibody_joints = MultibodyJointSet::new();
let base = bodies.insert(RigidBodyBuilder::fixed());
let link = bodies.insert(RigidBodyBuilder::dynamic().additional_mass_properties(
MassProperties::new(Vector::ZERO, 1.0, Vector::new(inertia, inertia, inertia)),
));
let rev = RevoluteJointBuilder::new(Vector::Z);
let handle = multibody_joints.insert(base, link, rev, true).unwrap();
let gravity = Vector::ZERO;
let integration_parameters = IntegrationParameters::default();
let mut pipeline = PhysicsPipeline::new();
let mut islands = IslandManager::new();
let mut broad_phase = DefaultBroadPhase::new();
let mut narrow_phase = NarrowPhase::new();
let mut ccd = CCDSolver::new();
let mut step = |bodies: &mut RigidBodySet, mbj: &mut MultibodyJointSet| {
pipeline.step(
gravity,
&integration_parameters,
&mut islands,
&mut broad_phase,
&mut narrow_phase,
bodies,
&mut colliders,
&mut impulse_joints,
mbj,
&mut ccd,
&(),
&(),
);
};
step(&mut bodies, &mut multibody_joints);
{
let (mb, link_id) = multibody_joints.get_mut(handle).unwrap();
let link_mut = mb.links_mut().nth(link_id).unwrap();
link_mut.joint.set_spring(3, stiffness, rest);
let n = mb.damping().len();
mb.damping_mut()[n - 1] = damping;
}
for _ in 0..steps {
step(&mut bodies, &mut multibody_joints);
}
bodies[link].rotation().to_scaled_axis().z
}
#[test]
fn implicit_spring_drives_joint_to_rest_angle() {
let angle = settle_angle(5.0, 0.6, 1.0, 0.05, 400);
assert!(
(angle - 0.6).abs() < 0.05,
"spring did not settle at its rest angle: angle = {angle}"
);
}
#[test]
fn implicit_spring_is_stable_on_tiny_inertia() {
let angle = settle_angle(50.0, 0.3, 0.01, 1.0e-6, 600);
assert!(angle.is_finite(), "spring blew up on tiny inertia: {angle}");
assert!(
(angle - 0.3).abs() < 0.1,
"spring on tiny inertia didn't reach rest: angle = {angle}"
);
}