119 static_assert(
MaxEntries >= 2,
"RTree requires MaxEntries >= 2");
120 static_assert(
MinEntries >= 1,
"RTree requires MinEntries >= 1");
121 static_assert(2 *
MinEntries <=
MaxEntries + 1,
"RTree requires 2 * MinEntries <= MaxEntries + 1");
122 static_assert(std::default_initializable<Payload>,
123 "RTree requires default-initializable Payload");
124 static_assert(std::movable<Payload>,
"RTree requires movable Payload");
156 size_t root = std::numeric_limits<size_t>::max();
200 return {xmin, ymin, xmax, ymax};
234 for (
size_t i = 1; i < node.
data.size(); ++i)
239 for (
size_t i = 1; i < node.
children.size(); ++i)
255 for (
size_t i = 1; i < node.
children.size(); ++i)
280 for (
size_t i = 0; i <
k; ++i)
284 for (
size_t j = 0; j <
k; ++j)
308 template <
typename EntryT>
311 const size_t n = entries.
size();
322 union_bbox(items(0).bbox, items(1).bbox).
area() - items(0).bbox.area() - items(1).bbox.area();
323 for (
size_t i = 0; i < n; ++i)
324 for (
size_t j = i + 1; j < n; ++j)
327 items(i).bbox.area() - items(j).bbox.area();
336 std::array<bool, MaxEntries + 1>
assigned{};
343 size_t remaining = n - 2;
347 for (
size_t k = 0;
k < n; ++
k)
351 group.append(std::move(items(
k)));
356 while (remaining > 0)
375 for (
size_t k = 0;
k < n; ++
k)
398 else if (
mbr1.area() !=
mbr2.area())
407 group1.append(std::move(items(pick)));
412 group2.append(std::move(items(pick)));
417 entries = std::move(
group1);
425 template <
typename EntryT>
428 const size_t n = entries.
size();
439 auto make_mbr_cache = [&items, n](
const std::array<size_t, MaxEntries + 1> &order)
441 std::array<Rectangle, MaxEntries + 2>
prefix{};
442 std::array<Rectangle, MaxEntries + 2>
suffix{};
443 prefix[1] = items(order[0]).bbox;
444 for (
size_t k = 2;
k <= n; ++
k)
446 suffix[n - 1] = items(order[n - 1]).bbox;
447 for (
size_t k = n - 1;
k > 0; --
k)
454 std::array<size_t, MaxEntries + 1> order{};
455 for (
size_t i = 0; i < n; ++i)
457 std::sort(order.begin(), order.begin() + n,
458 [&items,
axis, edge](
const size_t a,
const size_t b)
460 const Rectangle &ra = items(a).bbox;
461 const Rectangle &rb = items(b).bbox;
462 const Geom_Number la = axis == 0 ? ra.get_xmin() : ra.get_ymin();
463 const Geom_Number ua = axis == 0 ? ra.get_xmax() : ra.get_ymax();
464 const Geom_Number lb = axis == 0 ? rb.get_xmin() : rb.get_ymin();
465 const Geom_Number ub = axis == 0 ? rb.get_xmax() : rb.get_ymax();
466 const Geom_Number pa = edge == 0 ? la : ua;
467 const Geom_Number pb = edge == 0 ? lb : ub;
470 return (edge == 0 ? ua : la) < (edge == 0 ? ub : lb);
482 for (
int edge = 0; edge < 2; ++edge)
484 const std::array<size_t, MaxEntries + 1> order =
make_order(
axis, edge);
497 std::array<size_t, MaxEntries + 1>
best_order{};
502 for (
int edge = 0; edge < 2; ++edge)
527 entries = std::move(
group1);
534 template <
typename EntryT>
548 const size_t n = node.
data.size();
551 std::array<size_t, MaxEntries + 1> order{};
552 for (
size_t i = 0; i < n; ++i)
554 std::sort(order.begin(), order.begin() + n, [&node, &
centre](
const size_t a,
const size_t b)
556 return node.data(a).bbox.center().distance_squared_to(centre) >
557 node.data(b).bbox.center().distance_squared_to(centre);
568 for (
size_t k = p;
k < n; ++
k)
569 kept.append(std::move(node.
data(order[
k])));
570 for (
size_t k = 0;
k < p; ++
k)
582 node.
data.append(std::move(entry));
595 auto sibling = std::make_unique<Node>();
596 sibling->leaf =
true;
597 sibling->data = std::move(
group2);
604 if (
split ==
nullptr)
614 auto sibling = std::make_unique<Node>();
615 sibling->leaf =
false;
616 sibling->children = std::move(
group2);
624 if (
root_ ==
nullptr)
626 auto root = std::make_unique<Node>();
628 root->data.reserve(1);
629 root->data.append(std::move(entry));
636 if (
split ==
nullptr)
639 auto new_root = std::make_unique<Node>();
672 for (
size_t i = 0; i < node.
data.size(); ++i)
673 out.append(std::move(node.
data(i)));
676 for (
size_t i = 0; i < node.
children.size(); ++i)
683 return node.
data.size();
685 for (
size_t i = 0; i < node.
children.size(); ++i)
689 <<
"RTree: data entry count would overflow";
700 requires std::equality_comparable<Payload>
704 for (
size_t i = 0; i < node.data.size(); ++i)
705 if (node.data(i).bbox == bbox
and node.data(i).value ==
value)
708 for (
size_t j = 0; j < node.data.size(); ++j)
710 kept.append(std::move(node.data(j)));
711 node.data = std::move(
kept);
718 for (
size_t i = 0; i < node.children.size(); ++i)
720 Child &c = node.children(i);
733 <<
"RTree: orphan collection would overflow";
737 for (
size_t j = 0; j < node.children.size(); ++j)
739 kept.append(std::move(node.children(j)));
740 node.children = std::move(
kept);
757 template <
typename F>
762 for (
size_t i = 0; i < node.
data.size(); ++i)
763 if (node.
data(i).bbox.intersects(
rect))
764 f(node.
data(i).bbox, node.
data(i).value);
767 for (
size_t i = 0; i < node.
children.size(); ++i)
772 template <
typename F>
777 for (
size_t i = 0; i < node.
data.size(); ++i)
778 if (node.
data(i).bbox.contains(p))
779 f(node.
data(i).bbox, node.
data(i).value);
782 for (
size_t i = 0; i < node.
children.size(); ++i)
783 if (node.
children(i).bbox.contains(p))
790 requires (std::is_copy_constructible_v<Payload>
and std::movable<Payload>)
792 auto copy = std::make_unique<Node>();
793 copy->leaf = node.leaf;
796 copy->data.reserve(node.data.size());
797 for (
size_t i = 0; i < node.data.size(); ++i)
798 copy->data.append(
Entry{node.data(i).bbox, node.data(i).value});
802 copy->children.reserve(node.children.size());
803 for (
size_t i = 0; i < node.children.size(); ++i)
804 copy->children.append(
Child{node.children(i).bbox, clone_node(*node.children(i).child)});
822 if (leaf_depth == std::numeric_limits<size_t>::max())
824 else if (leaf_depth != depth)
827 if (
count > std::numeric_limits<size_t>::max() - n)
833 if (is_root
and n < 2)
837 for (
size_t i = 0; i < node.
children.size(); ++i)
868 other.clear_rstar_reinsert_state();
889 other.clear_rstar_reinsert_state();
898 requires (std::is_copy_constructible_v<Payload>
and std::movable<Payload>)
901 if (
other.root_ !=
nullptr)
911 requires (std::is_copy_constructible_v<Payload>
and std::movable<Payload>)
916 if (
other.root_ !=
nullptr)
972 <<
"RTree: size would overflow";
987 <<
"RTree: size would overflow";
1001 requires std::equality_comparable<Payload>
1003 if (
root_ ==
nullptr)
1016 for (
size_t i = 0; i <
orphans.size(); ++i)
1041 template <
typename F>
1044 if (
root_ !=
nullptr)
1054 requires (std::is_copy_constructible_v<Payload>
and std::movable<Payload>)
1070 requires (std::is_copy_constructible_v<Payload>
and std::movable<Payload>)
1077 if (
root_ !=
nullptr)
1093 if (
root_ ==
nullptr)
1096 size_t leaf_depth = std::numeric_limits<size_t>::max();
1117 if (
root_ ==
nullptr)
1123 auto dfs = [&](
const auto &self,
const Node &node,
const size_t depth) ->
size_t
1137 for (
size_t i = 0; i < node.data.size(); ++i)
1138 boxes.append(node.data(i).bbox);
1142 snap.nodes(
out_idx).children.reserve(node.children.size());
1143 for (
size_t i = 0; i < node.children.size(); ++i)
1145 const size_t child_idx = self(self, *node.children(i).child, depth + 1);
Exception handling system with formatted messages for Aleph-w.
#define ah_overflow_error_if(C)
Throws std::overflow_error if condition holds.
size_t size_t int32_t value
size_t size_t int32_t * out
Simple dynamic array with automatic resizing and functional operations.
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
T & append(const T &data)
Append a copy of data
void reserve(size_t cap)
Reserves cap cells into the array.
Represents a point with rectangular coordinates in a 2D plane.
Dynamic R-tree indexing axis-aligned rectangles by payload.
size_t height_
Number of node levels (0 when empty).
static Array< EntryT > quadratic_split(Array< EntryT > &entries)
Split an overflowed entry array in two using the quadratic heuristic.
static size_t rstar_choose_overlap(const Node &node, const Rectangle &bbox)
R*-tree ChooseSubtree for a node whose children are leaves: pick the child whose growth adds the leas...
void for_each_intersecting_rec(const Node &node, const Rectangle &rect, F &f) const
static Array< EntryT > split_entries(Array< EntryT > &entries)
Split the entry array of node according to the active variant.
static Rectangle union_bbox(const Rectangle &a, const Rectangle &b)
static Geom_Number enlargement(const Rectangle &base, const Rectangle &added)
Area added to base by growing it to also cover added.
void reinsert_farthest(Node &node)
Move the R*-tree forced-reinsert candidates (the entries farthest from the node centre) out of the ov...
void add_entry(Entry entry)
Add a data entry without touching size_ (shared by insert and by erase-time reinsertion).
static size_t entry_count(const Node &node)
void clear_rstar_reinsert_state() noexcept
Drop R*-tree transient insertion state.
static Geom_Number overlap_area(const Rectangle &a, const Rectangle &b)
Area of the overlap between two rectangles (0 if disjoint).
DebugSnapshot debug_snapshot() const
Capture the full tree structure for visualization/debugging.
void insert_one(Entry entry)
Insert one data entry into the tree (no size_ change, no reinsert-buffer management).
void insert(const Rectangle &bbox, const Payload &value)
Insert a (bbox, value) entry, copying value.
RTree(const RTree &other)
Deep-copy other (requires copy-constructible, movable Payload).
static size_t data_entry_count(const Node &node)
static bool box_contains_box(const Rectangle &outer, const Rectangle &inner)
True iff outer fully covers inner.
bool erase(const Rectangle &bbox, const Payload &value)
Remove one entry equal to (bbox, value).
static Rectangle compute_mbr(const Node &node)
Tight bounding box covering every entry of node.
static size_t choose_subtree(const Node &node, const Rectangle &bbox)
Choose the child of node into which bbox should be inserted.
void erase_descend(Node &node, const Rectangle &bbox, const Payload &value, Array< Entry > &orphans, bool &removed)
Remove one entry equal to (bbox, value) from node's subtree.
size_t height() const noexcept
Return the number of node levels (0 when empty, 1 for a lone leaf).
RTree() noexcept=default
Construct an empty R-tree.
bool rstar_reinsert_available_
Leaf-level reinsert not yet used this insert.
bool is_empty() const noexcept
Return true when the tree has no entries.
void insert(const Rectangle &bbox, Payload &&value)
Insert a (bbox, value) entry, moving value.
Array< Payload > search_intersects(const Rectangle &rect) const
Return the payloads of every entry whose bbox intersects rect.
void for_each_containing_rec(const Node &node, const Point &p, F &f) const
Array< Payload > search_contains(const Point &p) const
Return the payloads of every entry whose bbox contains p.
size_t size() const noexcept
Return the number of stored entries.
std::unique_ptr< Node > insert_descend(Node &node, Entry entry)
Insert entry at the leaf level of node.
RTree & operator=(RTree &&other) noexcept
Move-assign from other, leaving it empty and valid.
void for_each_intersecting(const Rectangle &rect, F &&f) const
Invoke f for every entry whose bbox intersects rect.
static Array< EntryT > rstar_split(Array< EntryT > &entries)
R*-tree split: choose the split axis minimizing the total margin of the two groups,...
bool verify_rec(const Node &node, const size_t depth, const bool is_root, size_t &leaf_depth, size_t &count, Rectangle &out_mbr) const
std::unique_ptr< Node > root_
static std::unique_ptr< Node > clone_node(const Node &node)
bool verify() const
Verify the R-tree structural invariants.
void clear() noexcept
Remove all entries.
size_t size_
Number of stored data entries.
Array< Entry > rstar_reinsert_buffer_
Entries pending forced reinsertion.
static void collect_data_entries(Node &node, Array< Entry > &out)
Move every data entry in node's subtree into out.
An axis-aligned rectangle.
const Geom_Number & get_xmin() const
Gets the minimum x-coordinate.
Geom_Number area() const noexcept
Calculates the area of the rectangle.
const Geom_Number & get_ymax() const
Gets the maximum y-coordinate.
const Geom_Number & get_ymin() const
Gets the minimum y-coordinate.
const Geom_Number & get_xmax() const
Gets the maximum x-coordinate.
Point center() const noexcept
Calculates the center point of the rectangle.
__gmp_expr< T, __gmp_binary_expr< __gmp_expr< T, U >, unsigned long int, __gmp_root_function > > root(const __gmp_expr< T, U > &expr, unsigned long int l)
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Main namespace for Aleph-w library functions.
static void suffix(Node *root, DynList< Node * > &acc)
Itor2 copy(Itor1 sourceBeg, const Itor1 &sourceEnd, Itor2 destBeg)
Copy elements from one range to another.
and
Check uniqueness with explicit hash + equality functors.
static void prefix(Node *root, DynList< Node * > &acc)
bool diff(const C1 &c1, const C2 &c2, Eq e=Eq())
Check if two containers differ.
mpq_class Geom_Number
Numeric type used by the geometry module.
std::vector< std::string > & split(const std::string &s, const char delim, std::vector< std::string > &elems)
Split a std::string by a single delimiter character.
RTreeVariant
Node-split / insertion strategy for RTree.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
2D point and geometric utilities.
Internal-node entry: a child subtree plus its tight bounding box.
std::unique_ptr< Node > child
Owned child subtree.
Rectangle bbox
Tight MBR of child.
One node of a debug_snapshot, independent of Payload.
size_t depth
Root is 0, increasing towards the leaves.
bool is_leaf
True for leaf nodes (see entry_boxes).
Array< Rectangle > entry_boxes
Data-entry boxes stored here (leaves only).
Rectangle bbox
Tight MBR of this node.
Array< size_t > children
Indices into DebugSnapshot::nodes (internal nodes).
Full tree structure captured for visualization/debugging.
Array< DebugNode > nodes
Every node, in preorder.
size_t root
Index of the root in nodes.
A stored (bounding box, payload) pair.
Rectangle bbox
Axis-aligned bounding box.
Payload value
User payload associated with bbox.
A node is a leaf holding data or an internal node holding children.
Array< Child > children
Child entries (used iff not leaf).
Array< Entry > data
Data entries (used iff leaf).
Dynamic array container with automatic resizing.