all impl'd, should work
This commit is contained in:
parent
d8f1ffd801
commit
969c84d9cc
2 changed files with 48 additions and 25 deletions
4
.rustfmt.toml
Normal file
4
.rustfmt.toml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
imports_granularity = "Crate"
|
||||||
|
group_imports = "StdExternalCrate"
|
||||||
|
wrap_comments = true
|
||||||
|
edition = "2024"
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
use crate::geom::Point;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
math::bounding::{Aabb2d, BoundingVolume, IntersectsVolume},
|
math::bounding::{Aabb2d, BoundingVolume, IntersectsVolume},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
use ordered_float::OrderedFloat;
|
|
||||||
use std::{cmp::Ordering, collections::BinaryHeap};
|
use crate::geom::Point;
|
||||||
|
|
||||||
// Epsilon value for zero-sizes bounding boxes/cubes.
|
// Epsilon value for zero-sizes bounding boxes/cubes.
|
||||||
const EPSILON: f32 = 1e-10;
|
const EPSILON: f32 = 1e-10;
|
||||||
|
|
@ -37,16 +38,15 @@ pub struct TreeNode {
|
||||||
|
|
||||||
/// R*‑tree data structure for indexing 2D or 3D points.
|
/// R*‑tree data structure for indexing 2D or 3D points.
|
||||||
///
|
///
|
||||||
/// The tree is initialized with a maximum number of entries per node. If a node exceeds this
|
/// The tree is initialized with a maximum number of entries per node. If a node
|
||||||
/// number, it will split. The tree supports insertion, deletion, and range searches.
|
/// exceeds this number, it will split. The tree supports insertion, deletion,
|
||||||
|
/// and range searches.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RStarTree {
|
pub struct RStarTree {
|
||||||
root: TreeNode,
|
root: TreeNode,
|
||||||
max_entries: usize,
|
max_entries: usize,
|
||||||
min_entries: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Common trait implementations for R*-tree to reuse shared algorithms.
|
|
||||||
impl Entry {
|
impl Entry {
|
||||||
fn as_leaf_obj(&self) -> Option<&Point> {
|
fn as_leaf_obj(&self) -> Option<&Point> {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -94,21 +94,21 @@ impl TreeNode {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
if self.is_leaf() {
|
if self.is_leaf() {
|
||||||
for entry in self.entries() {
|
for entry in self.entries() {
|
||||||
if let Some(obj) = entry.as_leaf_obj() {
|
if let Some(obj) = entry.as_leaf_obj()
|
||||||
if entry.mbr().intersects(bbox) {
|
&& entry.mbr().intersects(bbox)
|
||||||
|
{
|
||||||
result.push(obj);
|
result.push(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for entry in self.entries() {
|
for entry in self.entries() {
|
||||||
if let Some(child) = entry.child() {
|
if let Some(child) = entry.child()
|
||||||
if entry.mbr().intersects(bbox) {
|
&& entry.mbr().intersects(bbox)
|
||||||
|
{
|
||||||
result.extend_from_slice(&child.range_search_bbox(bbox));
|
result.extend_from_slice(&child.range_search_bbox(bbox));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,14 +119,13 @@ impl TreeNode {
|
||||||
|
|
||||||
impl RStarTree {
|
impl RStarTree {
|
||||||
pub fn new(max_entries: usize) -> Self {
|
pub fn new(max_entries: usize) -> Self {
|
||||||
let max_entries = max_entries.max(2);
|
let max_entries = max_entries.max(4);
|
||||||
RStarTree {
|
RStarTree {
|
||||||
root: TreeNode {
|
root: TreeNode {
|
||||||
entries: Vec::new(),
|
entries: Vec::new(),
|
||||||
is_leaf: true,
|
is_leaf: true,
|
||||||
},
|
},
|
||||||
max_entries,
|
max_entries,
|
||||||
min_entries: (max_entries as f32 * 0.4).ceil() as usize,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,11 +158,11 @@ impl RStarTree {
|
||||||
if reinsert_level == Some(overflow_level) {
|
if reinsert_level == Some(overflow_level) {
|
||||||
let old_entries = overflowed_node;
|
let old_entries = overflowed_node;
|
||||||
let (group1, group2) = split_entries(old_entries, self.max_entries);
|
let (group1, group2) = split_entries(old_entries, self.max_entries);
|
||||||
let mut mbr1 = group1[0].mbr().clone();
|
let mut mbr1 = *group1[0].mbr();
|
||||||
for entry in group1.iter() {
|
for entry in group1.iter() {
|
||||||
mbr1 = mbr1.merge(entry.mbr());
|
mbr1 = mbr1.merge(entry.mbr());
|
||||||
}
|
}
|
||||||
let mut mbr2 = group2[0].mbr().clone();
|
let mut mbr2 = *group2[0].mbr();
|
||||||
for entry in group2.iter() {
|
for entry in group2.iter() {
|
||||||
mbr2 = mbr2.merge(entry.mbr());
|
mbr2 = mbr2.merge(entry.mbr());
|
||||||
}
|
}
|
||||||
|
|
@ -212,7 +211,8 @@ impl RStarTree {
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// A vector of references to the objects whose minimum bounding volumes intersect the query.
|
/// A vector of references to the objects whose minimum bounding volumes
|
||||||
|
/// intersect the query.
|
||||||
pub fn range_search_bbox(&self, query_bbox: &Aabb2d) -> Vec<&Point> {
|
pub fn range_search_bbox(&self, query_bbox: &Aabb2d) -> Vec<&Point> {
|
||||||
self.root.range_search_bbox(query_bbox)
|
self.root.range_search_bbox(query_bbox)
|
||||||
}
|
}
|
||||||
|
|
@ -481,11 +481,11 @@ fn split_entries(mut entries: Vec<Entry>, max_entries: usize) -> (Vec<Entry>, Ve
|
||||||
for k in min_entries..=entries.len() - min_entries {
|
for k in min_entries..=entries.len() - min_entries {
|
||||||
let group1 = &entries[..k];
|
let group1 = &entries[..k];
|
||||||
let group2 = &entries[k..];
|
let group2 = &entries[k..];
|
||||||
let mut mbr1 = group1[0].mbr().clone();
|
let mut mbr1 = *group1[0].mbr();
|
||||||
for entry in group1 {
|
for entry in group1 {
|
||||||
mbr1 = mbr1.merge(entry.mbr());
|
mbr1 = mbr1.merge(entry.mbr());
|
||||||
}
|
}
|
||||||
let mbr2 = group2[0].mbr().clone();
|
let mbr2 = *group2[0].mbr();
|
||||||
|
|
||||||
let margin = mbr1.margin() + mbr2.margin();
|
let margin = mbr1.margin() + mbr2.margin();
|
||||||
if margin < min_margin {
|
if margin < min_margin {
|
||||||
|
|
@ -532,7 +532,8 @@ fn split_entries(mut entries: Vec<Entry>, max_entries: usize) -> (Vec<Entry>, Ve
|
||||||
impl RStarTree {
|
impl RStarTree {
|
||||||
/// Performs a range search on the R*‑tree using a query object and radius.
|
/// Performs a range search on the R*‑tree using a query object and radius.
|
||||||
///
|
///
|
||||||
/// The query object is wrapped into a bounding volume using `from_point_radius`.
|
/// The query object is wrapped into a bounding volume using
|
||||||
|
/// `from_point_radius`.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
|
|
@ -555,7 +556,7 @@ impl RStarTree {
|
||||||
|
|
||||||
fn entries_mbr(entries: &[Entry]) -> Option<Aabb2d> {
|
fn entries_mbr(entries: &[Entry]) -> Option<Aabb2d> {
|
||||||
let mut iter = entries.iter();
|
let mut iter = entries.iter();
|
||||||
let first = iter.next()?.mbr().clone();
|
let first = *iter.next()?.mbr();
|
||||||
Some(iter.fold(first, |acc, entry| acc.merge(entry.mbr())))
|
Some(iter.fold(first, |acc, entry| acc.merge(entry.mbr())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -572,6 +573,24 @@ impl Bvr for Aabb2d {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overlap(&self, other: &Aabb2d) -> f32 {
|
fn overlap(&self, other: &Aabb2d) -> f32 {
|
||||||
todo!()
|
let Vec2 {
|
||||||
|
x: self_width,
|
||||||
|
y: self_height,
|
||||||
|
} = 2.0 * self.half_size();
|
||||||
|
|
||||||
|
let self_center = self.center();
|
||||||
|
let other_center = other.center();
|
||||||
|
|
||||||
|
let Vec2 {
|
||||||
|
x: other_width,
|
||||||
|
y: other_height,
|
||||||
|
} = 2.0 * other.half_size();
|
||||||
|
|
||||||
|
let o_x = (self_center.x + self_width).min(other_center.x + other_width)
|
||||||
|
- self_center.x.max(other_center.x);
|
||||||
|
let o_y = (self_center.y + self_height).min(other_center.y + other_height)
|
||||||
|
- self_center.y.max(other_center.y);
|
||||||
|
|
||||||
|
(o_x * o_y).max(0.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue