Skip to content

Commit 84c776e

Browse files
rapier 0.20 feature: RevoluteJoint::angle + more detailed joints enum (#530)
Co-authored-by: Sébastien Crozet <[email protected]>
1 parent ecdacfd commit 84c776e

File tree

13 files changed

+239
-69
lines changed

13 files changed

+239
-69
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,17 @@
66
and new features. Please have a look at the
77
[0.20 and 0.21 changelogs](https://github.com/dimforge/rapier/blob/master/CHANGELOG.md) of Rapier.**
88

9+
### Modified
10+
911
- Update to rapier `0.21`.
1012
- Update to nalgebra `0.33`.
13+
- `ImpulseJoint::data` and `MultibodyJoint::data` are now a more detailed enum `TypedJoint` instead of a `GenericJoint`.
14+
You can still access its inner `GenericJoint` with `.as_ref()` or `as_mut()`.
15+
- `data` fields from all joints (`FixedJoint`, …) are now public, and their getters removed.
16+
17+
### Added
18+
19+
- Added `RapierContext::context.impulse_revolute_joint_angle` to compute the angle along a revolute joint’s principal axis.
1120

1221
## v0.27.0-rc.1 (18 June 2024)
1322

bevy_rapier2d/examples/debug_despawn2.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,7 @@ fn spawn_cube(commands: &mut Commands, game: &mut Game) {
174174
block_entities[*i],
175175
RevoluteJointBuilder::new()
176176
.local_anchor1(anchor_1)
177-
.local_anchor2(anchor_2)
178-
.build(),
177+
.local_anchor2(anchor_2),
179178
))
180179
.id();
181180
game.current_cube_joints.push(id);

bevy_rapier3d/examples/joints3.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use bevy::prelude::*;
1+
use std::time::Duration;
2+
3+
use bevy::{prelude::*, time::common_conditions::once_after_delay};
24
use bevy_rapier3d::prelude::*;
35

46
fn main() {
@@ -14,6 +16,11 @@ fn main() {
1416
RapierDebugRenderPlugin::default(),
1517
))
1618
.add_systems(Startup, (setup_graphics, setup_physics))
19+
.add_systems(
20+
Last,
21+
(print_impulse_revolute_joints,)
22+
.run_if(once_after_delay(Duration::from_secs_f32(1f32))),
23+
)
1724
.run();
1825
}
1926

@@ -134,7 +141,6 @@ fn create_revolute_joints(commands: &mut Commands, origin: Vec3, num: usize) {
134141
RevoluteJointBuilder::new(z).local_anchor2(Vec3::new(0.0, 0.0, -shift)),
135142
RevoluteJointBuilder::new(x).local_anchor2(Vec3::new(shift, 0.0, 0.0)),
136143
];
137-
138144
commands
139145
.entity(handles[0])
140146
.insert(ImpulseJoint::new(curr_parent, revs[0]));
@@ -276,3 +282,21 @@ pub fn setup_physics(mut commands: Commands) {
276282
create_rope_joints(&mut commands, Vec3::new(30.0, 10.0, 0.0), 5);
277283
create_ball_joints(&mut commands, 15);
278284
}
285+
286+
pub fn print_impulse_revolute_joints(
287+
context: Res<RapierContext>,
288+
joints: Query<(Entity, &ImpulseJoint)>,
289+
) {
290+
for (entity, impulse_joint) in joints.iter() {
291+
match &impulse_joint.data {
292+
TypedJoint::RevoluteJoint(_revolute_joint) => {
293+
println!(
294+
"angle for {}: {:?}",
295+
entity,
296+
context.impulse_revolute_joint_angle(entity),
297+
);
298+
}
299+
_ => {}
300+
}
301+
}
302+
}

src/dynamics/fixed_joint.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ use crate::dynamics::{GenericJoint, GenericJointBuilder};
22
use crate::math::{Rot, Vect};
33
use rapier::dynamics::JointAxesMask;
44

5+
use super::TypedJoint;
6+
57
#[derive(Copy, Clone, Debug, PartialEq)]
68
#[repr(transparent)]
79
/// A fixed joint, locks all relative motion between two bodies.
810
pub struct FixedJoint {
9-
data: GenericJoint,
11+
/// The underlying joint data.
12+
pub data: GenericJoint,
1013
}
1114

1215
impl Default for FixedJoint {
@@ -134,8 +137,14 @@ impl FixedJointBuilder {
134137
}
135138
}
136139

137-
impl From<FixedJointBuilder> for GenericJoint {
138-
fn from(joint: FixedJointBuilder) -> GenericJoint {
140+
impl From<FixedJointBuilder> for TypedJoint {
141+
fn from(joint: FixedJointBuilder) -> TypedJoint {
139142
joint.0.into()
140143
}
141144
}
145+
146+
impl From<FixedJoint> for TypedJoint {
147+
fn from(joint: FixedJoint) -> TypedJoint {
148+
TypedJoint::FixedJoint(joint)
149+
}
150+
}

src/dynamics/joint.rs

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,63 @@
1-
use crate::dynamics::GenericJoint;
21
use bevy::prelude::*;
32
use rapier::dynamics::{ImpulseJointHandle, MultibodyJointHandle};
43

54
pub use rapier::dynamics::{JointAxesMask, JointAxis, MotorModel};
65

6+
use super::{FixedJoint, GenericJoint, PrismaticJoint, RevoluteJoint, RopeJoint, SpringJoint};
7+
8+
#[cfg(feature = "dim3")]
9+
use super::SphericalJoint;
10+
11+
/// Wrapper enum over a specific joint.
12+
#[derive(Clone, Copy, Debug, PartialEq)]
13+
pub enum TypedJoint {
14+
/// See [`FixedJoint`]
15+
FixedJoint(FixedJoint),
16+
/// See [`GenericJoint`]
17+
GenericJoint(GenericJoint),
18+
/// See [`PrismaticJoint`]
19+
PrismaticJoint(PrismaticJoint),
20+
/// See [`RevoluteJoint`]
21+
RevoluteJoint(RevoluteJoint),
22+
/// See [`RopeJoint`]
23+
RopeJoint(RopeJoint),
24+
/// See [`SphericalJoint`]
25+
#[cfg(feature = "dim3")]
26+
SphericalJoint(SphericalJoint),
27+
/// See [`SpringJoint`]
28+
SpringJoint(SpringJoint),
29+
}
30+
31+
impl AsMut<GenericJoint> for TypedJoint {
32+
fn as_mut(&mut self) -> &mut GenericJoint {
33+
match self {
34+
TypedJoint::FixedJoint(ref mut j) => &mut j.data,
35+
TypedJoint::GenericJoint(ref mut j) => j,
36+
TypedJoint::PrismaticJoint(ref mut j) => &mut j.data,
37+
TypedJoint::RevoluteJoint(ref mut j) => &mut j.data,
38+
TypedJoint::RopeJoint(ref mut j) => &mut j.data,
39+
#[cfg(feature = "dim3")]
40+
TypedJoint::SphericalJoint(ref mut j) => &mut j.data,
41+
TypedJoint::SpringJoint(ref mut j) => &mut j.data,
42+
}
43+
}
44+
}
45+
46+
impl AsRef<GenericJoint> for TypedJoint {
47+
fn as_ref(&self) -> &GenericJoint {
48+
match self {
49+
TypedJoint::FixedJoint(j) => &j.data,
50+
TypedJoint::GenericJoint(j) => j,
51+
TypedJoint::PrismaticJoint(j) => &j.data,
52+
TypedJoint::RevoluteJoint(j) => &j.data,
53+
TypedJoint::RopeJoint(j) => &j.data,
54+
#[cfg(feature = "dim3")]
55+
TypedJoint::SphericalJoint(j) => &j.data,
56+
TypedJoint::SpringJoint(j) => &j.data,
57+
}
58+
}
59+
}
60+
761
/// The handle of an impulse joint added to the physics scene.
862
#[derive(Copy, Clone, Debug, Component)]
963
pub struct RapierImpulseJointHandle(pub ImpulseJointHandle);
@@ -28,12 +82,12 @@ pub struct ImpulseJoint {
2882
/// The entity containing the rigid-body used as the first endpoint of this joint.
2983
pub parent: Entity,
3084
/// The joint’s description.
31-
pub data: GenericJoint,
85+
pub data: TypedJoint,
3286
}
3387

3488
impl ImpulseJoint {
3589
/// Initializes an impulse-based joint from its first endpoint and the joint description.
36-
pub fn new(parent: Entity, data: impl Into<GenericJoint>) -> Self {
90+
pub fn new(parent: Entity, data: impl Into<TypedJoint>) -> Self {
3791
Self {
3892
parent,
3993
data: data.into(),
@@ -55,16 +109,13 @@ pub struct MultibodyJoint {
55109
/// The entity containing the rigid-body used as the first endpoint of this joint.
56110
pub parent: Entity,
57111
/// The joint’s description.
58-
pub data: GenericJoint,
112+
pub data: TypedJoint,
59113
}
60114

61115
impl MultibodyJoint {
62116
/// Initializes an joint based on reduced coordinates from its first endpoint and
63117
/// the joint description.
64-
pub fn new(parent: Entity, data: impl Into<GenericJoint>) -> Self {
65-
Self {
66-
parent,
67-
data: data.into(),
68-
}
118+
pub fn new(parent: Entity, data: TypedJoint) -> Self {
119+
Self { parent, data }
69120
}
70121
}

src/dynamics/prismatic_joint.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ use crate::dynamics::{GenericJoint, GenericJointBuilder};
22
use crate::math::{Real, Vect};
33
use rapier::dynamics::{JointAxesMask, JointAxis, JointLimits, JointMotor, MotorModel};
44

5+
use super::TypedJoint;
6+
57
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
68
#[derive(Copy, Clone, Debug, PartialEq)]
79
#[repr(transparent)]
810
/// A prismatic joint, locks all relative motion between two bodies except for translation along the joint’s principal axis.
911
pub struct PrismaticJoint {
10-
data: GenericJoint,
12+
/// The underlying joint data.
13+
pub data: GenericJoint,
1114
}
1215

1316
impl PrismaticJoint {
@@ -22,11 +25,6 @@ impl PrismaticJoint {
2225
Self { data }
2326
}
2427

25-
/// The underlying generic joint.
26-
pub fn data(&self) -> &GenericJoint {
27-
&self.data
28-
}
29-
3028
/// Are contacts between the attached rigid-bodies enabled?
3129
pub fn contacts_enabled(&self) -> bool {
3230
self.data.contacts_enabled()
@@ -253,8 +251,14 @@ impl PrismaticJointBuilder {
253251
}
254252
}
255253

256-
impl From<PrismaticJointBuilder> for GenericJoint {
257-
fn from(joint: PrismaticJointBuilder) -> GenericJoint {
254+
impl From<PrismaticJointBuilder> for TypedJoint {
255+
fn from(joint: PrismaticJointBuilder) -> TypedJoint {
258256
joint.0.into()
259257
}
260258
}
259+
260+
impl From<PrismaticJoint> for TypedJoint {
261+
fn from(joint: PrismaticJoint) -> TypedJoint {
262+
TypedJoint::PrismaticJoint(joint)
263+
}
264+
}

src/dynamics/revolute_joint.rs

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
use crate::dynamics::{GenericJoint, GenericJointBuilder};
22
use crate::math::{Real, Vect};
3-
use rapier::dynamics::{JointAxesMask, JointAxis, JointLimits, JointMotor, MotorModel};
3+
use crate::plugin::RapierContext;
4+
use bevy::prelude::Entity;
5+
use rapier::dynamics::{
6+
JointAxesMask, JointAxis, JointLimits, JointMotor, MotorModel, RigidBodyHandle, RigidBodySet,
7+
};
8+
9+
use super::TypedJoint;
410

511
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
612
#[derive(Copy, Clone, Debug, PartialEq)]
713
#[repr(transparent)]
814
/// A revolute joint, locks all relative motion except for rotation along the joint’s principal axis.
915
pub struct RevoluteJoint {
10-
data: GenericJoint,
16+
/// The underlying joint data.
17+
pub data: GenericJoint,
1118
}
1219

1320
#[cfg(feature = "dim2")]
@@ -37,11 +44,6 @@ impl RevoluteJoint {
3744
Self { data }
3845
}
3946

40-
/// The underlying generic joint.
41-
pub fn data(&self) -> &GenericJoint {
42-
&self.data
43-
}
44-
4547
/// Are contacts between the attached rigid-bodies enabled?
4648
pub fn contacts_enabled(&self) -> bool {
4749
self.data.contacts_enabled()
@@ -138,6 +140,41 @@ impl RevoluteJoint {
138140
self.data.set_limits(JointAxis::AngX, limits);
139141
self
140142
}
143+
144+
/// The angle along the free degree of freedom of this revolute joint in `[-π, π]`.
145+
///
146+
/// See also [`Self::angle`] for a version of this method taking entities instead of rigid-body handles.
147+
/// Similarly [`RapierContext::impulse_revolute_joint_angle`] only takes a single entity as argument to compute that angle.
148+
///
149+
/// # Parameters
150+
/// - `bodies` : the rigid body set from [`RapierContext`]
151+
/// - `body1`: the first rigid-body attached to this revolute joint, obtained through [`rapier::dynamics::ImpulseJoint`] or [`rapier::dynamics::MultibodyJoint`].
152+
/// - `body2`: the second rigid-body attached to this revolute joint, obtained through [`rapier::dynamics::ImpulseJoint`] or [`rapier::dynamics::MultibodyJoint`].
153+
pub fn angle_from_handles(
154+
&self,
155+
bodies: &RigidBodySet,
156+
body1: RigidBodyHandle,
157+
body2: RigidBodyHandle,
158+
) -> f32 {
159+
// NOTE: unwrap will always succeed since `Self` is known to be a revolute joint.
160+
let joint = self.data.raw.as_revolute().unwrap();
161+
162+
let rb1 = &bodies[body1];
163+
let rb2 = &bodies[body2];
164+
joint.angle(rb1.rotation(), rb2.rotation())
165+
}
166+
167+
/// The angle along the free degree of freedom of this revolute joint in `[-π, π]`.
168+
///
169+
/// # Parameters
170+
/// - `bodies` : the rigid body set from [`super::super::RapierContext`]
171+
/// - `body1`: the first rigid-body attached to this revolute joint.
172+
/// - `body2`: the second rigid-body attached to this revolute joint.
173+
pub fn angle(&self, context: &RapierContext, body1: Entity, body2: Entity) -> f32 {
174+
let rb1 = context.entity2body().get(&body1).unwrap();
175+
let rb2 = context.entity2body().get(&body2).unwrap();
176+
self.angle_from_handles(&context.bodies, *rb1, *rb2)
177+
}
141178
}
142179

143180
impl From<RevoluteJoint> for GenericJoint {
@@ -244,8 +281,14 @@ impl RevoluteJointBuilder {
244281
}
245282
}
246283

247-
impl From<RevoluteJointBuilder> for GenericJoint {
248-
fn from(joint: RevoluteJointBuilder) -> GenericJoint {
284+
impl From<RevoluteJointBuilder> for TypedJoint {
285+
fn from(joint: RevoluteJointBuilder) -> TypedJoint {
249286
joint.0.into()
250287
}
251288
}
289+
290+
impl From<RevoluteJoint> for TypedJoint {
291+
fn from(joint: RevoluteJoint) -> TypedJoint {
292+
TypedJoint::RevoluteJoint(joint)
293+
}
294+
}

src/dynamics/rope_joint.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ use crate::dynamics::{GenericJoint, GenericJointBuilder};
22
use crate::math::{Real, Vect};
33
use rapier::dynamics::{JointAxesMask, JointAxis, JointLimits, JointMotor, MotorModel};
44

5+
use super::TypedJoint;
6+
57
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
68
#[derive(Copy, Clone, Debug, PartialEq)]
79
#[repr(transparent)]
810
/// A rope joint, limits the maximum distance between two bodies
911
pub struct RopeJoint {
10-
data: GenericJoint,
12+
/// The underlying joint data.
13+
pub data: GenericJoint,
1114
}
1215

1316
impl RopeJoint {
@@ -21,11 +24,6 @@ impl RopeJoint {
2124
result
2225
}
2326

24-
/// The underlying generic joint.
25-
pub fn data(&self) -> &GenericJoint {
26-
&self.data
27-
}
28-
2927
/// Are contacts between the attached rigid-bodies enabled?
3028
pub fn contacts_enabled(&self) -> bool {
3129
self.data.contacts_enabled()
@@ -262,8 +260,14 @@ impl RopeJointBuilder {
262260
}
263261
}
264262

265-
impl From<RopeJointBuilder> for GenericJoint {
266-
fn from(joint: RopeJointBuilder) -> GenericJoint {
263+
impl From<RopeJointBuilder> for TypedJoint {
264+
fn from(joint: RopeJointBuilder) -> TypedJoint {
267265
joint.0.into()
268266
}
269267
}
268+
269+
impl From<RopeJoint> for TypedJoint {
270+
fn from(joint: RopeJoint) -> TypedJoint {
271+
TypedJoint::RopeJoint(joint)
272+
}
273+
}

0 commit comments

Comments
 (0)