Skip to main content

zvxryb_broadphase/
index.rs

1// mlodato, 2020
2
3use cgmath::{Point2, Point3, Vector2, Vector3};
4use cgmath::prelude::*;
5use std::fmt::{Debug, Formatter};
6
7/// An index representing an object's position and scale
8/// 
9/// The `Ord` trait must be implemented such that sorting produces a topological ordering.
10/// 
11/// This may be accomplished using trivial comparison operators for a primitive integer type by:
12///
13/// 1. Packing bits such that `origin` is higher-significance than `depth`
14/// 2. Storing the value of `origin` as a Morton code
15/// 3. Truncating `origin` bits to the level specified by `depth`, such that it represents the _minimum bound_
16///    of the cell at the given scale
17/// 
18/// Currently, requirement #3 (truncating origin) is not the responsibility of the particular `SpatialIndex`
19/// implementation — an appropriately-truncated value must be passed as an argument to `set_origin`
20/// 
21/// `Ord` should be implemented such that an X-bit is lower significance (changes more rapidly) than the
22/// corresponding a Y-bit (which should, likewise, be lower significance than the corresponding Z-bit for
23/// 3D indices)
24/// 
25/// `<SpatialIndex as Default>::default()` is required to return an index which encompasses the entire system
26/// bounds (i.e. zero origin and zero depth)
27/// 
28/// The following index types are provided:
29/// 
30/// [`Index32_2D`]: struct.Index32_2D.html
31/// [`Index64_2D`]: struct.Index64_2D.html
32/// [`Index64_3D`]: struct.Index64_3D.html
33/// 
34/// * [`Index32_2D`]: A 32-bit 2D index type providing 14 bits' precision per axis
35/// * [`Index64_2D`]: A 64-bit 2D index type providing 29 bits' precision per axis
36/// * [`Index64_3D`]: A 64-bit 3D index type providing 19 bits' precision per axis
37
38pub trait SpatialIndex: Clone + Copy + Default + Ord + Send + std::fmt::Debug {
39    type Diff: cgmath::VectorSpace<Scalar = u32>;
40    type Point: Copy + EuclideanSpace<Diff = Self::Diff, Scalar = u32>;
41
42    /// clamps a depth value to the representable range
43    fn clamp_depth(_: u32) -> u32;
44
45    fn origin(self) -> Self::Point;
46    fn depth(self) -> u32;
47
48    fn set_origin(self, _: Self::Point) -> Self;
49    fn set_depth(self, _: u32) -> Self;
50
51    type SubdivideResult: AsRef<[Self]>;
52
53    /// Subdivide the cell represented by this index into cells of `depth + 1`
54    /// 
55    /// This is required to return results in sorted order.  Returns `None` if depth limit has been reached.
56    fn subdivide(self) -> Option<Self::SubdivideResult>;
57
58    /// Check if two indices represent overlapping regions of space
59    fn overlaps(self, other: Self) -> bool;
60
61    /// Check if two indices would fall into the same cell at a given (truncated) depth
62    fn same_cell_at_depth(lhs: Self, rhs: Self, depth: u32) -> bool;
63}
64
65macro_rules! index_impl {
66    (index: $name:ident, $dim:tt, $bits:tt, $depth_bits:tt, $axis_bits:tt) => {
67        #[derive(Clone, Copy, Default, Eq, Ord, PartialEq, PartialOrd)]
68        #[cfg_attr(any(test, feature="serde"), derive(Deserialize, Serialize))]
69        pub struct $name(index_impl!{primitive_type: $bits});
70
71        impl $name {
72            const DEPTH_BITS: u32 = $depth_bits;
73            const DEPTH_SHIFT: u32 = 0;
74            const DEPTH_MASK: index_impl!{primitive_type: $bits} = (((1 as index_impl!{primitive_type: $bits}) << Self::DEPTH_BITS) - 1) << Self::DEPTH_SHIFT;
75            const AXIS_BITS: u32 = $axis_bits;
76            const ORIGIN_BITS: u32 = $dim * Self::AXIS_BITS;
77            const ORIGIN_SHIFT: u32 = Self::DEPTH_SHIFT + Self::DEPTH_BITS;
78            const ORIGIN_MASK: index_impl!{primitive_type: $bits} = (((1 as index_impl!{primitive_type: $bits}) << (Self::ORIGIN_BITS)) - 1) << Self::ORIGIN_SHIFT;
79
80            index_impl!{codec: $dim, $bits}
81        
82            fn level_mask(depth: u32) -> index_impl!{primitive_type: $bits} {
83                if depth <= 0 { 0 } else {
84                    (((1 as index_impl!{primitive_type: $bits}) << ($dim * depth)) - 1) << (Self::ORIGIN_BITS + Self::ORIGIN_SHIFT - $dim * depth)
85                }
86            }
87        }
88
89        impl SpatialIndex for $name {
90            type Diff  = index_impl!{vector_type: $dim};
91            type Point = index_impl!{point_type: $dim};
92
93            fn clamp_depth(depth: u32) -> u32 {
94                std::cmp::min(depth, Self::AXIS_BITS)
95            }
96
97            index_impl!{origin: $dim}
98
99            fn depth(self) -> u32 {
100                let Self(index) = self;
101                ((index & Self::DEPTH_MASK) >> Self::DEPTH_SHIFT) as u32
102            }
103
104            index_impl!{set_origin: $dim}
105
106            fn set_depth(self, depth: u32) -> Self {
107                let Self(mut index) = self;
108                index &= !Self::DEPTH_MASK;
109                index |= Self::DEPTH_MASK & (
110                    <index_impl!{primitive_type: $bits} as From<u32>>::from(Self::clamp_depth(depth)) << Self::DEPTH_SHIFT);
111                Self(index)
112            }
113
114            index_impl!{subdivide: $dim, $bits}
115
116            fn overlaps(self, other: Self) -> bool {
117                Self::same_cell_at_depth(self, other, std::cmp::min(self.depth(), other.depth()))
118            }
119
120            fn same_cell_at_depth(Self(lhs): Self, Self(rhs): Self, depth: u32) -> bool {
121                (lhs ^ rhs) & Self::level_mask(depth) == 0
122            }
123        }
124    };
125    (primitive_type: 32) => {u32};
126    (primitive_type: 64) => {u64};
127    (vector_type: 2) => {Vector2<u32>};
128    (vector_type: 3) => {Vector3<u32>};
129    (point_type: 2) => {Point2<u32>};
130    (point_type: 3) => {Point3::<u32>};
131    (codec: 2, $bits:tt) => {
132        #[allow(overflowing_literals)] // allow (intentional) truncating casts
133        #[inline]
134        fn decode_axis(origin: index_impl!{primitive_type: $bits}) -> u32 {
135            let axis00 =  origin & 0x1111_1111_1111_1111 as index_impl!{primitive_type: $bits};
136            let axis01 = (origin & 0x4444_4444_4444_4444 as index_impl!{primitive_type: $bits}) >> 0x01;
137            let axis0_ = axis00 | axis01;
138            let axis10 =  axis0_ & 0x0303_0303_0303_0303 as index_impl!{primitive_type: $bits};
139            let axis11 = (axis0_ & 0x3030_3030_3030_3030 as index_impl!{primitive_type: $bits}) >> 0x02;
140            let axis1_ = axis10 | axis11;
141            let axis20 =  axis1_ & 0x000f_000f_000f_000f as index_impl!{primitive_type: $bits};
142            let axis21 = (axis1_ & 0x0f00_0f00_0f00_0f00 as index_impl!{primitive_type: $bits}) >> 0x04;
143            let axis2_ = axis20 | axis21;
144            let axis30 =  axis2_ & 0x0000_00ff_0000_00ff as index_impl!{primitive_type: $bits};
145            let axis31 = (axis2_ & 0x00ff_0000_00ff_0000 as index_impl!{primitive_type: $bits}) >> 0x08;
146            let axis3_ = axis30 | axis31;
147            let axis40 =  axis3_ & 0x0000_0000_0000_ffff as index_impl!{primitive_type: $bits};
148            let axis41 = (axis3_ & 0x0000_ffff_0000_0000 as index_impl!{primitive_type: $bits}) >> 0x10;
149            let axis4_ = axis40 | axis41;
150            (axis4_ as u32) << (32 - Self::AXIS_BITS)
151        }
152
153        #[allow(overflowing_literals)] // allow (intentional) truncating casts
154        #[inline]
155        fn encode_axis(origin: u32) -> index_impl!{primitive_type: $bits} {
156            let axis0_ = <index_impl!{primitive_type: $bits} as From<u32>>::from(origin >> (32 - Self::AXIS_BITS));
157            let axis00 =  axis0_          & 0x0000_0000_0000_ffff as index_impl!{primitive_type: $bits};
158            let axis01 = (axis0_ << 0x10) & 0x0000_ffff_0000_0000 as index_impl!{primitive_type: $bits};
159            let axis1_ = axis00 | axis01;
160            let axis10 =  axis1_          & 0x0000_00ff_0000_00ff as index_impl!{primitive_type: $bits};
161            let axis11 = (axis1_ << 0x08) & 0x00ff_0000_00ff_0000 as index_impl!{primitive_type: $bits};
162            let axis2_ = axis10 | axis11;
163            let axis20 =  axis2_          & 0x000f_000f_000f_000f as index_impl!{primitive_type: $bits};
164            let axis21 = (axis2_ << 0x04) & 0x0f00_0f00_0f00_0f00 as index_impl!{primitive_type: $bits};
165            let axis3_ = axis20 | axis21;
166            let axis30 =  axis3_          & 0x0303_0303_0303_0303 as index_impl!{primitive_type: $bits};
167            let axis31 = (axis3_ << 0x02) & 0x3030_3030_3030_3030 as index_impl!{primitive_type: $bits};
168            let axis4_ = axis30 | axis31;
169            let axis40 =  axis4_          & 0x1111_1111_1111_1111 as index_impl!{primitive_type: $bits};
170            let axis41 = (axis4_ << 0x01) & 0x4444_4444_4444_4444 as index_impl!{primitive_type: $bits};
171            axis40 | axis41
172        }
173    };
174    (codec: 3, $bits:tt) => {
175        #[inline]
176        fn decode_axis(origin: index_impl!{primitive_type: $bits}) -> u32 {
177            let axis00 =  origin & 0o1_001_001_001_001_001_001_001 as index_impl!{primitive_type: $bits};
178            let axis01 = (origin & 0o0_010_010_010_010_010_010_010 as index_impl!{primitive_type: $bits}) >> 0o02;
179            let axis02 = (origin & 0o0_100_100_100_100_100_100_100 as index_impl!{primitive_type: $bits}) >> 0o04;
180            let axis0_ = axis00 | axis01 | axis02;
181            let axis10 =  axis0_ & 0o0_007_000_000_007_000_000_007 as index_impl!{primitive_type: $bits};
182            let axis11 = (axis0_ & 0o1_000_000_007_000_000_007_000 as index_impl!{primitive_type: $bits}) >> 0o06;
183            let axis12 = (axis0_ & 0o0_000_007_000_000_007_000_000 as index_impl!{primitive_type: $bits}) >> 0o14;
184            let axis1_ = axis10 | axis11 | axis12;
185            let axis20 =  axis1_ & 0o0_000_000_000_000_000_000_777 as index_impl!{primitive_type: $bits};
186            let axis21 = (axis1_ & 0o0_000_000_000_777_000_000_000 as index_impl!{primitive_type: $bits}) >> 0o22;
187            let axis22 = (axis1_ & 0o0_777_000_000_000_000_000_000 as index_impl!{primitive_type: $bits}) >> 0o44;
188            let axis2_ = axis20 | axis21 | axis22;
189            (axis2_ as u32) << (32 - Self::AXIS_BITS)
190        }
191
192        #[inline]
193        fn encode_axis(origin: u32) -> index_impl!{primitive_type: $bits} {
194            let axis0_ = <index_impl!{primitive_type: $bits} as From<u32>>::from(origin >> (32 - Self::AXIS_BITS));
195            let axis00 =  axis0_          & 0o0_000_000_000_000_000_000_777 as index_impl!{primitive_type: $bits};
196            let axis01 = (axis0_ << 0o22) & 0o0_000_000_000_777_000_000_000 as index_impl!{primitive_type: $bits};
197            let axis02 = (axis0_ << 0o44) & 0o0_777_000_000_000_000_000_000 as index_impl!{primitive_type: $bits};
198            let axis1_ = axis00 | axis01 | axis02;
199            let axis10 =  axis1_          & 0o0_007_000_000_007_000_000_007 as index_impl!{primitive_type: $bits};
200            let axis11 = (axis1_ << 0o06) & 0o1_000_000_007_000_000_007_000 as index_impl!{primitive_type: $bits};
201            let axis12 = (axis1_ << 0o14) & 0o0_000_007_000_000_007_000_000 as index_impl!{primitive_type: $bits};
202            let axis2_ = axis10 | axis11 | axis12;
203            let axis20 =  axis2_          & 0o1_001_001_001_001_001_001_001 as index_impl!{primitive_type: $bits};
204            let axis21 = (axis2_ << 0o02) & 0o0_010_010_010_010_010_010_010 as index_impl!{primitive_type: $bits};
205            let axis22 = (axis2_ << 0o04) & 0o0_100_100_100_100_100_100_100 as index_impl!{primitive_type: $bits};
206            axis20 | axis21 | axis22
207        }
208    };
209    (origin: 2) => {
210        fn origin(self) -> index_impl!{point_type: 2} {
211            let Self(index) = self;
212            let origin = (index & Self::ORIGIN_MASK) >> Self::ORIGIN_SHIFT;
213            Point2::new(
214                Self::decode_axis(origin),
215                Self::decode_axis(origin >> 1),
216            )
217        }
218    };
219    (origin: 3) => {
220        fn origin(self) -> index_impl!{point_type: 3} {
221            let Self(index) = self;
222            let origin = (index & Self::ORIGIN_MASK) >> Self::ORIGIN_SHIFT;
223            Point3::new(
224                Self::decode_axis(origin),
225                Self::decode_axis(origin >> 1),
226                Self::decode_axis(origin >> 2),
227            )
228        }
229    };
230    (set_origin: 2) => {
231        fn set_origin(self, origin: index_impl!{point_type: 2}) -> Self {
232            let origin = Self::encode_axis(origin.x)
233                       | Self::encode_axis(origin.y) << 1;
234            let Self(mut index) = self;
235            index &= !Self::ORIGIN_MASK;
236            index |= Self::ORIGIN_MASK & (origin << Self::ORIGIN_SHIFT);
237            Self(index)
238        }
239    };
240    (set_origin: 3) => {
241        fn set_origin(self, origin: index_impl!{point_type: 3}) -> Self {
242            let origin = Self::encode_axis(origin.x)
243                       | Self::encode_axis(origin.y) << 1
244                       | Self::encode_axis(origin.z) << 2;
245            let Self(mut index) = self;
246            index &= !Self::ORIGIN_MASK;
247            index |= Self::ORIGIN_MASK & (origin << Self::ORIGIN_SHIFT);
248            Self(index)
249        }
250    };
251    (subdivide: 2, $bits:tt) => {
252        type SubdivideResult = [Self; 4];
253        fn subdivide(self) -> Option<[Self; 4]> {
254            let depth = self.depth();
255            if depth < Self::AXIS_BITS {
256                let Self(index) = self;
257                let shift = Self::ORIGIN_BITS + Self::ORIGIN_SHIFT - (2 * (depth + 1));
258                Some([
259                    Self(index | (0b00 as index_impl!{primitive_type: $bits} << shift)).set_depth(depth + 1),
260                    Self(index | (0b01 as index_impl!{primitive_type: $bits} << shift)).set_depth(depth + 1),
261                    Self(index | (0b10 as index_impl!{primitive_type: $bits} << shift)).set_depth(depth + 1),
262                    Self(index | (0b11 as index_impl!{primitive_type: $bits} << shift)).set_depth(depth + 1)
263                ])
264            } else {
265                None
266            }
267        }
268    };
269    (subdivide: 3, $bits:tt) => {
270        type SubdivideResult = [Self; 8];
271        fn subdivide(self) -> Option<[Self; 8]> {
272            let depth = self.depth();
273            if depth < Self::AXIS_BITS {
274                let Self(index) = self;
275                let shift = Self::ORIGIN_BITS + Self::ORIGIN_SHIFT - (3 * (depth + 1));
276                Some([
277                    Self(index | (0b000 as index_impl!{primitive_type: $bits} << shift)).set_depth(depth + 1),
278                    Self(index | (0b001 as index_impl!{primitive_type: $bits} << shift)).set_depth(depth + 1),
279                    Self(index | (0b010 as index_impl!{primitive_type: $bits} << shift)).set_depth(depth + 1),
280                    Self(index | (0b011 as index_impl!{primitive_type: $bits} << shift)).set_depth(depth + 1),
281                    Self(index | (0b100 as index_impl!{primitive_type: $bits} << shift)).set_depth(depth + 1),
282                    Self(index | (0b101 as index_impl!{primitive_type: $bits} << shift)).set_depth(depth + 1),
283                    Self(index | (0b110 as index_impl!{primitive_type: $bits} << shift)).set_depth(depth + 1),
284                    Self(index | (0b111 as index_impl!{primitive_type: $bits} << shift)).set_depth(depth + 1)
285                ])
286            } else {
287                None
288            }
289        }
290    };
291}
292
293index_impl!{index: Index32_2D, 2, 32, 4, 14}
294index_impl!{index: Index64_2D, 2, 64, 5, 29}
295index_impl!{index: Index64_3D, 3, 64, 5, 19}
296
297impl Debug for Index64_3D {
298    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
299        let Self(index) = self;
300        let origin_bits = (index & Self::ORIGIN_MASK) >> Self::ORIGIN_SHIFT;
301        let origin = self.origin();
302        write!(f, "Index64_3D{{origin={{0o{:019o}, <0x{:08x}, 0x{:08x}, 0x{:08x}>}}, depth={:}}}",
303            origin_bits,
304            origin.x,
305            origin.y,
306            origin.z,
307            self.depth())
308    }
309}
310
311impl Debug for Index32_2D {
312    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
313        let Self(index) = self;
314        let origin_bits = (index & Self::ORIGIN_MASK) >> Self::ORIGIN_SHIFT;
315        let origin = self.origin();
316        write!(f, "Index32_2D{{origin={{0x{:011x}, <0x{:04x}, 0x{:04x}>}}, depth={:}}}",
317            origin_bits,
318            origin.x,
319            origin.y,
320            self.depth())
321    }
322}
323
324impl Debug for Index64_2D {
325    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
326        let Self(index) = self;
327        let origin_bits = (index & Self::ORIGIN_MASK) >> Self::ORIGIN_SHIFT;
328        let origin = self.origin();
329        write!(f, "Index64_2D{{origin={{0x{:022x}, <0x{:08x}, 0x{:08x}>}}, depth={:}}}",
330            origin_bits,
331            origin.x,
332            origin.y,
333            self.depth())
334    }
335}
336
337#[cfg(test)]
338mod tests {
339    use super::*;
340    use rand::prelude::*;
341
342    #[test]
343    fn decode() {
344        assert_eq!(
345            Index64_3D::decode_axis(0o0_001_111_111_111_111_111_111),
346            0o1_777_777u32 << 13
347        );
348        assert_eq!(
349            Index64_3D::decode_axis(0o0_006_666_666_666_666_666_666),
350            0o0_000_000u32 << 13
351        );
352    }
353
354    #[test]
355    fn encode() {
356        assert_eq!(
357            Index64_3D::encode_axis(0o1_777_777u32 << 13),
358            0o0_001_111_111_111_111_111_111
359        );
360        assert_eq!(
361            Index64_3D::encode_axis(0o0_000_000u32 << 13),
362            0o0_000_000_000_000_000_000_000
363        );
364    }
365
366    #[test]
367    fn round_trip_axis() {
368        let mut prng = rand_chacha::ChaChaRng::seed_from_u64(0);
369        for _ in 0..10000 {
370            let expected = prng.gen_range(0o0_000_000, 0o2_000_000) << 13;
371            let actual = Index64_3D::decode_axis(Index64_3D::encode_axis(expected));
372            assert_eq!(actual, expected);
373        }
374    }
375}