rapier2d/dynamics/solver/
solver_body.rs1use crate::alloc_prelude::*;
2use crate::dynamics::RigidBody;
3use crate::math::{Real, SPATIAL_DIM, Vector};
4use crate::utils::{RotationOps, ScalarType};
5use core::ops::{AddAssign, Sub, SubAssign};
6use na::{DVectorView, DVectorViewMut};
7use parry::math::{Pose, Rotation, SIMD_WIDTH, SimdReal};
8
9use crate::utils::{SolverBlock, transpose_wide, transpose_wide_inv};
10
11macro_rules! aos(
12 ($data_repr: ident [ $idx: ident ] . $data_n: ident, $fallback: ident) => {
13 core::array::from_fn(|k| {
15 if ($idx[k] as usize) < $data_repr.len() {
16 $data_repr[$idx[k] as usize].$data_n.0
17 } else {
18 $fallback.$data_n.0
19 }
20 })
21 }
22);
23
24macro_rules! scatter(
25 ($data: ident [ $idx: ident [ $i: expr ] ] = [$($aos: ident),*]) => {
26 unsafe {
27 #[allow(clippy::missing_transmute_annotations)] if ($idx[$i] as usize) < $data.len() {
29 $data[$idx[$i] as usize] = core::mem::transmute([$($aos[$i]),*]);
30 }
31 }
32 }
33);
34
35pub(crate) const SOLVER_BODY_ALLOW_FAST_ROTATION: u8 = 1;
39
40#[derive(Default)]
41pub struct SolverBodies {
42 pub vels: Vec<SolverVel<Real>>,
43 pub poses: Vec<SolverPose<Real>>,
44 pub flags: Vec<u8>,
46}
47
48impl SolverBodies {
49 pub fn clear(&mut self) {
50 self.vels.clear();
51 self.poses.clear();
52 self.flags.clear();
53 }
54
55 pub fn resize(&mut self, sz: usize) {
56 self.vels.resize(sz, Default::default());
57 self.poses.resize(sz, Default::default());
58 self.flags.resize(sz, 0);
59 }
60
61 pub fn len(&self) -> usize {
62 self.vels.len()
63 }
64
65 #[cfg(feature = "solver-bounds-checks")]
70 #[inline]
71 pub fn assert_ids_in_range(&self, idx: [u32; SIMD_WIDTH]) {
72 let len = self.len();
73 for id in idx {
74 assert!(
75 id == u32::MAX || (id as usize) < len,
76 "stale solver-body id {id} (solver bodies: {len}) — solver contact graph corruption"
77 );
78 }
79 }
80
81 pub fn copy_from(&mut self, i: usize, rb: &RigidBody) {
83 let poses = &mut self.poses[i];
84 let vels = &mut self.vels[i];
85
86 self.flags[i] = if rb.ccd.allow_fast_rotation {
87 SOLVER_BODY_ALLOW_FAST_ROTATION
88 } else {
89 0
90 };
91
92 #[cfg(feature = "dim2")]
95 {
96 vels.angular = rb.vels.angvel;
97 }
98 #[cfg(feature = "dim3")]
99 {
100 vels.angular = rb.angvel();
101 }
102 vels.linear = rb.vels.linvel;
103
104 let pose = rb
105 .pos
106 .position
107 .prepend_translation(rb.mprops.local_mprops.local_com);
108 poses.rotation = pose.rotation;
109 poses.translation = pose.translation;
110
111 if rb.is_dynamic_or_kinematic() && !rb.is_sleeping() {
115 poses.ii = rb.mprops.effective_world_inv_inertia;
116 poses.im = rb.mprops.effective_inv_mass;
117 } else {
118 poses.ii = Default::default();
119 poses.im = Default::default();
120 }
121 }
122
123 #[inline]
124 pub fn gather_vels(&self, idx: [u32; SIMD_WIDTH]) -> SolverVel<SimdReal> {
125 SolverVel::gather(&self.vels, idx)
126 }
127
128 #[inline]
129 pub fn get_vel(&self, i: u32) -> SolverVel<Real> {
130 self.vels.get(i as usize).copied().unwrap_or_default()
131 }
132
133 #[inline]
134 pub fn scatter_vels(&mut self, idx: [u32; SIMD_WIDTH], vels: SolverVel<SimdReal>) {
135 vels.scatter(&mut self.vels, idx);
136 }
137
138 #[inline]
139 pub fn set_vel(&mut self, i: u32, vel: SolverVel<Real>) {
140 if (i as usize) < self.vels.len() {
141 self.vels[i as usize] = vel;
142 }
143 }
144
145 #[inline]
146 pub fn get_pose(&self, i: u32) -> SolverPose<Real> {
147 self.poses.get(i as usize).copied().unwrap_or_default()
148 }
149
150 #[inline]
151 pub fn gather_poses(&self, idx: [u32; SIMD_WIDTH]) -> SolverPose<SimdReal> {
152 SolverPose::gather(&self.poses, idx)
153 }
154
155 #[inline]
159 pub fn gather_transforms(&self, idx: [u32; SIMD_WIDTH]) -> SolverTransform<SimdReal> {
160 SolverTransform::gather(&self.poses, idx)
161 }
162}
163
164#[repr(C)]
166#[repr(align(16))]
167#[derive(Copy, Clone, Default)]
168pub struct SolverVel<T: ScalarType> {
169 pub linear: T::Vector, pub angular: T::AngVector, #[cfg(feature = "dim2")]
175 padding: [T; 1],
176 #[cfg(feature = "dim3")]
177 padding: [T; 2],
178}
179
180#[repr(C)]
181struct SolverVelRepr {
182 data0: SolverBlock,
183 #[cfg(feature = "dim3")]
184 data1: SolverBlock,
185}
186
187impl SolverVelRepr {
188 pub fn zero() -> Self {
189 Self {
190 data0: na::zero(),
191 #[cfg(feature = "dim3")]
192 data1: na::zero(),
193 }
194 }
195}
196
197impl SolverVel<SimdReal> {
198 #[inline]
199 pub fn gather(data: &[SolverVel<Real>], idx: [u32; SIMD_WIDTH]) -> Self {
200 let zero = SolverVelRepr::zero();
204 let data_repr: &[SolverVelRepr] = unsafe { core::mem::transmute(data) };
205
206 #[cfg(feature = "dim2")]
207 {
208 let aos = aos!(data_repr[idx].data0, zero);
209 let soa = transpose_wide(aos);
210 unsafe { core::mem::transmute(soa) }
211 }
212
213 #[cfg(feature = "dim3")]
214 {
215 let aos0 = aos!(data_repr[idx].data0, zero);
216 let soa0 = transpose_wide(aos0);
217 let aos1 = aos!(data_repr[idx].data1, zero);
218 let soa1 = transpose_wide(aos1);
219 unsafe { core::mem::transmute((soa0, soa1)) }
220 }
221 }
222
223 #[inline]
224 #[cfg(feature = "dim2")]
225 pub fn scatter(self, data: &mut [SolverVel<Real>], idx: [u32; SIMD_WIDTH]) {
226 let soa: [SimdReal; 4] = unsafe { core::mem::transmute(self) };
228 let aos = transpose_wide_inv(soa);
229 for i in 0..SIMD_WIDTH {
230 scatter!(data[idx[i]] = [aos]);
231 }
232 }
233
234 #[inline]
235 #[cfg(feature = "dim3")]
236 pub fn scatter(self, data: &mut [SolverVel<Real>], idx: [u32; SIMD_WIDTH]) {
237 let soa: [[SimdReal; 4]; 2] = unsafe { core::mem::transmute(self) };
238 let aos0 = transpose_wide_inv(soa[0]);
240 let aos1 = transpose_wide_inv(soa[1]);
241 for i in 0..SIMD_WIDTH {
242 scatter!(data[idx[i]] = [aos0, aos1]);
243 }
244 }
245}
246
247#[repr(C)]
249#[repr(align(16))]
250#[derive(Copy, Clone)]
251pub struct SolverPose<N: ScalarType> {
252 pub rotation: N::Rotation, pub translation: N::Vector, pub ii: N::AngInertia, pub im: N::Vector, #[cfg(feature = "dim2")]
258 pub padding: [N; 1],
259}
260
261impl SolverPose<Real> {
262 pub fn pose(&self) -> Pose {
263 Pose::from_parts(self.translation, self.rotation)
264 }
265}
266
267impl SolverPose<SimdReal> {
268 pub fn pose(&self) -> <SimdReal as ScalarType>::Pose {
269 <SimdReal as ScalarType>::Pose::from_parts(self.translation.into(), self.rotation)
270 }
271}
272
273impl<N: ScalarType> SolverPose<N> {
274 #[inline]
275 pub fn transform_point(&self, pt: N::Vector) -> N::Vector {
276 self.rotation * pt + self.translation
277 }
278
279 #[inline]
280 pub fn inverse_transform_point(&self, pt: N::Vector) -> N::Vector {
281 self.rotation.inverse() * (pt - self.translation)
282 }
283}
284
285#[repr(C)]
289#[derive(Copy, Clone)]
290pub struct SolverTransform<N: ScalarType> {
291 pub rotation: N::Rotation,
292 pub translation: N::Vector,
293}
294
295impl<N: ScalarType> SolverTransform<N> {
296 #[inline]
297 pub fn transform_point(&self, pt: N::Vector) -> N::Vector {
298 self.rotation * pt + self.translation
299 }
300}
301
302impl SolverTransform<SimdReal> {
303 #[inline]
304 pub fn gather(data: &[SolverPose<Real>], idx: [u32; SIMD_WIDTH]) -> Self {
305 let identity = SolverPoseRepr::identity();
306 let data_repr: &[SolverPoseRepr] = unsafe { core::mem::transmute(data) };
307
308 #[cfg(feature = "dim2")]
309 {
310 let aos0 = aos!(data_repr[idx].data0, identity);
313 let soa0 = transpose_wide(aos0);
314 unsafe { core::mem::transmute(soa0) }
315 }
316
317 #[cfg(feature = "dim3")]
318 {
319 let aos0 = aos!(data_repr[idx].data0, identity);
322 let aos1 = aos!(data_repr[idx].data1, identity);
323 let soa0 = transpose_wide(aos0);
324 let soa1 = transpose_wide(aos1);
325
326 #[repr(C)]
327 struct TransformAndPad {
328 transform: SolverTransform<SimdReal>,
329 _ii_xx: SimdReal,
331 }
332 let repr: TransformAndPad = unsafe { core::mem::transmute([soa0, soa1]) };
333 repr.transform
334 }
335 }
336}
337
338impl Default for SolverPose<Real> {
339 #[inline]
340 fn default() -> Self {
341 Self {
342 rotation: Rotation::IDENTITY,
343 translation: Vector::ZERO,
344 ii: Default::default(),
345 im: Default::default(),
346 #[cfg(feature = "dim2")]
347 padding: Default::default(),
348 }
349 }
350}
351
352#[repr(C)]
353struct SolverPoseRepr {
354 data0: SolverBlock,
355 data1: SolverBlock,
356 #[cfg(feature = "dim3")]
357 data2: SolverBlock,
358 #[cfg(feature = "dim3")]
359 data3: SolverBlock,
360}
361
362impl SolverPoseRepr {
363 pub fn identity() -> Self {
364 unsafe { core::mem::transmute(SolverPose::default()) }
367 }
368}
369
370impl SolverPose<SimdReal> {
371 #[inline]
372 pub fn gather(data: &[SolverPose<Real>], idx: [u32; SIMD_WIDTH]) -> Self {
373 let identity = SolverPoseRepr::identity();
377 let data_repr: &[SolverPoseRepr] = unsafe { core::mem::transmute(data) };
378
379 #[cfg(feature = "dim2")]
380 {
381 let aos0 = aos!(data_repr[idx].data0, identity);
382 let aos1 = aos!(data_repr[idx].data1, identity);
383 let soa0 = transpose_wide(aos0);
384 let soa1 = transpose_wide(aos1);
385 unsafe { core::mem::transmute([soa0, soa1]) }
386 }
387
388 #[cfg(feature = "dim3")]
389 {
390 let aos0 = aos!(data_repr[idx].data0, identity);
391 let aos1 = aos!(data_repr[idx].data1, identity);
392 let aos2 = aos!(data_repr[idx].data2, identity);
393 let aos3 = aos!(data_repr[idx].data3, identity);
394 let soa0 = transpose_wide(aos0);
395 let soa1 = transpose_wide(aos1);
396 let soa2 = transpose_wide(aos2);
397 let soa3 = transpose_wide(aos3);
398 unsafe { core::mem::transmute([soa0, soa1, soa2, soa3]) }
399 }
400 }
401}
402
403impl<N: ScalarType> SolverVel<N> {
404 pub fn as_slice(&self) -> &[N; SPATIAL_DIM] {
405 unsafe { core::mem::transmute(self) }
406 }
407
408 pub fn as_mut_slice(&mut self) -> &mut [N; SPATIAL_DIM] {
409 unsafe { core::mem::transmute(self) }
410 }
411
412 pub fn as_vector_slice(&self) -> DVectorView<'_, N> {
413 DVectorView::from_slice(&self.as_slice()[..], SPATIAL_DIM)
414 }
415
416 pub fn as_vector_slice_mut(&mut self) -> DVectorViewMut<'_, N> {
417 DVectorViewMut::from_slice(&mut self.as_mut_slice()[..], SPATIAL_DIM)
418 }
419}
420
421impl<N: ScalarType> SolverVel<N> {
422 pub fn zero() -> Self {
423 Self {
424 linear: Default::default(),
425 angular: Default::default(),
426 #[cfg(feature = "dim2")]
427 padding: [na::zero(); 1],
428 #[cfg(feature = "dim3")]
429 padding: [na::zero(); 2],
430 }
431 }
432}
433
434impl<N: ScalarType> AddAssign for SolverVel<N> {
435 fn add_assign(&mut self, rhs: Self) {
436 self.linear += rhs.linear;
437 self.angular += rhs.angular;
438 }
439}
440
441impl<N: ScalarType> SubAssign for SolverVel<N> {
442 fn sub_assign(&mut self, rhs: Self) {
443 self.linear -= rhs.linear;
444 self.angular -= rhs.angular;
445 }
446}
447
448impl<N: ScalarType> Sub for SolverVel<N> {
449 type Output = Self;
450
451 fn sub(self, rhs: Self) -> Self {
452 SolverVel {
453 linear: self.linear - rhs.linear,
454 angular: self.angular - rhs.angular,
455 padding: self.padding,
456 }
457 }
458}