use rapier3d::dynamics::{
ImpulseJointHandle, ImpulseJointSet, MultibodyJointHandle, MultibodyJointSet, RigidBodyHandle,
RigidBodySet,
};
use rapier3d::geometry::ColliderSet;
use rapier3d::math::Pose;
use super::handles::{
MjcfActuatorHandle, MjcfBodyHandle, MjcfColliderHandle, MjcfJointHandle, MjcfRobotHandles,
};
use super::mass::move_motor_damping_to_multibody;
use super::options::MjcfMultibodyOptions;
use super::types::MjcfRobot;
impl MjcfRobot {
pub fn insert_using_impulse_joints(
self,
bodies: &mut RigidBodySet,
colliders: &mut ColliderSet,
impulse_joints: &mut ImpulseJointSet,
) -> MjcfRobotHandles<ImpulseJointHandle> {
let world_referenced = self.joints.iter().any(|j| j.link1 == 0 || j.link2 == 0)
|| self
.equality_joints
.iter()
.any(|j| j.link1 == 0 || j.link2 == 0)
|| !self.bodies[0].colliders.is_empty();
let mut body_handles: Vec<Option<MjcfBodyHandle>> = vec![None; self.bodies.len()];
for (i, b) in self.bodies.into_iter().enumerate() {
if i == 0 && !world_referenced {
continue;
}
let handle = bodies.insert(b.body);
let mut col_handles = Vec::with_capacity(b.colliders.len());
for c in b.colliders {
let h = colliders.insert_with_parent(c, handle, bodies);
col_handles.push(MjcfColliderHandle { handle: h });
}
body_handles[i] = Some(MjcfBodyHandle {
body: handle,
colliders: col_handles,
});
}
let mut joint_handles = Vec::with_capacity(self.joints.len());
for j in self.joints {
let l1 = body_handles[j.link1].as_ref().map(|b| b.body);
let l2 = body_handles[j.link2].as_ref().map(|b| b.body);
let (Some(l1), Some(l2)) = (l1, l2) else {
continue;
};
let h = impulse_joints.insert(l1, l2, j.joint, true);
joint_handles.push(MjcfJointHandle {
joint: h,
link1: l1,
link2: l2,
});
}
let mut eq_handles = Vec::with_capacity(self.equality_joints.len());
for eq in self.equality_joints {
let l1 = body_handles[eq.link1].as_ref().map(|b| b.body);
let l2 = body_handles[eq.link2].as_ref().map(|b| b.body);
let (Some(l1), Some(l2)) = (l1, l2) else {
continue;
};
let mut joint = eq.joint;
joint.set_enabled(eq.active);
let h = impulse_joints.insert(l1, l2, joint, true);
eq_handles.push(MjcfJointHandle {
joint: h,
link1: l1,
link2: l2,
});
}
let actuators = self
.actuators
.iter()
.map(|a| MjcfActuatorHandle {
actuator: a.actuator.clone(),
joint: a
.joint_index
.and_then(|i| joint_handles.get(i))
.map(|jh| jh.joint),
})
.collect();
MjcfRobotHandles {
bodies: body_handles,
joints: joint_handles,
equality_joints: eq_handles,
actuators,
}
}
pub fn insert_using_multibody_joints(
self,
bodies: &mut RigidBodySet,
colliders: &mut ColliderSet,
multibody_joints: &mut MultibodyJointSet,
impulse_joints: &mut ImpulseJointSet,
options: MjcfMultibodyOptions,
) -> MjcfRobotHandles<Option<MultibodyJointHandle>> {
let skip_loop_closures = options.contains(MjcfMultibodyOptions::SKIP_LOOP_CLOSURES);
let skip_motors = options.contains(MjcfMultibodyOptions::SKIP_JOINT_MOTORS);
let skip_limits = options.contains(MjcfMultibodyOptions::SKIP_JOINT_LIMITS);
let world_referenced = self.joints.iter().any(|j| j.link1 == 0 || j.link2 == 0)
|| (!skip_loop_closures
&& self
.equality_joints
.iter()
.any(|j| j.link1 == 0 || j.link2 == 0))
|| !self.bodies[0].colliders.is_empty();
let mut body_handles: Vec<Option<MjcfBodyHandle>> = vec![None; self.bodies.len()];
for (i, b) in self.bodies.into_iter().enumerate() {
if i == 0 && !world_referenced {
continue;
}
let handle = bodies.insert(b.body);
let mut col_handles = Vec::with_capacity(b.colliders.len());
for c in b.colliders {
let h = colliders.insert_with_parent(c, handle, bodies);
col_handles.push(MjcfColliderHandle { handle: h });
}
body_handles[i] = Some(MjcfBodyHandle {
body: handle,
colliders: col_handles,
});
}
let mut joint_handles = Vec::with_capacity(self.joints.len());
for j in self.joints {
let l1 = body_handles[j.link1].as_ref().map(|b| b.body);
let l2 = body_handles[j.link2].as_ref().map(|b| b.body);
let (Some(l1), Some(l2)) = (l1, l2) else {
joint_handles.push(MjcfJointHandle {
joint: None,
link1: l1.unwrap_or_else(RigidBodyHandle::invalid),
link2: l2.unwrap_or_else(RigidBodyHandle::invalid),
});
continue;
};
let damping_per_dof = j.damping_per_dof;
let joint_name = j.name.clone();
let mut joint = j.joint;
if skip_limits {
joint.limit_axes = rapier3d::dynamics::JointAxesMask::empty();
}
if skip_motors {
joint.motor_axes = rapier3d::dynamics::JointAxesMask::empty();
}
let h = if options.contains(MjcfMultibodyOptions::JOINTS_ARE_KINEMATIC) {
multibody_joints.insert_kinematic(l1, l2, joint, true)
} else {
multibody_joints.insert(l1, l2, joint, true)
};
if h.is_none() {
log::warn!(
"<joint name={joint_name:?}>: dropped from the multibody chain because it would form a loop (rapier multibodies are tree-structured). Use an `<equality><connect>` or `<equality><weld>` for loop closures.",
);
}
if let Some(h) = h {
if options.contains(MjcfMultibodyOptions::DISABLE_SELF_CONTACTS)
&& let Some((mb, _)) = multibody_joints.get_mut(h)
{
mb.set_self_contacts_enabled(false);
}
if damping_per_dof > 0.0 {
move_motor_damping_to_multibody(multibody_joints, h, damping_per_dof);
}
}
joint_handles.push(MjcfJointHandle {
joint: h,
link1: l1,
link2: l2,
});
}
let mut eq_handles = Vec::with_capacity(self.equality_joints.len());
if !skip_loop_closures {
for eq in self.equality_joints {
let l1 = body_handles[eq.link1].as_ref().map(|b| b.body);
let l2 = body_handles[eq.link2].as_ref().map(|b| b.body);
let (Some(l1), Some(l2)) = (l1, l2) else {
continue;
};
let mut joint = eq.joint;
joint.set_enabled(eq.active);
let h = impulse_joints.insert(l1, l2, joint, true);
eq_handles.push(MjcfJointHandle {
joint: h,
link1: l1,
link2: l2,
});
}
}
let actuators = self
.actuators
.iter()
.map(|a| MjcfActuatorHandle {
actuator: a.actuator.clone(),
joint: a
.joint_index
.and_then(|i| joint_handles.get(i))
.map(|jh| jh.joint),
})
.collect();
MjcfRobotHandles {
bodies: body_handles,
joints: joint_handles,
equality_joints: eq_handles,
actuators,
}
}
pub fn append_transform(&mut self, transform: &Pose) {
for b in self.bodies.iter_mut().skip(1) {
let p = transform * b.body.position();
b.body.set_position(p, true);
}
for j in self.joints.iter_mut() {
if j.link1 == 0 {
let f = j.joint.local_frame1;
j.joint.set_local_frame1(*transform * f);
} else if j.link2 == 0 {
let f = j.joint.local_frame2;
j.joint.set_local_frame2(*transform * f);
}
}
for eq in self.equality_joints.iter_mut() {
if eq.link1 == 0 {
let f = eq.joint.local_frame1;
eq.joint.set_local_frame1(*transform * f);
} else if eq.link2 == 0 {
let f = eq.joint.local_frame2;
eq.joint.set_local_frame2(*transform * f);
}
}
}
}