rapier3d/dynamics/joint/multibody_joint/
multibody_joint_set.rsuse parry::utils::hashset::HashSet;
use crate::data::{Arena, Coarena, Index};
use crate::dynamics::joint::MultibodyLink;
use crate::dynamics::{GenericJoint, Multibody, MultibodyJoint, RigidBodyHandle};
use crate::geometry::{InteractionGraph, RigidBodyGraphIndex};
use crate::parry::partitioning::IndexedData;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[repr(transparent)]
pub struct MultibodyJointHandle(pub Index);
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[repr(transparent)]
pub struct MultibodyIndex(pub Index);
impl MultibodyJointHandle {
pub fn into_raw_parts(self) -> (u32, u32) {
self.0.into_raw_parts()
}
pub fn from_raw_parts(id: u32, generation: u32) -> Self {
Self(Index::from_raw_parts(id, generation))
}
pub fn invalid() -> Self {
Self(Index::from_raw_parts(
crate::INVALID_U32,
crate::INVALID_U32,
))
}
}
impl Default for MultibodyJointHandle {
fn default() -> Self {
Self::invalid()
}
}
impl IndexedData for MultibodyJointHandle {
fn default() -> Self {
Self(IndexedData::default())
}
fn index(&self) -> usize {
self.0.index()
}
}
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct MultibodyLinkId {
pub(crate) graph_id: RigidBodyGraphIndex,
pub multibody: MultibodyIndex,
pub id: usize,
}
impl Default for MultibodyLinkId {
fn default() -> Self {
Self {
graph_id: RigidBodyGraphIndex::new(crate::INVALID_U32),
multibody: MultibodyIndex(Index::from_raw_parts(
crate::INVALID_U32,
crate::INVALID_U32,
)),
id: 0,
}
}
}
#[derive(Default)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub struct MultibodyJointSet {
pub(crate) multibodies: Arena<Multibody>, pub(crate) rb2mb: Coarena<MultibodyLinkId>,
pub(crate) connectivity_graph: InteractionGraph<RigidBodyHandle, ()>,
pub(crate) to_wake_up: HashSet<RigidBodyHandle>,
}
impl MultibodyJointSet {
pub fn new() -> Self {
Self {
multibodies: Arena::new(),
rb2mb: Coarena::new(),
connectivity_graph: InteractionGraph::new(),
to_wake_up: HashSet::default(),
}
}
pub fn iter(
&self,
) -> impl Iterator<
Item = (
MultibodyJointHandle,
&MultibodyLinkId,
&Multibody,
&MultibodyLink,
),
> {
self.rb2mb
.iter()
.filter(|(_, link)| link.id > 0) .map(|(h, link)| {
let mb = &self.multibodies[link.multibody.0];
(MultibodyJointHandle(h), link, mb, mb.link(link.id).unwrap())
})
}
pub fn insert_kinematic(
&mut self,
body1: RigidBodyHandle,
body2: RigidBodyHandle,
data: impl Into<GenericJoint>,
wake_up: bool,
) -> Option<MultibodyJointHandle> {
self.do_insert(body1, body2, data, true, wake_up)
}
pub fn insert(
&mut self,
body1: RigidBodyHandle,
body2: RigidBodyHandle,
data: impl Into<GenericJoint>,
wake_up: bool,
) -> Option<MultibodyJointHandle> {
self.do_insert(body1, body2, data, false, wake_up)
}
#[profiling::function]
fn do_insert(
&mut self,
body1: RigidBodyHandle,
body2: RigidBodyHandle,
data: impl Into<GenericJoint>,
kinematic: bool,
wake_up: bool,
) -> Option<MultibodyJointHandle> {
let link1 = self.rb2mb.get(body1.0).copied().unwrap_or_else(|| {
let mb_handle = self.multibodies.insert(Multibody::with_root(body1, true));
MultibodyLinkId {
graph_id: self.connectivity_graph.graph.add_node(body1),
multibody: MultibodyIndex(mb_handle),
id: 0,
}
});
let link2 = self.rb2mb.get(body2.0).copied().unwrap_or_else(|| {
let mb_handle = self.multibodies.insert(Multibody::with_root(body2, true));
MultibodyLinkId {
graph_id: self.connectivity_graph.graph.add_node(body2),
multibody: MultibodyIndex(mb_handle),
id: 0,
}
});
if link1.multibody == link2.multibody || link2.id != 0 {
return None;
}
self.connectivity_graph
.graph
.add_edge(link1.graph_id, link2.graph_id, ());
self.rb2mb.insert(body1.0, link1);
self.rb2mb.insert(body2.0, link2);
let mb2 = self.multibodies.remove(link2.multibody.0).unwrap();
let multibody1 = &mut self.multibodies[link1.multibody.0];
for mb_link2 in mb2.links() {
let link = self.rb2mb.get_mut(mb_link2.rigid_body.0).unwrap();
link.multibody = link1.multibody;
link.id += multibody1.num_links();
}
multibody1.append(mb2, link1.id, MultibodyJoint::new(data.into(), kinematic));
if wake_up {
self.to_wake_up.insert(body1);
self.to_wake_up.insert(body2);
}
Some(MultibodyJointHandle(body2.0))
}
#[profiling::function]
pub fn remove(&mut self, handle: MultibodyJointHandle, wake_up: bool) {
if let Some(removed) = self.rb2mb.get(handle.0).copied() {
let multibody = self.multibodies.remove(removed.multibody.0).unwrap();
if let Some(parent_link) = multibody.link(removed.id).unwrap().parent_id() {
let parent_rb = multibody.link(parent_link).unwrap().rigid_body;
let parent_graph_id = self.rb2mb.get(parent_rb.0).unwrap().graph_id;
self.connectivity_graph
.remove_edge(parent_graph_id, removed.graph_id);
if wake_up {
self.to_wake_up.insert(RigidBodyHandle(handle.0));
self.to_wake_up.insert(parent_rb);
}
let multibodies = multibody.remove_link(removed.id, true);
for multibody in multibodies {
if multibody.num_links() == 1 {
let isolated_link = multibody.link(0).unwrap();
let isolated_graph_id =
self.rb2mb.get(isolated_link.rigid_body.0).unwrap().graph_id;
if let Some(other) = self.connectivity_graph.remove_node(isolated_graph_id)
{
self.rb2mb.get_mut(other.0).unwrap().graph_id = isolated_graph_id;
}
} else {
let mb_id = self.multibodies.insert(multibody);
for link in self.multibodies[mb_id].links() {
let ids = self.rb2mb.get_mut(link.rigid_body.0).unwrap();
ids.multibody = MultibodyIndex(mb_id);
ids.id = link.internal_id;
}
}
}
}
}
}
#[profiling::function]
pub fn remove_multibody_articulations(&mut self, handle: RigidBodyHandle, wake_up: bool) {
if let Some(removed) = self.rb2mb.get(handle.0).copied() {
let multibody = self.multibodies.remove(removed.multibody.0).unwrap();
for link in multibody.links() {
let rb_handle = link.rigid_body;
if wake_up {
self.to_wake_up.insert(rb_handle);
}
let removed = self.rb2mb.remove(rb_handle.0, Default::default()).unwrap();
if let Some(other) = self.connectivity_graph.remove_node(removed.graph_id) {
self.rb2mb.get_mut(other.0).unwrap().graph_id = removed.graph_id;
}
}
}
}
#[profiling::function]
pub fn remove_joints_attached_to_rigid_body(&mut self, rb_to_remove: RigidBodyHandle) {
if let Some(link_to_remove) = self.rb2mb.get(rb_to_remove.0).copied() {
let mut articulations_to_remove = vec![];
for (rb1, rb2, _) in self
.connectivity_graph
.interactions_with(link_to_remove.graph_id)
{
articulations_to_remove.push(MultibodyJointHandle(rb2.0));
self.to_wake_up.insert(rb1);
self.to_wake_up.insert(rb2);
}
for articulation_handle in articulations_to_remove {
self.remove(articulation_handle, true);
}
}
}
pub fn rigid_body_link(&self, rb: RigidBodyHandle) -> Option<&MultibodyLinkId> {
self.rb2mb.get(rb.0)
}
pub fn get_multibody(&self, index: MultibodyIndex) -> Option<&Multibody> {
self.multibodies.get(index.0)
}
pub fn get_multibody_mut(&mut self, index: MultibodyIndex) -> Option<&mut Multibody> {
self.multibodies.get_mut(index.0)
}
pub fn get_multibody_mut_internal(&mut self, index: MultibodyIndex) -> Option<&mut Multibody> {
self.multibodies.get_mut(index.0)
}
pub fn get(&self, handle: MultibodyJointHandle) -> Option<(&Multibody, usize)> {
let link = self.rb2mb.get(handle.0)?;
let multibody = self.multibodies.get(link.multibody.0)?;
Some((multibody, link.id))
}
pub fn get_mut(&mut self, handle: MultibodyJointHandle) -> Option<(&mut Multibody, usize)> {
let link = self.rb2mb.get(handle.0)?;
let multibody = self.multibodies.get_mut(link.multibody.0)?;
Some((multibody, link.id))
}
pub fn get_mut_internal(
&mut self,
handle: MultibodyJointHandle,
) -> Option<(&mut Multibody, usize)> {
let link = self.rb2mb.get(handle.0)?;
let multibody = self.multibodies.get_mut(link.multibody.0)?;
Some((multibody, link.id))
}
pub fn get_unknown_gen(&self, i: u32) -> Option<(&Multibody, usize, MultibodyJointHandle)> {
let link = self.rb2mb.get_unknown_gen(i)?;
let gen = self.rb2mb.get_gen(i)?;
let multibody = self.multibodies.get(link.multibody.0)?;
Some((
multibody,
link.id,
MultibodyJointHandle(Index::from_raw_parts(i, gen)),
))
}
pub fn joint_between(
&self,
rb1: RigidBodyHandle,
rb2: RigidBodyHandle,
) -> Option<(MultibodyJointHandle, &Multibody, &MultibodyLink)> {
let id1 = self.rb2mb.get(rb1.0)?;
let id2 = self.rb2mb.get(rb2.0)?;
if id1.multibody != id2.multibody {
return None;
}
let mb = self.multibodies.get(id1.multibody.0)?;
let link1 = mb.link(id1.id)?;
let parent1 = link1.parent_id();
if parent1 == Some(id2.id) {
Some((MultibodyJointHandle(rb1.0), mb, link1))
} else {
let link2 = mb.link(id2.id)?;
let parent2 = link2.parent_id();
if parent2 == Some(id1.id) {
Some((MultibodyJointHandle(rb2.0), mb, link2))
} else {
None
}
}
}
#[profiling::function]
pub fn attached_joints(
&self,
rb: RigidBodyHandle,
) -> impl Iterator<Item = (RigidBodyHandle, RigidBodyHandle, MultibodyJointHandle)> + '_ {
self.rb2mb
.get(rb.0)
.into_iter()
.flat_map(move |link| self.connectivity_graph.interactions_with(link.graph_id))
.map(|inter| {
(inter.0, inter.1, MultibodyJointHandle(inter.1 .0))
})
}
pub fn attached_bodies(
&self,
body: RigidBodyHandle,
) -> impl Iterator<Item = RigidBodyHandle> + '_ {
self.rb2mb
.get(body.0)
.into_iter()
.flat_map(move |id| self.connectivity_graph.interactions_with(id.graph_id))
.map(move |inter| crate::utils::select_other((inter.0, inter.1), body))
}
#[profiling::function]
pub fn bodies_attached_with_enabled_joint(
&self,
body: RigidBodyHandle,
) -> impl Iterator<Item = RigidBodyHandle> + '_ {
self.attached_bodies(body).filter(move |other| {
if let Some((_, _, link)) = self.joint_between(body, *other) {
link.joint.data.is_enabled()
} else {
false
}
})
}
pub fn multibodies(&self) -> impl Iterator<Item = &Multibody> {
self.multibodies.iter().map(|e| e.1)
}
}
impl std::ops::Index<MultibodyIndex> for MultibodyJointSet {
type Output = Multibody;
fn index(&self, index: MultibodyIndex) -> &Multibody {
&self.multibodies[index.0]
}
}