parry3d_f64/query/distance/
distance_composite_shape_shape.rs1use crate::bounding_volume::SimdAabb;
2use crate::math::{Isometry, Real, SimdBool, SimdReal, Vector, SIMD_WIDTH};
3use crate::partitioning::{SimdBestFirstVisitStatus, SimdBestFirstVisitor};
4use crate::query::QueryDispatcher;
5use crate::shape::{Shape, TypedSimdCompositeShape};
6use crate::utils::IsometryOpt;
7use simba::simd::{SimdBool as _, SimdPartialOrd, SimdValue};
8
9pub fn distance_composite_shape_shape<D, G1>(
11 dispatcher: &D,
12 pos12: &Isometry<Real>,
13 g1: &G1,
14 g2: &dyn Shape,
15) -> Real
16where
17 D: ?Sized + QueryDispatcher,
18 G1: ?Sized + TypedSimdCompositeShape,
19{
20 let mut visitor = CompositeShapeAgainstAnyDistanceVisitor::new(dispatcher, pos12, g1, g2);
21 g1.typed_qbvh()
22 .traverse_best_first(&mut visitor)
23 .expect("The composite shape must not be empty.")
24 .1
25 .1
26}
27
28pub fn distance_shape_composite_shape<D, G2>(
30 dispatcher: &D,
31 pos12: &Isometry<Real>,
32 g1: &dyn Shape,
33 g2: &G2,
34) -> Real
35where
36 D: ?Sized + QueryDispatcher,
37 G2: ?Sized + TypedSimdCompositeShape,
38{
39 distance_composite_shape_shape(dispatcher, &pos12.inverse(), g2, g1)
40}
41
42pub struct CompositeShapeAgainstAnyDistanceVisitor<'a, D: ?Sized, G1: ?Sized + 'a> {
44 msum_shift: Vector<SimdReal>,
45 msum_margin: Vector<SimdReal>,
46
47 dispatcher: &'a D,
48 pos12: &'a Isometry<Real>,
49 g1: &'a G1,
50 g2: &'a dyn Shape,
51}
52
53impl<'a, D: ?Sized, G1: ?Sized + 'a> CompositeShapeAgainstAnyDistanceVisitor<'a, D, G1> {
54 pub fn new(
56 dispatcher: &'a D,
57 pos12: &'a Isometry<Real>,
58 g1: &'a G1,
59 g2: &'a dyn Shape,
60 ) -> Self {
61 let ls_aabb2 = g2.compute_aabb(pos12);
62
63 Self {
64 dispatcher,
65 msum_shift: Vector::splat(-ls_aabb2.center().coords),
66 msum_margin: Vector::splat(ls_aabb2.half_extents()),
67 pos12,
68 g1,
69 g2,
70 }
71 }
72}
73
74impl<D, G1> SimdBestFirstVisitor<G1::PartId, SimdAabb>
75 for CompositeShapeAgainstAnyDistanceVisitor<'_, D, G1>
76where
77 D: ?Sized + QueryDispatcher,
78 G1: ?Sized + TypedSimdCompositeShape,
79{
80 type Result = (G1::PartId, Real);
81
82 fn visit(
83 &mut self,
84 best: Real,
85 bv: &SimdAabb,
86 data: Option<[Option<&G1::PartId>; SIMD_WIDTH]>,
87 ) -> SimdBestFirstVisitStatus<Self::Result> {
88 let msum = SimdAabb {
90 mins: bv.mins + self.msum_shift + (-self.msum_margin),
91 maxs: bv.maxs + self.msum_shift + self.msum_margin,
92 };
93 let dist = msum.distance_to_origin();
94 let mask = dist.simd_lt(SimdReal::splat(best));
95
96 if let Some(data) = data {
97 let bitmask = mask.bitmask();
98 let mut weights = [0.0; SIMD_WIDTH];
99 let mut mask = [false; SIMD_WIDTH];
100 let mut results = [None; SIMD_WIDTH];
101
102 for ii in 0..SIMD_WIDTH {
103 if (bitmask & (1 << ii)) != 0 && data[ii].is_some() {
104 let part_id = *data[ii].unwrap();
105 let mut dist = Ok(0.0);
106 self.g1.map_untyped_part_at(part_id, |part_pos1, g1, _| {
107 dist =
108 self.dispatcher
109 .distance(&part_pos1.inv_mul(self.pos12), g1, self.g2);
110 });
111
112 if let Ok(dist) = dist {
113 if dist == 0.0 {
114 return SimdBestFirstVisitStatus::ExitEarly(Some((part_id, 0.0)));
115 } else {
116 weights[ii] = dist;
117 mask[ii] = dist < best;
118 results[ii] = Some((part_id, dist));
119 }
120 }
121 }
122 }
123
124 SimdBestFirstVisitStatus::MaybeContinue {
125 weights: SimdReal::from(weights),
126 mask: SimdBool::from(mask),
127 results,
128 }
129 } else {
130 SimdBestFirstVisitStatus::MaybeContinue {
131 weights: dist,
132 mask,
133 results: [None; SIMD_WIDTH],
134 }
135 }
136 }
137}