Implement multibody joints and the new solver

This commit is contained in:
Sébastien Crozet
2022-01-02 14:47:40 +01:00
parent b45d4b5ac2
commit f74b8401ad
182 changed files with 9871 additions and 12645 deletions

View File

@@ -0,0 +1,352 @@
use crate::data::{Arena, Coarena, ComponentSet, ComponentSetMut};
use crate::dynamics::joint::MultibodyLink;
use crate::dynamics::{
IslandManager, JointData, Multibody, MultibodyJoint, RigidBodyActivation, RigidBodyHandle,
RigidBodyIds, RigidBodyType,
};
use crate::geometry::{InteractionGraph, RigidBodyGraphIndex};
use crate::parry::partitioning::IndexedData;
use std::ops::Index;
/// The unique handle of an multibody_joint added to a `MultibodyJointSet`.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[repr(transparent)]
pub struct MultibodyJointHandle(pub crate::data::arena::Index);
/// The temporary index of a multibody added to a `MultibodyJointSet`.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[repr(transparent)]
pub struct MultibodyIndex(pub crate::data::arena::Index);
impl MultibodyJointHandle {
/// Converts this handle into its (index, generation) components.
pub fn into_raw_parts(self) -> (u32, u32) {
self.0.into_raw_parts()
}
/// Reconstructs an handle from its (index, generation) components.
pub fn from_raw_parts(id: u32, generation: u32) -> Self {
Self(crate::data::arena::Index::from_raw_parts(id, generation))
}
/// An always-invalid rigid-body handle.
pub fn invalid() -> Self {
Self(crate::data::arena::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()
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct MultibodyJointLink {
pub graph_id: RigidBodyGraphIndex,
pub multibody: MultibodyIndex,
pub id: usize,
}
impl Default for MultibodyJointLink {
fn default() -> Self {
Self {
graph_id: RigidBodyGraphIndex::new(crate::INVALID_U32),
multibody: MultibodyIndex(crate::data::arena::Index::from_raw_parts(
crate::INVALID_U32,
crate::INVALID_U32,
)),
id: 0,
}
}
}
/// A set of rigid bodies that can be handled by a physics pipeline.
pub struct MultibodyJointSet {
pub(crate) multibodies: Arena<Multibody>, // NOTE: a Slab would be sufficient.
pub(crate) rb2mb: Coarena<MultibodyJointLink>,
// NOTE: this is mostly for the island extraction. So perhaps we wont need
// that any more in the future when we improve our island builder.
pub(crate) connectivity_graph: InteractionGraph<RigidBodyHandle, ()>,
}
impl MultibodyJointSet {
/// Create a new empty set of multibodies.
pub fn new() -> Self {
Self {
multibodies: Arena::new(),
rb2mb: Coarena::new(),
connectivity_graph: InteractionGraph::new(),
}
}
pub fn iter(&self) -> impl Iterator<Item = (MultibodyJointHandle, &Multibody, &MultibodyLink)> {
self.rb2mb
.iter()
.filter(|(_, link)| link.id > 0) // The first link of a rigid-body hasnt been added by the user.
.map(|(h, link)| {
let mb = &self.multibodies[link.multibody.0];
(MultibodyJointHandle(h), mb, mb.link(link.id).unwrap())
})
}
/// Inserts a new multibody_joint into this set.
pub fn insert(
&mut self,
body1: RigidBodyHandle,
body2: RigidBodyHandle,
data: impl Into<JointData>,
) -> Option<MultibodyJointHandle> {
let data = data.into();
let link1 = self.rb2mb.get(body1.0).copied().unwrap_or_else(|| {
let mb_handle = self.multibodies.insert(Multibody::with_root(body1));
MultibodyJointLink {
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));
MultibodyJointLink {
graph_id: self.connectivity_graph.graph.add_node(body2),
multibody: MultibodyIndex(mb_handle),
id: 0,
}
});
if link1.multibody == link2.multibody || link2.id != 0 {
// This would introduce an invalid configuration.
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));
// Because each rigid-body can only have one parent link,
// we can use the second rigid-bodys handle as the multibody_joints
// handle.
Some(MultibodyJointHandle(body2.0))
}
/// Removes an multibody_joint from this set.
pub fn remove<Bodies>(
&mut self,
handle: MultibodyJointHandle,
islands: &mut IslandManager,
bodies: &mut Bodies,
wake_up: bool,
) where
Bodies: ComponentSetMut<RigidBodyActivation>
+ ComponentSet<RigidBodyType>
+ ComponentSetMut<RigidBodyIds>,
{
if let Some(removed) = self.rb2mb.get(handle.0).copied() {
let multibody = self.multibodies.remove(removed.multibody.0).unwrap();
// Remove the edge from the connectivity graph.
if let Some(parent_link) = multibody.link(removed.id).unwrap().parent_id() {
let parent_rb = multibody.link(parent_link).unwrap().rigid_body;
self.connectivity_graph.remove_edge(
self.rb2mb.get(parent_rb.0).unwrap().graph_id,
removed.graph_id,
);
if wake_up {
islands.wake_up(bodies, RigidBodyHandle(handle.0), true);
islands.wake_up(bodies, parent_rb, true);
}
// TODO: remove the node if it no longer has any attached edges?
// Extract the individual sub-trees generated by this removal.
let multibodies = multibody.remove_link(removed.id, true);
// Update the rb2mb mapping.
for multibody in multibodies {
if multibody.num_links() == 1 {
// We dont have any multibody_joint attached to this body, remove it.
if let Some(other) = self.connectivity_graph.remove_node(removed.graph_id) {
self.rb2mb.get_mut(other.0).unwrap().graph_id = removed.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;
}
}
}
}
}
}
/// Removes all the multibody_joints from the multibody the given rigid-body is part of.
pub fn remove_multibody_articulations<Bodies>(
&mut self,
handle: RigidBodyHandle,
islands: &mut IslandManager,
bodies: &mut Bodies,
wake_up: bool,
) where
Bodies: ComponentSetMut<RigidBodyActivation>
+ ComponentSet<RigidBodyType>
+ ComponentSetMut<RigidBodyIds>,
{
if let Some(removed) = self.rb2mb.get(handle.0).copied() {
// Remove the multibody.
let multibody = self.multibodies.remove(removed.multibody.0).unwrap();
for link in multibody.links() {
let rb_handle = link.rigid_body;
if wake_up {
islands.wake_up(bodies, rb_handle, true);
}
// Remove the rigid-body <-> multibody mapping for this link.
let removed = self.rb2mb.remove(rb_handle.0, Default::default()).unwrap();
// Remove the node (and all its edges) from the connectivity graph.
if let Some(other) = self.connectivity_graph.remove_node(removed.graph_id) {
self.rb2mb.get_mut(other.0).unwrap().graph_id = removed.graph_id;
}
}
}
}
pub fn remove_articulations_attached_to_rigid_body<Bodies>(
&mut self,
rb_to_remove: RigidBodyHandle,
islands: &mut IslandManager,
bodies: &mut Bodies,
) where
Bodies: ComponentSetMut<RigidBodyActivation>
+ ComponentSet<RigidBodyType>
+ ComponentSetMut<RigidBodyIds>,
{
// TODO: optimize this.
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)
{
// There is an multibody_joint that we need to remove between these two bodies.
// If this is an outbound edge, then the multibody_joints handle is equal to the
// second body handle.
if rb1 == rb_to_remove {
articulations_to_remove.push(MultibodyJointHandle(rb2.0));
} else {
articulations_to_remove.push(MultibodyJointHandle(rb1.0));
}
islands.wake_up(bodies, rb1, true);
islands.wake_up(bodies, rb2, true);
}
for articulation_handle in articulations_to_remove {
self.remove(articulation_handle, islands, bodies, true);
}
}
}
/// Returns the link of this multibody attached to the given rigid-body.
///
/// Returns `None` if `rb` isnt part of any rigid-body.
pub fn rigid_body_link(&self, rb: RigidBodyHandle) -> Option<&MultibodyJointLink> {
self.rb2mb.get(rb.0)
}
/// Gets a reference to a multibody, based on its temporary index.
pub fn get_multibody(&self, index: MultibodyIndex) -> Option<&Multibody> {
self.multibodies.get(index.0)
}
/// Gets a mutable reference to a multibody, based on its temporary index.
///
/// This method will bypass any modification-detection automatically done by the
/// `MultibodyJointSet`.
pub fn get_multibody_mut_internal(&mut self, index: MultibodyIndex) -> Option<&mut Multibody> {
self.multibodies.get_mut(index.0)
}
/// Gets a reference to the multibody identified by its `handle`.
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))
}
/// Gets a mutable reference to the multibody identified by its `handle`.
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))
}
/// Iterate through the handles of all the rigid-bodies attached to this rigid-body
/// by an multibody_joint.
pub fn attached_bodies<'a>(
&'a self,
body: RigidBodyHandle,
) -> impl Iterator<Item = RigidBodyHandle> + 'a {
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))
}
/// Iterates through all the multibodies on this set.
pub fn multibodies(&self) -> impl Iterator<Item = &Multibody> {
self.multibodies.iter().map(|e| e.1)
}
}
impl Index<MultibodyIndex> for MultibodyJointSet {
type Output = Multibody;
fn index(&self, index: MultibodyIndex) -> &Multibody {
&self.multibodies[index.0]
}
}
// impl Index<MultibodyJointHandle> for MultibodyJointSet {
// type Output = Multibody;
//
// fn index(&self, index: MultibodyJointHandle) -> &Multibody {
// &self.multibodies[index.0]
// }
// }