1#![allow(dead_code)]
11
12use super::*;
13use crate::body::{make_body_id, wake_body};
14use crate::core::NULL_INDEX;
15use crate::id::{BodyId, JointId};
16use crate::math_functions::{
17 abs_float, dot, is_valid_float, is_valid_transform, left_perp, length, relative_angle,
18 rotate_vector, sub, to_relative_transform, transform_point, Transform, Vec2,
19};
20use crate::world::World;
21
22pub fn joint_get_type(world: &World, joint_id: JointId) -> JointType {
24 let joint_index = get_joint_full_id(world, joint_id);
25 world.joints[joint_index as usize].type_
26}
27
28pub fn joint_get_body_a(world: &World, joint_id: JointId) -> BodyId {
30 let joint_index = get_joint_full_id(world, joint_id);
31 make_body_id(world, world.joints[joint_index as usize].edges[0].body_id)
32}
33
34pub fn joint_get_body_b(world: &World, joint_id: JointId) -> BodyId {
36 let joint_index = get_joint_full_id(world, joint_id);
37 make_body_id(world, world.joints[joint_index as usize].edges[1].body_id)
38}
39
40pub fn joint_set_local_frame_a(world: &mut World, joint_id: JointId, local_frame: Transform) {
42 debug_assert!(is_valid_transform(local_frame));
43
44 let joint_index = get_joint_full_id(world, joint_id);
45 let joint_sim = get_joint_sim(world, joint_index);
46 joint_sim.local_frame_a = local_frame;
47}
48
49pub fn joint_get_local_frame_a(world: &World, joint_id: JointId) -> Transform {
51 let joint_index = get_joint_full_id(world, joint_id);
52 get_joint_sim_ref(world, joint_index).local_frame_a
53}
54
55pub fn joint_set_local_frame_b(world: &mut World, joint_id: JointId, local_frame: Transform) {
57 debug_assert!(is_valid_transform(local_frame));
58
59 let joint_index = get_joint_full_id(world, joint_id);
60 let joint_sim = get_joint_sim(world, joint_index);
61 joint_sim.local_frame_b = local_frame;
62}
63
64pub fn joint_get_local_frame_b(world: &World, joint_id: JointId) -> Transform {
66 let joint_index = get_joint_full_id(world, joint_id);
67 get_joint_sim_ref(world, joint_index).local_frame_b
68}
69
70pub fn joint_set_collide_connected(world: &mut World, joint_id: JointId, should_collide: bool) {
72 let joint_index = get_joint_full_id(world, joint_id);
73 if world.joints[joint_index as usize].collide_connected == should_collide {
74 return;
75 }
76
77 world.joints[joint_index as usize].collide_connected = should_collide;
78
79 let body_id_a = world.joints[joint_index as usize].edges[0].body_id;
80 let body_id_b = world.joints[joint_index as usize].edges[1].body_id;
81
82 if should_collide {
83 let shape_count_a = world.bodies[body_id_a as usize].shape_count;
86 let shape_count_b = world.bodies[body_id_b as usize].shape_count;
87
88 let mut shape_id = if shape_count_a < shape_count_b {
89 world.bodies[body_id_a as usize].head_shape_id
90 } else {
91 world.bodies[body_id_b as usize].head_shape_id
92 };
93 while shape_id != NULL_INDEX {
94 let proxy_key = world.shapes[shape_id as usize].proxy_key;
95 if proxy_key != NULL_INDEX {
96 world.broad_phase.buffer_move(proxy_key);
97 }
98
99 shape_id = world.shapes[shape_id as usize].next_shape_id;
100 }
101 } else {
102 destroy_contacts_between_bodies(world, body_id_a, body_id_b);
103 }
104}
105
106pub fn joint_get_collide_connected(world: &World, joint_id: JointId) -> bool {
108 let joint_index = get_joint_full_id(world, joint_id);
109 world.joints[joint_index as usize].collide_connected
110}
111
112pub fn joint_set_user_data(world: &mut World, joint_id: JointId, user_data: u64) {
114 let joint_index = get_joint_full_id(world, joint_id);
115 world.joints[joint_index as usize].user_data = user_data;
116}
117
118pub fn joint_get_user_data(world: &World, joint_id: JointId) -> u64 {
120 let joint_index = get_joint_full_id(world, joint_id);
121 world.joints[joint_index as usize].user_data
122}
123
124pub fn joint_wake_bodies(world: &mut World, joint_id: JointId) {
126 let joint_index = get_joint_full_id(world, joint_id);
127 let body_id_a = world.joints[joint_index as usize].edges[0].body_id;
128 let body_id_b = world.joints[joint_index as usize].edges[1].body_id;
129
130 wake_body(world, body_id_a);
131 wake_body(world, body_id_b);
132}
133
134pub fn joint_get_constraint_force(world: &World, joint_id: JointId) -> Vec2 {
136 let joint_index = get_joint_full_id(world, joint_id);
137 get_joint_constraint_force(world, joint_index)
138}
139
140pub fn joint_get_constraint_torque(world: &World, joint_id: JointId) -> f32 {
142 let joint_index = get_joint_full_id(world, joint_id);
143 get_joint_constraint_torque(world, joint_index)
144}
145
146pub fn joint_get_linear_separation(world: &World, joint_id: JointId) -> f32 {
148 let joint_index = get_joint_full_id(world, joint_id);
149 let base = get_joint_sim_ref(world, joint_index);
150 let joint = &world.joints[joint_index as usize];
151
152 let wxf_a = crate::body::get_body_transform(world, joint.edges[0].body_id);
155 let xf_a = to_relative_transform(wxf_a, wxf_a.p);
156 let xf_b = to_relative_transform(
157 crate::body::get_body_transform(world, joint.edges[1].body_id),
158 wxf_a.p,
159 );
160
161 let p_a = transform_point(xf_a, base.local_frame_a.p);
162 let p_b = transform_point(xf_b, base.local_frame_b.p);
163 let dp = sub(p_b, p_a);
164
165 match &base.payload {
166 JointPayload::Distance(distance_joint) => {
167 let length_ = length(dp);
168 if distance_joint.enable_spring {
169 if distance_joint.enable_limit {
170 if length_ < distance_joint.min_length {
171 return distance_joint.min_length - length_;
172 }
173
174 if length_ > distance_joint.max_length {
175 return length_ - distance_joint.max_length;
176 }
177
178 return 0.0;
179 }
180
181 return 0.0;
182 }
183
184 abs_float(length_ - distance_joint.length)
185 }
186
187 JointPayload::Motor(_) => 0.0,
188
189 JointPayload::Filter => 0.0,
190
191 JointPayload::Prismatic(prismatic_joint) => {
192 let axis_a = rotate_vector(xf_a.q, Vec2 { x: 1.0, y: 0.0 });
193 let perp_a = left_perp(axis_a);
194 let perpendicular_separation = abs_float(dot(perp_a, dp));
195 let mut limit_separation = 0.0;
196
197 if prismatic_joint.enable_limit {
198 let translation = dot(axis_a, dp);
199 if translation < prismatic_joint.lower_translation {
200 limit_separation = prismatic_joint.lower_translation - translation;
201 }
202
203 if prismatic_joint.upper_translation < translation {
204 limit_separation = translation - prismatic_joint.upper_translation;
205 }
206 }
207
208 (perpendicular_separation * perpendicular_separation
209 + limit_separation * limit_separation)
210 .sqrt()
211 }
212
213 JointPayload::Revolute(_) => length(dp),
214
215 JointPayload::Weld(weld_joint) => {
216 if weld_joint.linear_hertz == 0.0 {
217 return length(dp);
218 }
219
220 0.0
221 }
222
223 JointPayload::Wheel(wheel_joint) => {
224 let axis_a = rotate_vector(xf_a.q, Vec2 { x: 1.0, y: 0.0 });
225 let perp_a = left_perp(axis_a);
226 let perpendicular_separation = abs_float(dot(perp_a, dp));
227 let mut limit_separation = 0.0;
228
229 if wheel_joint.enable_limit {
230 let translation = dot(axis_a, dp);
231 if translation < wheel_joint.lower_translation {
232 limit_separation = wheel_joint.lower_translation - translation;
233 }
234
235 if wheel_joint.upper_translation < translation {
236 limit_separation = translation - wheel_joint.upper_translation;
237 }
238 }
239
240 (perpendicular_separation * perpendicular_separation
241 + limit_separation * limit_separation)
242 .sqrt()
243 }
244 }
245}
246
247pub fn joint_get_angular_separation(world: &World, joint_id: JointId) -> f32 {
249 let joint_index = get_joint_full_id(world, joint_id);
250 let base = get_joint_sim_ref(world, joint_index);
251 let joint = &world.joints[joint_index as usize];
252
253 let q_a = crate::body::get_body_transform(world, joint.edges[0].body_id).q;
254 let q_b = crate::body::get_body_transform(world, joint.edges[1].body_id).q;
255 let relative_angle_ = relative_angle(q_a, q_b);
256
257 match &base.payload {
258 JointPayload::Distance(_) => 0.0,
259
260 JointPayload::Motor(_) => 0.0,
261
262 JointPayload::Filter => 0.0,
263
264 JointPayload::Prismatic(_) => relative_angle_,
265
266 JointPayload::Revolute(revolute_joint) => {
267 if revolute_joint.enable_limit {
268 let angle = relative_angle_;
269 if angle < revolute_joint.lower_angle {
270 return revolute_joint.lower_angle - angle;
271 }
272
273 if revolute_joint.upper_angle < angle {
274 return angle - revolute_joint.upper_angle;
275 }
276 }
277
278 0.0
279 }
280
281 JointPayload::Weld(weld_joint) => {
282 if weld_joint.angular_hertz == 0.0 {
283 return relative_angle_;
284 }
285
286 0.0
287 }
288
289 JointPayload::Wheel(_) => 0.0,
290 }
291}
292
293pub fn joint_set_constraint_tuning(
295 world: &mut World,
296 joint_id: JointId,
297 hertz: f32,
298 damping_ratio: f32,
299) {
300 debug_assert!(is_valid_float(hertz) && hertz >= 0.0);
301 debug_assert!(is_valid_float(damping_ratio) && damping_ratio >= 0.0);
302
303 let joint_index = get_joint_full_id(world, joint_id);
304 let base = get_joint_sim(world, joint_index);
305 base.constraint_hertz = hertz;
306 base.constraint_damping_ratio = damping_ratio;
307}
308
309pub fn joint_get_constraint_tuning(world: &World, joint_id: JointId) -> (f32, f32) {
311 let joint_index = get_joint_full_id(world, joint_id);
312 let base = get_joint_sim_ref(world, joint_index);
313 (base.constraint_hertz, base.constraint_damping_ratio)
314}
315
316pub fn joint_set_force_threshold(world: &mut World, joint_id: JointId, threshold: f32) {
318 debug_assert!(is_valid_float(threshold) && threshold >= 0.0);
319
320 let joint_index = get_joint_full_id(world, joint_id);
321 let base = get_joint_sim(world, joint_index);
322 base.force_threshold = threshold;
323}
324
325pub fn joint_get_force_threshold(world: &World, joint_id: JointId) -> f32 {
327 let joint_index = get_joint_full_id(world, joint_id);
328 get_joint_sim_ref(world, joint_index).force_threshold
329}
330
331pub fn joint_set_torque_threshold(world: &mut World, joint_id: JointId, threshold: f32) {
333 debug_assert!(is_valid_float(threshold) && threshold >= 0.0);
334
335 let joint_index = get_joint_full_id(world, joint_id);
336 let base = get_joint_sim(world, joint_index);
337 base.torque_threshold = threshold;
338}
339
340pub fn joint_get_torque_threshold(world: &World, joint_id: JointId) -> f32 {
342 let joint_index = get_joint_full_id(world, joint_id);
343 get_joint_sim_ref(world, joint_index).torque_threshold
344}