1#![allow(rustdoc::broken_intra_doc_links)]
2use crate::types::BodyId;
3use crate::world::World;
4use boxdd_sys::ffi;
5
6use super::{Joint, JointBase, OwnedJoint, raw_body_id};
7use crate::error::ApiResult;
8
9#[derive(Clone, Debug)]
11pub struct WheelJointDef(pub(crate) ffi::b2WheelJointDef);
17
18impl WheelJointDef {
19 pub fn new(base: JointBase) -> Self {
20 let mut def: ffi::b2WheelJointDef = unsafe { ffi::b2DefaultWheelJointDef() };
21 def.base = base.0;
22 Self(def)
23 }
24
25 #[inline]
26 pub fn from_raw(raw: ffi::b2WheelJointDef) -> Self {
27 Self(raw)
28 }
29
30 #[inline]
31 pub fn base(&self) -> JointBase {
32 JointBase(self.0.base)
33 }
34
35 #[inline]
36 pub fn spring_enabled(&self) -> bool {
37 self.0.enableSpring
38 }
39
40 #[inline]
41 pub fn spring_hertz(&self) -> f32 {
42 self.0.hertz
43 }
44
45 #[inline]
46 pub fn spring_damping_ratio(&self) -> f32 {
47 self.0.dampingRatio
48 }
49
50 #[inline]
51 pub fn limit_enabled(&self) -> bool {
52 self.0.enableLimit
53 }
54
55 #[inline]
56 pub fn minimum_translation(&self) -> f32 {
57 self.0.lowerTranslation
58 }
59
60 #[inline]
61 pub fn maximum_translation(&self) -> f32 {
62 self.0.upperTranslation
63 }
64
65 #[inline]
66 pub fn motor_enabled(&self) -> bool {
67 self.0.enableMotor
68 }
69
70 #[inline]
71 pub fn maximum_motor_torque(&self) -> f32 {
72 self.0.maxMotorTorque
73 }
74
75 #[inline]
76 pub fn target_motor_speed(&self) -> f32 {
77 self.0.motorSpeed
78 }
79
80 #[inline]
81 pub fn into_raw(self) -> ffi::b2WheelJointDef {
82 self.0
83 }
84
85 #[inline]
86 pub fn validate(&self) -> ApiResult<()> {
87 super::check_wheel_joint_def_valid(self)
88 }
89
90 pub fn enable_spring(mut self, flag: bool) -> Self {
92 self.0.enableSpring = flag;
93 self
94 }
95 pub fn hertz(mut self, v: f32) -> Self {
97 self.0.hertz = v;
98 self
99 }
100 pub fn damping_ratio(mut self, v: f32) -> Self {
102 self.0.dampingRatio = v;
103 self
104 }
105 pub fn enable_limit(mut self, flag: bool) -> Self {
107 self.0.enableLimit = flag;
108 self
109 }
110 pub fn lower_translation(mut self, v: f32) -> Self {
112 self.0.lowerTranslation = v;
113 self
114 }
115 pub fn upper_translation(mut self, v: f32) -> Self {
117 self.0.upperTranslation = v;
118 self
119 }
120 pub fn enable_motor(mut self, flag: bool) -> Self {
122 self.0.enableMotor = flag;
123 self
124 }
125 pub fn max_motor_torque(mut self, v: f32) -> Self {
127 self.0.maxMotorTorque = v;
128 self
129 }
130 pub fn motor_speed(mut self, v: f32) -> Self {
132 self.0.motorSpeed = v;
133 self
134 }
135 pub fn motor_speed_deg(mut self, speed_deg_per_s: f32) -> Self {
137 self.0.motorSpeed = speed_deg_per_s * (core::f32::consts::PI / 180.0);
138 self
139 }
140}
141
142pub struct WheelJointBuilder<'w> {
144 pub(crate) world: &'w mut World,
145 pub(crate) body_a: BodyId,
146 pub(crate) body_b: BodyId,
147 pub(crate) anchor_a_world: Option<ffi::b2Vec2>,
148 pub(crate) anchor_b_world: Option<ffi::b2Vec2>,
149 pub(crate) axis_world: Option<ffi::b2Vec2>,
150 pub(crate) def: WheelJointDef,
151}
152
153impl<'w> WheelJointBuilder<'w> {
154 pub fn anchors_world<VA: Into<crate::types::Vec2>, VB: Into<crate::types::Vec2>>(
156 mut self,
157 a: VA,
158 b: VB,
159 ) -> Self {
160 self.anchor_a_world = Some(a.into().into_raw());
161 self.anchor_b_world = Some(b.into().into_raw());
162 self
163 }
164 pub fn axis_world<V: Into<crate::types::Vec2>>(mut self, axis: V) -> Self {
166 self.axis_world = Some(axis.into().into_raw());
167 self
168 }
169 pub fn limit(mut self, lower: f32, upper: f32) -> Self {
170 self.def = self
171 .def
172 .enable_limit(true)
173 .lower_translation(lower)
174 .upper_translation(upper);
175 self
176 }
177 pub fn motor(mut self, max_torque: f32, speed: f32) -> Self {
178 self.def = self
179 .def
180 .enable_motor(true)
181 .max_motor_torque(max_torque)
182 .motor_speed(speed);
183 self
184 }
185 pub fn motor_deg(mut self, max_torque: f32, speed_deg: f32) -> Self {
186 self.def = self
187 .def
188 .enable_motor(true)
189 .max_motor_torque(max_torque)
190 .motor_speed_deg(speed_deg);
191 self
192 }
193 pub fn spring(mut self, hertz: f32, damping_ratio: f32) -> Self {
194 self.def = self
195 .def
196 .enable_spring(true)
197 .hertz(hertz)
198 .damping_ratio(damping_ratio);
199 self
200 }
201 pub fn collide_connected(mut self, flag: bool) -> Self {
202 self.def.0.base.collideConnected = flag;
203 self
204 }
205
206 pub fn with_limit_and_motor(
210 mut self,
211 lower: f32,
212 upper: f32,
213 max_torque: f32,
214 speed: f32,
215 ) -> Self {
216 self = self.limit(lower, upper);
217 self = self.motor(max_torque, speed);
218 self
219 }
220 pub fn with_limit_and_motor_deg(
224 mut self,
225 lower: f32,
226 upper: f32,
227 max_torque: f32,
228 speed_deg: f32,
229 ) -> Self {
230 self = self.limit(lower, upper);
231 self = self.motor_deg(max_torque, speed_deg);
232 self
233 }
234 pub fn with_limit_and_spring(
238 mut self,
239 lower: f32,
240 upper: f32,
241 hertz: f32,
242 damping_ratio: f32,
243 ) -> Self {
244 self = self.limit(lower, upper);
245 self = self.spring(hertz, damping_ratio);
246 self
247 }
248 pub fn with_motor_and_spring(
251 mut self,
252 max_torque: f32,
253 speed: f32,
254 hertz: f32,
255 damping_ratio: f32,
256 ) -> Self {
257 self = self.motor(max_torque, speed);
258 self = self.spring(hertz, damping_ratio);
259 self
260 }
261 pub fn with_motor_and_spring_deg(
264 mut self,
265 max_torque: f32,
266 speed_deg: f32,
267 hertz: f32,
268 damping_ratio: f32,
269 ) -> Self {
270 self = self.motor_deg(max_torque, speed_deg);
271 self = self.spring(hertz, damping_ratio);
272 self
273 }
274 pub fn with_limit_motor_spring(
278 mut self,
279 lower: f32,
280 upper: f32,
281 max_torque: f32,
282 speed: f32,
283 hertz: f32,
284 damping_ratio: f32,
285 ) -> Self {
286 self = self.limit(lower, upper);
287 self = self.motor(max_torque, speed);
288 self = self.spring(hertz, damping_ratio);
289 self
290 }
291 pub fn with_limit_motor_spring_deg(
295 mut self,
296 lower: f32,
297 upper: f32,
298 max_torque: f32,
299 speed_deg: f32,
300 hertz: f32,
301 damping_ratio: f32,
302 ) -> Self {
303 self = self.limit(lower, upper);
304 self = self.motor_deg(max_torque, speed_deg);
305 self = self.spring(hertz, damping_ratio);
306 self
307 }
308
309 #[must_use]
310 pub fn build(mut self) -> Joint<'w> {
311 crate::core::debug_checks::assert_body_valid(self.body_a);
312 crate::core::debug_checks::assert_body_valid(self.body_b);
313 let ta = unsafe { ffi::b2Body_GetTransform(raw_body_id(self.body_a)) };
315 let tb = unsafe { ffi::b2Body_GetTransform(raw_body_id(self.body_b)) };
316 let aw = self.anchor_a_world.unwrap_or(ta.p);
317 let bw = self.anchor_b_world.unwrap_or(tb.p);
318 let axis = self.axis_world.unwrap_or(ffi::b2Vec2 { x: 1.0, y: 0.0 });
319 let la = crate::core::math::world_to_local_point(ta, aw);
320 let lb = crate::core::math::world_to_local_point(tb, bw);
321 let ra = crate::core::math::world_axis_to_local_rot(ta, axis);
322 let rb = crate::core::math::world_axis_to_local_rot(tb, axis);
323 self.def.0.base.bodyIdA = raw_body_id(self.body_a);
324 self.def.0.base.bodyIdB = raw_body_id(self.body_b);
325 self.def.0.base.localFrameA = ffi::b2Transform { p: la, q: ra };
326 self.def.0.base.localFrameB = ffi::b2Transform { p: lb, q: rb };
327 self.world.create_wheel_joint(&self.def)
328 }
329
330 pub fn try_build(mut self) -> ApiResult<Joint<'w>> {
331 crate::core::debug_checks::check_body_valid(self.body_a)?;
332 crate::core::debug_checks::check_body_valid(self.body_b)?;
333 let ta = unsafe { ffi::b2Body_GetTransform(raw_body_id(self.body_a)) };
334 let tb = unsafe { ffi::b2Body_GetTransform(raw_body_id(self.body_b)) };
335 let aw = self.anchor_a_world.unwrap_or(ta.p);
336 let bw = self.anchor_b_world.unwrap_or(tb.p);
337 let axis = self.axis_world.unwrap_or(ffi::b2Vec2 { x: 1.0, y: 0.0 });
338 let la = crate::core::math::world_to_local_point(ta, aw);
339 let lb = crate::core::math::world_to_local_point(tb, bw);
340 let ra = crate::core::math::world_axis_to_local_rot(ta, axis);
341 let rb = crate::core::math::world_axis_to_local_rot(tb, axis);
342 self.def.0.base.bodyIdA = raw_body_id(self.body_a);
343 self.def.0.base.bodyIdB = raw_body_id(self.body_b);
344 self.def.0.base.localFrameA = ffi::b2Transform { p: la, q: ra };
345 self.def.0.base.localFrameB = ffi::b2Transform { p: lb, q: rb };
346 self.world.try_create_wheel_joint(&self.def)
347 }
348
349 #[must_use]
350 pub fn build_owned(mut self) -> OwnedJoint {
351 crate::core::debug_checks::assert_body_valid(self.body_a);
352 crate::core::debug_checks::assert_body_valid(self.body_b);
353 let ta = unsafe { ffi::b2Body_GetTransform(raw_body_id(self.body_a)) };
355 let tb = unsafe { ffi::b2Body_GetTransform(raw_body_id(self.body_b)) };
356 let aw = self.anchor_a_world.unwrap_or(ta.p);
357 let bw = self.anchor_b_world.unwrap_or(tb.p);
358 let axis = self.axis_world.unwrap_or(ffi::b2Vec2 { x: 1.0, y: 0.0 });
359 let la = crate::core::math::world_to_local_point(ta, aw);
360 let lb = crate::core::math::world_to_local_point(tb, bw);
361 let ra = crate::core::math::world_axis_to_local_rot(ta, axis);
362 let rb = crate::core::math::world_axis_to_local_rot(tb, axis);
363 self.def.0.base.bodyIdA = raw_body_id(self.body_a);
364 self.def.0.base.bodyIdB = raw_body_id(self.body_b);
365 self.def.0.base.localFrameA = ffi::b2Transform { p: la, q: ra };
366 self.def.0.base.localFrameB = ffi::b2Transform { p: lb, q: rb };
367 self.world.create_wheel_joint_owned(&self.def)
368 }
369
370 pub fn try_build_owned(mut self) -> ApiResult<OwnedJoint> {
371 crate::core::debug_checks::check_body_valid(self.body_a)?;
372 crate::core::debug_checks::check_body_valid(self.body_b)?;
373 let ta = unsafe { ffi::b2Body_GetTransform(raw_body_id(self.body_a)) };
374 let tb = unsafe { ffi::b2Body_GetTransform(raw_body_id(self.body_b)) };
375 let aw = self.anchor_a_world.unwrap_or(ta.p);
376 let bw = self.anchor_b_world.unwrap_or(tb.p);
377 let axis = self.axis_world.unwrap_or(ffi::b2Vec2 { x: 1.0, y: 0.0 });
378 let la = crate::core::math::world_to_local_point(ta, aw);
379 let lb = crate::core::math::world_to_local_point(tb, bw);
380 let ra = crate::core::math::world_axis_to_local_rot(ta, axis);
381 let rb = crate::core::math::world_axis_to_local_rot(tb, axis);
382 self.def.0.base.bodyIdA = raw_body_id(self.body_a);
383 self.def.0.base.bodyIdB = raw_body_id(self.body_b);
384 self.def.0.base.localFrameA = ffi::b2Transform { p: la, q: ra };
385 self.def.0.base.localFrameB = ffi::b2Transform { p: lb, q: rb };
386 self.world.try_create_wheel_joint_owned(&self.def)
387 }
388}