scirs2_spatial/rtree/
insertion.rs

1use crate::error::SpatialResult;
2use crate::rtree::node::{Entry, Node, RTree, Rectangle};
3use scirs2_core::ndarray::Array1;
4use std::collections::HashSet;
5
6impl<T: Clone> RTree<T> {
7    /// Insert a data point into the R-tree
8    ///
9    /// # Arguments
10    ///
11    /// * `point` - The point coordinates
12    /// * `data` - The data associated with the point
13    ///
14    /// # Returns
15    ///
16    /// A `SpatialResult` containing nothing if successful, or an error if the point has invalid dimensions
17    pub fn insert(&mut self, point: Array1<f64>, data: T) -> SpatialResult<()> {
18        if point.len() != self.ndim() {
19            return Err(crate::error::SpatialError::DimensionError(format!(
20                "Point dimension {} does not match RTree dimension {}",
21                point.len(),
22                self.ndim()
23            )));
24        }
25
26        // Create a leaf entry for the point
27        let mbr = Rectangle::from_point(&point.view());
28        let entry = Entry::Leaf {
29            mbr,
30            data,
31            index: self.size(),
32        };
33
34        // Insert the entry and handle node splits
35        self.insert_entry(&entry, 0)?;
36
37        // Increment the size after successful insertion
38        self.increment_size();
39
40        Ok(())
41    }
42
43    /// Insert a rectangle into the R-tree
44    ///
45    /// # Arguments
46    ///
47    /// * `min` - The minimum coordinates of the rectangle
48    /// * `max` - The maximum coordinates of the rectangle
49    /// * `data` - The data associated with the rectangle
50    ///
51    /// # Returns
52    ///
53    /// A `SpatialResult` containing nothing if successful, or an error if the rectangle has invalid dimensions
54    pub fn insert_rectangle(
55        &mut self,
56        min: Array1<f64>,
57        max: Array1<f64>,
58        data: T,
59    ) -> SpatialResult<()> {
60        if min.len() != self.ndim() {
61            return Err(crate::error::SpatialError::DimensionError(format!(
62                "Min coordinate dimension {} does not match RTree dimension {}",
63                min.len(),
64                self.ndim()
65            )));
66        }
67
68        if max.len() != self.ndim() {
69            return Err(crate::error::SpatialError::DimensionError(format!(
70                "Max coordinate dimension {} does not match RTree dimension {}",
71                max.len(),
72                self.ndim()
73            )));
74        }
75
76        // Create a leaf entry for the rectangle
77        let mbr = Rectangle::new(min, max)?;
78        let entry = Entry::Leaf {
79            mbr,
80            data,
81            index: self.size(),
82        };
83
84        // Insert the entry and handle node splits
85        self.insert_entry(&entry, 0)?;
86
87        // Increment the size after successful insertion
88        self.increment_size();
89
90        Ok(())
91    }
92
93    /// Helper function to insert an entry into the tree
94    pub(crate) fn insert_entry(
95        &mut self,
96        entry: &Entry<T>,
97        level: usize,
98    ) -> SpatialResult<Option<Node<T>>> {
99        // For leaf entries, we should insert at level 0
100        // If the root is a leaf node (level 0), insert directly
101        if self.root._isleaf && level == 0 {
102            self.root.entries.push(entry.clone());
103
104            // If the node overflows, split it
105            if self.root.size() > self.maxentries {
106                // Take ownership of the root temporarily
107                let mut root = std::mem::replace(&mut self.root, Node::new(true, 0));
108                let (node1, node2) = self.split_node(&mut root)?;
109
110                // Create a new root
111                let mut new_root = Node::new(false, 1);
112
113                // Add both split nodes as children
114                if let Ok(Some(mbr1)) = node1.mbr() {
115                    new_root.entries.push(Entry::NonLeaf {
116                        mbr: mbr1,
117                        child: Box::new(node1),
118                    });
119                }
120
121                if let Ok(Some(mbr2)) = node2.mbr() {
122                    new_root.entries.push(Entry::NonLeaf {
123                        mbr: mbr2,
124                        child: Box::new(node2),
125                    });
126                }
127
128                self.root = new_root;
129                self.increment_height();
130            }
131
132            return Ok(None);
133        }
134
135        // If root is not a leaf, we need to insert recursively
136        if !self.root._isleaf {
137            // Choose the best subtree to insert into
138            let subtree_index = self.choose_subtree(&self.root, entry.mbr(), level)?;
139
140            // Get the subtree
141            let child: &mut Box<Node<T>> = match &mut self.root.entries[subtree_index] {
142                Entry::NonLeaf { child, .. } => child,
143                Entry::Leaf { .. } => {
144                    return Err(crate::error::SpatialError::ComputationError(
145                        "Expected a non-leaf entry".into(),
146                    ))
147                }
148            };
149
150            // Get child as mutable raw pointer to avoid borrowing conflicts
151            let child_ptr = Box::as_mut(child) as *mut Node<T>;
152
153            // Recursively insert into the subtree
154            let maybe_split =
155                unsafe { self.insert_entry_recursive(entry, level, &mut *child_ptr) }?;
156
157            // If the child was split, add the new node as a sibling
158            if let Some(split_node) = maybe_split {
159                // Create a new entry for the split node
160                if let Ok(Some(mbr)) = split_node.mbr() {
161                    self.root.entries.push(Entry::NonLeaf {
162                        mbr,
163                        child: Box::new(split_node),
164                    });
165
166                    // If the node overflows, split it
167                    if self.root.size() > self.maxentries {
168                        // Take ownership of the root temporarily
169                        let mut root = std::mem::replace(&mut self.root, Node::new(false, 1));
170                        let root_level = root.level;
171                        let (node1, node2) = self.split_node(&mut root)?;
172
173                        // Create a new root
174                        let mut new_root = Node::new(false, root_level + 1);
175
176                        // Add both split nodes as children
177                        if let Ok(Some(mbr1)) = node1.mbr() {
178                            new_root.entries.push(Entry::NonLeaf {
179                                mbr: mbr1,
180                                child: Box::new(node1),
181                            });
182                        }
183
184                        if let Ok(Some(mbr2)) = node2.mbr() {
185                            new_root.entries.push(Entry::NonLeaf {
186                                mbr: mbr2,
187                                child: Box::new(node2),
188                            });
189                        }
190
191                        self.root = new_root;
192                        self.increment_height();
193                    }
194                }
195            }
196
197            // Update the MBR of the parent entry
198            if let Entry::NonLeaf { mbr, child } = &mut self.root.entries[subtree_index] {
199                if let Ok(Some(child_mbr)) = child.mbr() {
200                    *mbr = child_mbr;
201                }
202            }
203        }
204
205        Ok(None)
206    }
207
208    /// Recursively insert an entry into a node
209    pub(crate) fn insert_entry_recursive(
210        &mut self,
211        entry: &Entry<T>,
212        level: usize,
213        node: &mut Node<T>,
214    ) -> SpatialResult<Option<Node<T>>> {
215        // If we're at the target level, add the entry to this node
216        if level == node.level {
217            node.entries.push(entry.clone());
218
219            // If the node overflows, split it
220            if node.size() > self.maxentries {
221                let (new_node, split_node) = self.split_node(node)?;
222                *node = new_node;
223                return Ok(Some(split_node));
224            }
225
226            return Ok(None);
227        }
228
229        // Choose the best subtree to insert into
230        let subtree_index = self.choose_subtree(node, entry.mbr(), level)?;
231
232        // Get the subtree
233        let child: &mut Box<Node<T>> = match &mut node.entries[subtree_index] {
234            Entry::NonLeaf { child, .. } => child,
235            Entry::Leaf { .. } => {
236                return Err(crate::error::SpatialError::ComputationError(
237                    "Expected a non-leaf entry".into(),
238                ))
239            }
240        };
241
242        // Get child as mutable raw pointer to avoid borrowing conflicts
243        let child_ptr = Box::as_mut(child) as *mut Node<T>;
244
245        // Recursively insert into the subtree
246        let maybe_split = unsafe { self.insert_entry_recursive(entry, level, &mut *child_ptr) }?;
247
248        // If the child was split, add the new node as a sibling
249        if let Some(split_node) = maybe_split {
250            // Create a new entry for the split node
251            if let Ok(Some(mbr)) = split_node.mbr() {
252                node.entries.push(Entry::NonLeaf {
253                    mbr,
254                    child: Box::new(split_node),
255                });
256
257                // If the node overflows, split it
258                if node.size() > self.maxentries {
259                    let (new_node, split_node) = self.split_node(node)?;
260                    *node = new_node;
261                    return Ok(Some(split_node));
262                }
263            }
264        }
265
266        // Update the MBR of the parent entry
267        if let Entry::NonLeaf { mbr, child } = &mut node.entries[subtree_index] {
268            if let Ok(Some(child_mbr)) = child.mbr() {
269                *mbr = child_mbr;
270            }
271        }
272
273        Ok(None)
274    }
275
276    /// Choose the best subtree to insert an entry
277    pub(crate) fn choose_subtree(
278        &self,
279        node: &Node<T>,
280        mbr: &Rectangle,
281        level: usize,
282    ) -> SpatialResult<usize> {
283        let mut min_enlargement = f64::MAX;
284        let mut min_area = f64::MAX;
285        let mut chosen_index = 0;
286
287        // If this is a leaf node, we shouldn't be choosing a subtree
288        if node._isleaf {
289            return Err(crate::error::SpatialError::ComputationError(
290                "Cannot choose subtree in a leaf node".into(),
291            ));
292        }
293
294        for (i, entry) in node.entries.iter().enumerate() {
295            let entry_mbr = entry.mbr();
296
297            // Calculate the enlargement needed to include the new entry
298            let enlargement = entry_mbr.enlargement_area(mbr)?;
299
300            // Choose the entry with the minimum enlargement
301            if enlargement < min_enlargement
302                || (enlargement == min_enlargement && entry_mbr.area() < min_area)
303            {
304                min_enlargement = enlargement;
305                min_area = entry_mbr.area();
306                chosen_index = i;
307            }
308        }
309
310        Ok(chosen_index)
311    }
312
313    /// Split a node that has more than max_entries
314    pub(crate) fn split_node(&self, node: &mut Node<T>) -> SpatialResult<(Node<T>, Node<T>)> {
315        // Create two new nodes: the original (which will be replaced) and the split node
316        let mut node1 = Node::new(node._isleaf, node.level);
317        let mut node2 = Node::new(node._isleaf, node.level);
318
319        // Choose two seed entries to initialize the split
320        let (seed1, seed2) = self.choose_split_seeds(node)?;
321
322        // Create two groups with the seeds
323        node1.entries.push(node.entries[seed1].clone());
324        node2.entries.push(node.entries[seed2].clone());
325
326        // Use a set to track which entries have been assigned
327        let mut assigned = HashSet::new();
328        assigned.insert(seed1);
329        assigned.insert(seed2);
330
331        // Get the MBRs of the two groups
332        let mut mbr1 = node1.entries[0].mbr().clone();
333        let mut mbr2 = node2.entries[0].mbr().clone();
334
335        // Assign the remaining entries to the groups using the quadratic cost algorithm
336        while assigned.len() < node.size() {
337            // If one group needs to be filled to meet the minimum entries requirement
338            let remaining = node.size() - assigned.len();
339            if node1.size() + remaining == self.min_entries {
340                // Assign all remaining entries to group 1
341                for i in 0..node.size() {
342                    if !assigned.contains(&i) {
343                        node1.entries.push(node.entries[i].clone());
344                        mbr1 = mbr1.enlarge(node.entries[i].mbr())?;
345                    }
346                }
347                break;
348            } else if node2.size() + remaining == self.min_entries {
349                // Assign all remaining entries to group 2
350                for i in 0..node.size() {
351                    if !assigned.contains(&i) {
352                        node2.entries.push(node.entries[i].clone());
353                        mbr2 = mbr2.enlarge(node.entries[i].mbr())?;
354                    }
355                }
356                break;
357            }
358
359            // Find the entry that has the maximum difference in enlargement
360            let mut max_diff = -f64::MAX;
361            let mut chosen_index = 0;
362            let mut add_to_group1 = true;
363
364            for i in 0..node.size() {
365                if assigned.contains(&i) {
366                    continue;
367                }
368
369                // Calculate the enlargement needed for both groups
370                let entry_mbr = node.entries[i].mbr();
371                let enlargement1 = mbr1.enlargement_area(entry_mbr)?;
372                let enlargement2 = mbr2.enlargement_area(entry_mbr)?;
373
374                // Calculate the difference in enlargement
375                let diff = (enlargement1 - enlargement2).abs();
376                if diff > max_diff {
377                    max_diff = diff;
378                    chosen_index = i;
379                    add_to_group1 = enlargement1 < enlargement2;
380                }
381            }
382
383            // Add the chosen entry to the preferred group
384            if add_to_group1 {
385                node1.entries.push(node.entries[chosen_index].clone());
386                mbr1 = mbr1.enlarge(node.entries[chosen_index].mbr())?;
387            } else {
388                node2.entries.push(node.entries[chosen_index].clone());
389                mbr2 = mbr2.enlarge(node.entries[chosen_index].mbr())?;
390            }
391
392            assigned.insert(chosen_index);
393        }
394
395        // Replace the old node with the first group
396        *node = node1;
397
398        Ok((node.clone(), node2))
399    }
400
401    /// Choose two entries to be the seeds for node splitting
402    pub(crate) fn choose_split_seeds(&self, node: &Node<T>) -> SpatialResult<(usize, usize)> {
403        let mut max_waste = -f64::MAX;
404        let mut seed1 = 0;
405        let mut seed2 = 0;
406
407        // Find the two entries that would waste the most area if put together
408        for i in 0..node.size() - 1 {
409            for j in i + 1..node.size() {
410                let mbr_i = node.entries[i].mbr();
411                let mbr_j = node.entries[j].mbr();
412
413                // Calculate the area of the MBR containing both entries
414                let combined_mbr = mbr_i.enlarge(mbr_j)?;
415                let combined_area = combined_mbr.area();
416
417                // Calculate the wasted area
418                let waste = combined_area - mbr_i.area() - mbr_j.area();
419
420                if waste > max_waste {
421                    max_waste = waste;
422                    seed1 = i;
423                    seed2 = j;
424                }
425            }
426        }
427
428        Ok((seed1, seed2))
429    }
430}
431
432#[cfg(test)]
433mod tests {
434    use super::*;
435    use scirs2_core::ndarray::array;
436
437    #[test]
438    fn test_rtree_insert_and_search() {
439        // Create a new R-tree
440        let mut rtree: RTree<i32> = RTree::new(2, 2, 4).unwrap();
441
442        // Insert some points
443        let points = vec![
444            (array![0.0, 0.0], 0),
445            (array![1.0, 0.0], 1),
446            (array![0.0, 1.0], 2),
447            (array![1.0, 1.0], 3),
448            (array![0.5, 0.5], 4),
449            (array![2.0, 2.0], 5),
450            (array![3.0, 3.0], 6),
451            (array![4.0, 4.0], 7),
452            (array![5.0, 5.0], 8),
453            (array![6.0, 6.0], 9),
454        ];
455
456        for (point, value) in points {
457            rtree.insert(point, value).unwrap();
458        }
459
460        // Check the size
461        assert_eq!(rtree.size(), 10);
462        assert!(!rtree.is_empty());
463    }
464
465    #[test]
466    fn test_rtree_insert_rectangle() {
467        // Create a new R-tree
468        let mut rtree: RTree<&str> = RTree::new(2, 2, 4).unwrap();
469
470        // Insert some rectangles
471        let rectangles = vec![
472            (array![0.0, 0.0], array![1.0, 1.0], "A"),
473            (array![2.0, 2.0], array![3.0, 3.0], "B"),
474            (array![1.5, 0.0], array![2.5, 1.0], "C"),
475            (array![0.0, 1.5], array![1.0, 2.5], "D"),
476        ];
477
478        for (min, max, value) in rectangles {
479            rtree.insert_rectangle(min, max, value).unwrap();
480        }
481
482        // Check the size
483        assert_eq!(rtree.size(), 4);
484
485        // Test searching for rectangles that overlap with a query range
486        let results = rtree
487            .search_range(&array![0.5, 0.5].view(), &array![2.0, 2.0].view())
488            .unwrap();
489
490        // Should find all rectangles A, B, C, and D (B overlaps at boundary point (2.0, 2.0))
491        assert_eq!(results.len(), 4);
492
493        // Verify that the results contain all expected values
494        let result_values: Vec<&str> = results.iter().map(|(_, v)| *v).collect();
495        assert!(result_values.contains(&"A"));
496        assert!(result_values.contains(&"B")); // B overlaps at boundary
497        assert!(result_values.contains(&"C"));
498        assert!(result_values.contains(&"D"));
499    }
500}