quadtree_cd/
lib.rs

1#![feature(clamp)]
2#![feature(core_intrinsics)]
3
4#[macro_use]
5extern crate lazy_static;
6
7use std::intrinsics::ctlz;
8
9pub(in crate) mod geometry;
10pub use self::geometry::{intersects, BoundingBox, Intersection, RotatedRect};
11
12#[derive(Copy, Clone)]
13struct Node<T> {
14    count: u16,
15    item: Option<(u16, T)>,
16}
17
18pub struct Tree<T> {
19    nodes: Vec<Node<T>>,
20    pub width: f32,
21    pub height: f32,
22}
23
24lazy_static! {
25    static ref LEVELS: [u16; 8] = {
26        let mut levels = [0; 8];
27        let mut i: u16 = 0;
28        for j in 1..8 {
29            let k = j - 1;
30            i += (1 << k) * (1 << k);
31            levels[j as usize] = i;
32        }
33
34        levels
35    };
36}
37
38trait BitScan {
39    fn bsr(self) -> Self;
40}
41
42impl BitScan for u8 {
43    fn bsr(self) -> Self {
44        7 - ctlz(self)
45    }
46}
47
48impl From<BoundingBox<f32>> for BoundingBox<u8> {
49    fn from(item: BoundingBox<f32>) -> Self {
50        let clamp = |x: f32| x.clamp(0.0, 255.0);
51        BoundingBox {
52            x0: clamp(item.x0.floor()) as u8,
53            y0: clamp(item.y0.floor()) as u8,
54            x1: clamp(item.x1.ceil()) as u8,
55            y1: clamp(item.y1.ceil()) as u8,
56        }
57    }
58}
59
60impl<T> Tree<T>
61where
62    T: Clone,
63{
64    pub fn new(width: f32, height: f32) -> Tree<T> {
65        let nodes: Vec<Node<T>> = Vec::with_capacity(5);
66
67        Tree {
68            nodes,
69            width,
70            height,
71        }
72    }
73
74    pub fn insert_checked(
75        &mut self,
76        item: T,
77        bbox: &BoundingBox<f32>,
78        check: Option<&Fn(&T, &T) -> bool>,
79    ) -> bool {
80        let inv_w = 256.0 / self.width;
81        let inv_h = 256.0 / self.height;
82
83        // Clamp and convert bounds to byte range.
84        let shifted: BoundingBox<u8> = BoundingBox::new(
85            bbox.x0.max(0.0) * inv_w,
86            bbox.y0.max(0.0) * inv_h,
87            bbox.x1.min(self.width) * inv_w,
88            bbox.y1.min(self.height) * inv_h,
89        )
90        .into();
91
92        // Get the level at which the object will be inserted. We use
93        // a bithack from Game Programming Gems II by Matt Pritchard,
94        // courtesy of L. Spiro.
95        let x = shifted.x0 ^ shifted.x1;
96        let x = if x == 0 { 7 } else { 7 - x.bsr() };
97
98        let y = shifted.y0 ^ shifted.y1;
99        let y = if y == 0 { 7 } else { 7 - y.bsr() };
100
101        let level = x.min(y);
102
103        for i in (0..level + 1).rev() {
104            let length = {
105                let base = LEVELS[level as usize];
106                let index = if i == 0 {
107                    base
108                } else {
109                    let s = 1 << i;
110                    let k: u32 = 8_u32 - i as u32;
111                    let x = shifted.x0 as u8 >> k;
112                    let y = shifted.y0 as u8 >> k;
113                    base + y as u16 * s + x as u16
114                };
115                self.resize(index as usize)
116            };
117
118            let index = LEVELS[i as usize];
119            let mut k: usize = index as usize;
120            let count = self.nodes[k].count;
121            let mut remaining = count;
122            let mut slot = None;
123
124            for _ in 0..length {
125                match &self.nodes[k].item {
126                    Some((other_index, other_item)) => {
127                        if *other_index == index {
128                            if let Some(f) = &check {
129                                if f(&item, other_item) {
130                                    return false;
131                                }
132                            }
133
134                            remaining -= 1;
135                        }
136                    }
137                    None => {
138                        if slot.is_none() {
139                            slot = Some(k);
140                        }
141
142                        if remaining == 0 {
143                            break;
144                        }
145
146                        ()
147                    }
148                }
149
150                // Wrap around
151                k += 1;
152                if k == length {
153                    k = 0;
154                }
155            }
156
157            if i == 0 || check.is_none() {
158                let j = match slot {
159                    Some(j) => j,
160                    None => {
161                        &self.nodes.push(Node {
162                            count: 0,
163                            item: None,
164                        });
165                        length
166                    }
167                };
168
169                self.nodes[j].item = Some((index, item));
170                self.nodes[index as usize].count = count + 1;
171
172                return true;
173            }
174        }
175
176        false
177    }
178
179    pub fn insert_unless_intersecting(
180        &mut self,
181        item: T,
182        bbox: &BoundingBox<f32>,
183    ) -> bool
184    where
185        T: Intersection,
186    {
187        self.insert_checked(item, bbox, Some(&intersects))
188    }
189
190    pub fn insert(&mut self, item: T, bbox: &BoundingBox<f32>) {
191        self.insert_checked(item, bbox, None);
192    }
193
194    fn resize(&mut self, length: usize) -> usize {
195        let cur_length = self.nodes.len();
196        if cur_length > length {
197            return cur_length;
198        }
199
200        let mut new_length = 0;
201        for i in 0..8 {
202            let term = 2_usize.pow(2 * i);
203            new_length += term;
204            if new_length > length {
205                &self.nodes.resize(
206                    new_length,
207                    Node {
208                        count: 0,
209                        item: None,
210                    },
211                );
212                break;
213            }
214        }
215
216        return new_length;
217    }
218}