broccoli_tree/
build.rs

1//!
2//! Tree building blocks
3//!
4
5use super::*;
6
7#[must_use]
8pub struct NodeFinisher<'a, T: Aabb, S> {
9    axis: AxisDyn,
10    div: Option<T::Num>, //This can be null if there are no bots left at all
11    mid: &'a mut [T],
12    sorter: S,
13    num_elem: usize,
14}
15impl<'a, T: Aabb, S: Sorter<T>> NodeFinisher<'a, T, S> {
16    pub fn get_num_elem(&self) -> usize {
17        self.num_elem
18    }
19    #[inline(always)]
20    #[must_use]
21    pub fn finish(self) -> Node<'a, T> {
22        fn create_cont<A: Axis, T: Aabb>(axis: A, middle: &[T]) -> axgeom::Range<T::Num> {
23            match middle.split_first() {
24                Some((first, rest)) => {
25                    let mut min = first.get().get_range(axis).start;
26                    let mut max = first.get().get_range(axis).end;
27
28                    for a in rest.iter() {
29                        let start = &a.get().get_range(axis).start;
30                        let end = &a.get().get_range(axis).end;
31
32                        if *start < min {
33                            min = *start;
34                        }
35
36                        if *end > max {
37                            max = *end;
38                        }
39                    }
40
41                    axgeom::Range {
42                        start: min,
43                        end: max,
44                    }
45                }
46                None => axgeom::Range {
47                    start: Default::default(),
48                    end: Default::default(),
49                },
50            }
51        }
52
53        let cont = match self.axis {
54            AxisDyn::X => {
55                self.sorter.sort(axgeom::XAXIS.next(), self.mid);
56                create_cont(axgeom::XAXIS, self.mid)
57            }
58            AxisDyn::Y => {
59                self.sorter.sort(axgeom::YAXIS.next(), self.mid);
60                create_cont(axgeom::YAXIS, self.mid)
61            }
62        };
63
64        Node {
65            num_elem: self.num_elem,
66            range: AabbPin::new(self.mid),
67            cont,
68            div: self.div,
69        }
70    }
71}
72
73///
74/// The main primitive to build a tree.
75///
76pub struct TreeBuildVisitor<'a, T, S> {
77    bots: &'a mut [T],
78    current_height: usize,
79    sorter: S,
80    axis: AxisDyn,
81}
82
83pub struct NodeBuildResult<'a, T: Aabb, S> {
84    pub node: NodeFinisher<'a, T, S>,
85    pub rest: Option<[TreeBuildVisitor<'a, T, S>; 2]>,
86}
87
88impl<'a, T: Aabb, S: Sorter<T>> TreeBuildVisitor<'a, T, S> {
89    pub fn get_bots(&self) -> &[T] {
90        self.bots
91    }
92    #[must_use]
93    pub fn new(num_levels: usize, bots: &'a mut [T], sorter: S) -> TreeBuildVisitor<'a, T, S> {
94        assert!(num_levels >= 1);
95        TreeBuildVisitor {
96            bots,
97            current_height: num_levels - 1,
98            sorter,
99            axis: default_axis().to_dyn(),
100        }
101    }
102    #[must_use]
103    pub fn get_height(&self) -> usize {
104        self.current_height
105    }
106    #[must_use]
107    pub fn build_and_next(self) -> NodeBuildResult<'a, T, S> {
108        //leaf case
109        if self.current_height == 0 {
110            let node = NodeFinisher {
111                mid: self.bots,
112                div: None,
113                axis: self.axis,
114                sorter: self.sorter,
115                num_elem: 0,
116            };
117
118            NodeBuildResult { node, rest: None }
119        } else {
120            fn construct_non_leaf<T: Aabb>(
121                div_axis: impl Axis,
122                bots: &mut [T],
123            ) -> ConstructResult<T> {
124                if bots.is_empty() {
125                    return ConstructResult {
126                        mid: &mut [],
127                        div: None,
128                        left: &mut [],
129                        right: &mut [],
130                    };
131                }
132
133                let med_index = bots.len() / 2;
134                let (_, med, _) = bots.select_nth_unstable_by(med_index, move |a, b| {
135                    crate::util::compare_bots(div_axis, a, b)
136                });
137
138                let med_val = med.get().get_range(div_axis).start;
139
140                //It is very important that the median bot end up be binned into the middile bin.
141                //We know this must be true because we chose the divider to be the medians left border,
142                //and we binned so that all bots who intersect with the divider end up in the middle bin.
143                //Very important that if a bots border is exactly on the divider, it is put in the middle.
144                //If this were not true, there is no guarantee that the middile bin has bots in it even
145                //though we did pick a divider.
146                let binned = oned::bin_middle_left_right(div_axis, &med_val, bots);
147
148                ConstructResult {
149                    mid: binned.middle,
150                    div: Some(med_val),
151                    left: binned.left,
152                    right: binned.right,
153                }
154            }
155
156            let rr = match self.axis {
157                AxisDyn::X => construct_non_leaf(axgeom::XAXIS, self.bots),
158                AxisDyn::Y => construct_non_leaf(axgeom::YAXIS, self.bots),
159            };
160
161            let finish_node = NodeFinisher {
162                mid: rr.mid,
163                div: rr.div,
164                axis: self.axis,
165                sorter: self.sorter,
166                num_elem: rr.left.len().min(rr.right.len()),
167            };
168
169            let left = rr.left;
170            let right = rr.right;
171
172            NodeBuildResult {
173                node: finish_node,
174                rest: Some([
175                    TreeBuildVisitor {
176                        bots: left,
177                        current_height: self.current_height.saturating_sub(1),
178                        sorter: self.sorter,
179                        axis: self.axis.next(),
180                    },
181                    TreeBuildVisitor {
182                        bots: right,
183                        current_height: self.current_height.saturating_sub(1),
184                        sorter: self.sorter,
185                        axis: self.axis.next(),
186                    },
187                ]),
188            }
189        }
190    }
191
192    pub fn recurse_seq(self, res: &mut Vec<Node<'a, T>>) {
193        let NodeBuildResult { node, rest } = self.build_and_next();
194        res.push(node.finish());
195        if let Some([left, right]) = rest {
196            left.recurse_seq(res);
197            right.recurse_seq(res);
198        }
199    }
200}
201
202struct ConstructResult<'a, T: Aabb> {
203    div: Option<T::Num>,
204    mid: &'a mut [T],
205    right: &'a mut [T],
206    left: &'a mut [T],
207}
208
209#[derive(Copy, Clone, Default)]
210pub struct DefaultSorter;
211
212impl<T: Aabb> Sorter<T> for DefaultSorter {
213    fn sort(&self, axis: impl Axis, bots: &mut [T]) {
214        crate::util::sweeper_update(axis, bots);
215    }
216}
217
218#[derive(Copy, Clone, Default)]
219pub struct NoSorter;
220
221impl<T: Aabb> Sorter<T> for NoSorter {
222    fn sort(&self, _axis: impl Axis, _bots: &mut [T]) {}
223}