Skip to main content

box3d_rust/types/
joint.rs

1// Joint definition types from include/box3d/types.h and their b3Default*
2// constructors from src/joint.c.
3//
4// SPDX-FileCopyrightText: 2025 Erin Catto
5// SPDX-License-Identifier: MIT
6
7use crate::constants::huge;
8use crate::core::{get_length_units_per_meter, SECRET_COOKIE};
9use crate::id::BodyId;
10use crate::math_functions::{Quat, Transform, Vec3, QUAT_IDENTITY, TRANSFORM_IDENTITY, VEC3_ZERO};
11
12/// Base joint definition used by all joint types. The local frames are measured
13/// from the body's origin rather than the center of mass because:
14/// 1. You might not know where the center of mass will be.
15/// 2. If you add/remove shapes from a body and recompute the mass, the joints
16///    will be broken.
17///
18/// (b3JointDef)
19#[derive(Debug, Clone, Copy, PartialEq)]
20pub struct JointDef {
21    /// User data
22    pub user_data: u64,
23
24    /// The first attached body
25    pub body_id_a: BodyId,
26
27    /// The second attached body
28    pub body_id_b: BodyId,
29
30    /// The first local joint frame
31    pub local_frame_a: Transform,
32
33    /// The second local joint frame
34    pub local_frame_b: Transform,
35
36    /// Force threshold for joint events
37    pub force_threshold: f32,
38
39    /// Torque threshold for joint events
40    pub torque_threshold: f32,
41
42    /// Constraint hertz (advanced feature)
43    pub constraint_hertz: f32,
44
45    /// Constraint damping ratio (advanced feature)
46    pub constraint_damping_ratio: f32,
47
48    /// Debug draw scale
49    pub draw_scale: f32,
50
51    /// Set this flag to true if the attached bodies should collide
52    pub collide_connected: bool,
53
54    /// Used internally to detect a valid definition. DO NOT SET.
55    pub internal_value: i32,
56}
57
58/// (static b3DefaultJointDef)
59pub(crate) fn default_joint_def() -> JointDef {
60    JointDef {
61        user_data: 0,
62        body_id_a: BodyId::default(),
63        body_id_b: BodyId::default(),
64        local_frame_a: Transform {
65            q: QUAT_IDENTITY,
66            ..TRANSFORM_IDENTITY
67        },
68        local_frame_b: Transform {
69            q: QUAT_IDENTITY,
70            ..TRANSFORM_IDENTITY
71        },
72        force_threshold: f32::MAX,
73        torque_threshold: f32::MAX,
74        constraint_hertz: 60.0,
75        constraint_damping_ratio: 2.0,
76        draw_scale: get_length_units_per_meter(),
77        collide_connected: false,
78        internal_value: SECRET_COOKIE,
79    }
80}
81
82/// Distance joint definition.
83/// Connects a point on body A with a point on body B by a segment.
84/// Useful for ropes and springs. (b3DistanceJointDef)
85#[derive(Debug, Clone, Copy, PartialEq)]
86pub struct DistanceJointDef {
87    pub base: JointDef,
88    pub length: f32,
89    pub enable_spring: bool,
90    pub lower_spring_force: f32,
91    pub upper_spring_force: f32,
92    pub hertz: f32,
93    pub damping_ratio: f32,
94    pub enable_limit: bool,
95    pub min_length: f32,
96    pub max_length: f32,
97    pub enable_motor: bool,
98    pub max_motor_force: f32,
99    pub motor_speed: f32,
100}
101
102/// (b3DefaultDistanceJointDef)
103pub fn default_distance_joint_def() -> DistanceJointDef {
104    DistanceJointDef {
105        base: default_joint_def(),
106        length: 1.0,
107        enable_spring: false,
108        lower_spring_force: -f32::MAX,
109        upper_spring_force: f32::MAX,
110        hertz: 0.0,
111        damping_ratio: 0.0,
112        enable_limit: false,
113        min_length: 0.0,
114        max_length: huge(),
115        enable_motor: false,
116        max_motor_force: 0.0,
117        motor_speed: 0.0,
118    }
119}
120
121impl Default for DistanceJointDef {
122    fn default() -> Self {
123        default_distance_joint_def()
124    }
125}
126
127/// A motor joint controls relative position and velocity. (b3MotorJointDef)
128#[derive(Debug, Clone, Copy, PartialEq)]
129pub struct MotorJointDef {
130    pub base: JointDef,
131    pub linear_velocity: Vec3,
132    pub max_velocity_force: f32,
133    pub angular_velocity: Vec3,
134    pub max_velocity_torque: f32,
135    pub linear_hertz: f32,
136    pub linear_damping_ratio: f32,
137    pub max_spring_force: f32,
138    pub angular_hertz: f32,
139    pub angular_damping_ratio: f32,
140    pub max_spring_torque: f32,
141}
142
143/// (b3DefaultMotorJointDef)
144pub fn default_motor_joint_def() -> MotorJointDef {
145    MotorJointDef {
146        base: default_joint_def(),
147        linear_velocity: VEC3_ZERO,
148        max_velocity_force: 0.0,
149        angular_velocity: VEC3_ZERO,
150        max_velocity_torque: 0.0,
151        linear_hertz: 0.0,
152        linear_damping_ratio: 0.0,
153        max_spring_force: 0.0,
154        angular_hertz: 0.0,
155        angular_damping_ratio: 0.0,
156        max_spring_torque: 0.0,
157    }
158}
159
160impl Default for MotorJointDef {
161    fn default() -> Self {
162        default_motor_joint_def()
163    }
164}
165
166/// Disables collision between two specific bodies. (b3FilterJointDef)
167#[derive(Debug, Clone, Copy, PartialEq)]
168pub struct FilterJointDef {
169    pub base: JointDef,
170}
171
172/// (b3DefaultFilterJointDef)
173pub fn default_filter_joint_def() -> FilterJointDef {
174    FilterJointDef {
175        base: default_joint_def(),
176    }
177}
178
179impl Default for FilterJointDef {
180    fn default() -> Self {
181        default_filter_joint_def()
182    }
183}
184
185/// Parallel joint: spring between body A z-axis and body B z-axis.
186/// (b3ParallelJointDef)
187#[derive(Debug, Clone, Copy, PartialEq)]
188pub struct ParallelJointDef {
189    pub base: JointDef,
190    pub hertz: f32,
191    pub damping_ratio: f32,
192    pub max_torque: f32,
193}
194
195/// (b3DefaultParallelJointDef)
196pub fn default_parallel_joint_def() -> ParallelJointDef {
197    ParallelJointDef {
198        base: default_joint_def(),
199        hertz: 1.0,
200        damping_ratio: 1.0,
201        max_torque: f32::MAX,
202    }
203}
204
205impl Default for ParallelJointDef {
206    fn default() -> Self {
207        default_parallel_joint_def()
208    }
209}
210
211/// Prismatic joint: body B slides along frame A x-axis. (b3PrismaticJointDef)
212#[derive(Debug, Clone, Copy, PartialEq)]
213pub struct PrismaticJointDef {
214    pub base: JointDef,
215    pub enable_spring: bool,
216    pub hertz: f32,
217    pub damping_ratio: f32,
218    pub target_translation: f32,
219    pub enable_limit: bool,
220    pub lower_translation: f32,
221    pub upper_translation: f32,
222    pub enable_motor: bool,
223    pub max_motor_force: f32,
224    pub motor_speed: f32,
225}
226
227/// (b3DefaultPrismaticJointDef)
228pub fn default_prismatic_joint_def() -> PrismaticJointDef {
229    PrismaticJointDef {
230        base: default_joint_def(),
231        enable_spring: false,
232        hertz: 0.0,
233        damping_ratio: 0.0,
234        target_translation: 0.0,
235        enable_limit: false,
236        lower_translation: 0.0,
237        upper_translation: 0.0,
238        enable_motor: false,
239        max_motor_force: 0.0,
240        motor_speed: 0.0,
241    }
242}
243
244impl Default for PrismaticJointDef {
245    fn default() -> Self {
246        default_prismatic_joint_def()
247    }
248}
249
250/// Revolute joint: point constraint with relative rotation about z.
251/// (b3RevoluteJointDef)
252#[derive(Debug, Clone, Copy, PartialEq)]
253pub struct RevoluteJointDef {
254    pub base: JointDef,
255    pub target_angle: f32,
256    pub enable_spring: bool,
257    pub hertz: f32,
258    pub damping_ratio: f32,
259    pub enable_limit: bool,
260    pub lower_angle: f32,
261    pub upper_angle: f32,
262    pub enable_motor: bool,
263    pub max_motor_torque: f32,
264    pub motor_speed: f32,
265}
266
267/// (b3DefaultRevoluteJointDef)
268pub fn default_revolute_joint_def() -> RevoluteJointDef {
269    RevoluteJointDef {
270        base: default_joint_def(),
271        target_angle: 0.0,
272        enable_spring: false,
273        hertz: 0.0,
274        damping_ratio: 0.0,
275        enable_limit: false,
276        lower_angle: 0.0,
277        upper_angle: 0.0,
278        enable_motor: false,
279        max_motor_torque: 0.0,
280        motor_speed: 0.0,
281    }
282}
283
284impl Default for RevoluteJointDef {
285    fn default() -> Self {
286        default_revolute_joint_def()
287    }
288}
289
290/// Spherical joint: point constraint allowing free rotation. (b3SphericalJointDef)
291#[derive(Debug, Clone, Copy, PartialEq)]
292pub struct SphericalJointDef {
293    pub base: JointDef,
294    pub enable_spring: bool,
295    pub hertz: f32,
296    pub damping_ratio: f32,
297    pub target_rotation: Quat,
298    pub enable_cone_limit: bool,
299    pub cone_angle: f32,
300    pub enable_twist_limit: bool,
301    pub lower_twist_angle: f32,
302    pub upper_twist_angle: f32,
303    pub enable_motor: bool,
304    pub max_motor_torque: f32,
305    pub motor_velocity: Vec3,
306}
307
308/// (b3DefaultSphericalJointDef)
309pub fn default_spherical_joint_def() -> SphericalJointDef {
310    SphericalJointDef {
311        base: default_joint_def(),
312        enable_spring: false,
313        hertz: 0.0,
314        damping_ratio: 0.0,
315        target_rotation: QUAT_IDENTITY,
316        enable_cone_limit: false,
317        cone_angle: 0.0,
318        enable_twist_limit: false,
319        lower_twist_angle: 0.0,
320        upper_twist_angle: 0.0,
321        enable_motor: false,
322        max_motor_torque: 0.0,
323        motor_velocity: VEC3_ZERO,
324    }
325}
326
327impl Default for SphericalJointDef {
328    fn default() -> Self {
329        default_spherical_joint_def()
330    }
331}
332
333/// Weld joint: rigid connection with optional soft springs. (b3WeldJointDef)
334#[derive(Debug, Clone, Copy, PartialEq)]
335pub struct WeldJointDef {
336    pub base: JointDef,
337    pub linear_hertz: f32,
338    pub angular_hertz: f32,
339    pub linear_damping_ratio: f32,
340    pub angular_damping_ratio: f32,
341}
342
343/// (b3DefaultWeldJointDef)
344pub fn default_weld_joint_def() -> WeldJointDef {
345    WeldJointDef {
346        base: default_joint_def(),
347        linear_hertz: 0.0,
348        angular_hertz: 0.0,
349        linear_damping_ratio: 0.0,
350        angular_damping_ratio: 0.0,
351    }
352}
353
354impl Default for WeldJointDef {
355    fn default() -> Self {
356        default_weld_joint_def()
357    }
358}
359
360/// Wheel joint: chassis A + wheel B with suspension and steering.
361/// (b3WheelJointDef)
362#[derive(Debug, Clone, Copy, PartialEq)]
363pub struct WheelJointDef {
364    pub base: JointDef,
365    pub enable_suspension_spring: bool,
366    pub suspension_hertz: f32,
367    pub suspension_damping_ratio: f32,
368    pub enable_suspension_limit: bool,
369    pub lower_suspension_limit: f32,
370    pub upper_suspension_limit: f32,
371    pub enable_spin_motor: bool,
372    pub max_spin_torque: f32,
373    pub spin_speed: f32,
374    pub enable_steering: bool,
375    pub steering_hertz: f32,
376    pub steering_damping_ratio: f32,
377    pub target_steering_angle: f32,
378    pub max_steering_torque: f32,
379    pub enable_steering_limit: bool,
380    pub lower_steering_limit: f32,
381    pub upper_steering_limit: f32,
382}
383
384/// (b3DefaultWheelJointDef)
385pub fn default_wheel_joint_def() -> WheelJointDef {
386    WheelJointDef {
387        base: default_joint_def(),
388        enable_suspension_spring: true,
389        suspension_hertz: 1.0,
390        suspension_damping_ratio: 0.7,
391        enable_suspension_limit: false,
392        lower_suspension_limit: 0.0,
393        upper_suspension_limit: 0.0,
394        enable_spin_motor: false,
395        max_spin_torque: 0.0,
396        spin_speed: 0.0,
397        enable_steering: false,
398        steering_hertz: 1.0,
399        steering_damping_ratio: 0.7,
400        target_steering_angle: 0.0,
401        max_steering_torque: 0.0,
402        enable_steering_limit: false,
403        lower_steering_limit: 0.0,
404        upper_steering_limit: 0.0,
405    }
406}
407
408impl Default for WheelJointDef {
409    fn default() -> Self {
410        default_wheel_joint_def()
411    }
412}