Pangolin
Header-only C++20 plane computational geometry library
Loading...
Searching...
No Matches
pgl::IntervalTree< S, Axis > Class Template Reference

Mutable interval tree over the projection of bounded shapes. More...

#include <intervaltree.hpp>

Public Types

using ShapeType = S
using BoxType = std::remove_cvref_t<decltype(std::declval<const S&>().bbox())>
using NumberType = std::remove_cvref_t<decltype(std::declval<const BoxType&>().min().x())>
using value_type = ShapeType
using size_type = std::size_t
using const_iterator = typename std::vector<ShapeType>::const_iterator
using const_reference = const ShapeType&

Public Member Functions

 IntervalTree ()=default
template<class Container>
 IntervalTree (const Container &shapes)
 Builds a tree by inserting every shape in shapes.
std::size_t size () const
 Returns the number of stored shapes.
bool empty () const
 Returns whether no shape is stored.
const std::vector< ShapeType > & shapes () const
 Returns the stored shapes in internal storage order.
const_iterator begin () const
 Returns a constant iterator to the first stored shape.
const_iterator end () const
 Returns a constant iterator past the last stored shape.
const_iterator cbegin () const
 Returns a constant iterator to the first stored shape.
const_iterator cend () const
 Returns a constant iterator past the last stored shape.
void insert (const ShapeType &shape)
 Inserts shape and its selected closed bounding-box interval.
bool erase (const ShapeType &shape)
 Removes one stored shape equal to shape.
bool has (const ShapeType &shape) const
 Returns whether a shape equal to shape is stored.
template<class Q>
std::size_t countProjectionsIntersecting (const Q &q) const
 Counts shapes whose projected interval intersects the projection of q.
template<class Q>
std::vector< ShapeTypereportProjectionsIntersecting (const Q &q) const
 Returns copies of shapes whose projected interval intersects that of q.
template<class Q, class Fn>
bool visitProjectionsIntersecting (const Q &q, Fn fn) const
 Visits projected-interval intersections, stopping early if fn returns true.
template<class Q>
bool emptyProjectionsIntersecting (const Q &q) const
 Returns whether no stored projected interval intersects the projection of q.
template<class Q>
std::size_t countProjectionsContainedIn (const Q &q) const
 Counts shapes whose projected interval is contained in the projection of q.
template<class Q>
std::vector< ShapeTypereportProjectionsContainedIn (const Q &q) const
 Returns copies of shapes whose projected interval is contained in that of q.
template<class Q, class Fn>
bool visitProjectionsContainedIn (const Q &q, Fn fn) const
 Visits projected intervals contained in q, stopping early if fn returns true.
template<class Q>
bool emptyProjectionsContainedIn (const Q &q) const
 Returns whether no stored projected interval is contained in that of q.
template<class Q>
std::size_t countIntersecting (const Q &q) const
 Counts stored shapes that geometrically intersect q.
template<class Q>
std::vector< ShapeTypereportIntersecting (const Q &q) const
 Returns copies of stored shapes that geometrically intersect q.
template<class Q, class Fn>
bool visitIntersecting (const Q &q, Fn fn) const
 Visits stored shapes that geometrically intersect q.
template<class Q>
bool emptyIntersecting (const Q &q) const
 Returns whether no stored shape geometrically intersects q.
template<class Q>
std::size_t countContainedIn (const Q &q) const
 Counts stored shapes geometrically contained in q.
template<class Q>
std::vector< ShapeTypereportContainedIn (const Q &q) const
 Returns copies of stored shapes geometrically contained in q.
template<class Q, class Fn>
bool visitContainedIn (const Q &q, Fn fn) const
 Visits stored shapes geometrically contained in q.
template<class Q>
bool emptyContainedIn (const Q &q) const
 Returns whether no stored shape is geometrically contained in q.

Detailed Description

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
class pgl::IntervalTree< S, Axis >

Mutable interval tree over the projection of bounded shapes.

Each stored shape owns one closed interval: the x or y extent of its bounding box, selected by Axis. Queries apply the same projection to their argument, so this is intentionally a one-dimensional index: matching does not imply that the original two-dimensional shapes meet or contain one another.

Nodes form a red-black tree ordered by (low endpoint, high endpoint, node ID). The ID keeps equal projected intervals distinct. Every node caches the extrema of both endpoints in its subtree. In particular, maxHigh is the standard augmented interval-tree value used to prune subtrees lying completely before an intersection query. Query fields are stored separately from insertion-only parent/color state, and 32-bit node IDs keep the hot representation compact.

Removal tombstones a node rather than unlinking it: the node keeps its place in the tree but owns no shape, so it stops matching queries, and the whole index is rebuilt only once tombstones outnumber live nodes. Removals are therefore logarithmic on average, and the node array never exceeds twice the number of stored shapes. A node ID still indexes the stored shapes directly: the live nodes are exactly the first size() slots, so a removal moves the last live node into the freed slot and the tombstone to the end. One tree can hold at most 2^32 - 2 nodes, shapes and tombstones together, so at least 2^31 - 1 shapes always fit.

Template Parameters
SShape type exposing a finite bbox().
AxisCoordinate used for the one-dimensional projection.

Member Typedef Documentation

◆ BoxType

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
using pgl::IntervalTree< S, Axis >::BoxType = std::remove_cvref_t<decltype(std::declval<const S&>().bbox())>

◆ const_iterator

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
using pgl::IntervalTree< S, Axis >::const_iterator = typename std::vector<ShapeType>::const_iterator

◆ const_reference

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
using pgl::IntervalTree< S, Axis >::const_reference = const ShapeType&

◆ NumberType

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
using pgl::IntervalTree< S, Axis >::NumberType = std::remove_cvref_t<decltype(std::declval<const BoxType&>().min().x())>

◆ ShapeType

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
using pgl::IntervalTree< S, Axis >::ShapeType = S

◆ size_type

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
using pgl::IntervalTree< S, Axis >::size_type = std::size_t

◆ value_type

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
using pgl::IntervalTree< S, Axis >::value_type = ShapeType

Constructor & Destructor Documentation

◆ IntervalTree() [1/2]

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
pgl::IntervalTree< S, Axis >::IntervalTree ( )
default

◆ IntervalTree() [2/2]

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
template<class Container>
pgl::IntervalTree< S, Axis >::IntervalTree ( const Container & shapes)
inlineexplicit

Builds a tree by inserting every shape in shapes.

Member Function Documentation

◆ begin()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
const_iterator pgl::IntervalTree< S, Axis >::begin ( ) const
inlinenodiscard

Returns a constant iterator to the first stored shape.

◆ cbegin()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
const_iterator pgl::IntervalTree< S, Axis >::cbegin ( ) const
inlinenodiscard

Returns a constant iterator to the first stored shape.

◆ cend()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
const_iterator pgl::IntervalTree< S, Axis >::cend ( ) const
inlinenodiscard

Returns a constant iterator past the last stored shape.

◆ countContainedIn()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
template<class Q>
std::size_t pgl::IntervalTree< S, Axis >::countContainedIn ( const Q & q) const
inlinenodiscard

Counts stored shapes geometrically contained in q.

The selected projection prunes candidates, then each survivor is tested with q.contains(shape), exactly as in ShapeTree.

◆ countIntersecting()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
template<class Q>
std::size_t pgl::IntervalTree< S, Axis >::countIntersecting ( const Q & q) const
inlinenodiscard

Counts stored shapes that geometrically intersect q.

The selected projection prunes candidates, then each survivor is tested with shape.intersects(q), exactly as in ShapeTree.

◆ countProjectionsContainedIn()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
template<class Q>
std::size_t pgl::IntervalTree< S, Axis >::countProjectionsContainedIn ( const Q & q) const
inlinenodiscard

Counts shapes whose projected interval is contained in the projection of q.

◆ countProjectionsIntersecting()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
template<class Q>
std::size_t pgl::IntervalTree< S, Axis >::countProjectionsIntersecting ( const Q & q) const
inlinenodiscard

Counts shapes whose projected interval intersects the projection of q.

◆ empty()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
bool pgl::IntervalTree< S, Axis >::empty ( ) const
inlinenodiscard

Returns whether no shape is stored.

◆ emptyContainedIn()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
template<class Q>
bool pgl::IntervalTree< S, Axis >::emptyContainedIn ( const Q & q) const
inlinenodiscard

Returns whether no stored shape is geometrically contained in q.

◆ emptyIntersecting()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
template<class Q>
bool pgl::IntervalTree< S, Axis >::emptyIntersecting ( const Q & q) const
inlinenodiscard

Returns whether no stored shape geometrically intersects q.

◆ emptyProjectionsContainedIn()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
template<class Q>
bool pgl::IntervalTree< S, Axis >::emptyProjectionsContainedIn ( const Q & q) const
inlinenodiscard

Returns whether no stored projected interval is contained in that of q.

◆ emptyProjectionsIntersecting()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
template<class Q>
bool pgl::IntervalTree< S, Axis >::emptyProjectionsIntersecting ( const Q & q) const
inlinenodiscard

Returns whether no stored projected interval intersects the projection of q.

◆ end()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
const_iterator pgl::IntervalTree< S, Axis >::end ( ) const
inlinenodiscard

Returns a constant iterator past the last stored shape.

◆ erase()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
bool pgl::IntervalTree< S, Axis >::erase ( const ShapeType & shape)
inline

Removes one stored shape equal to shape.

The owning node is located through the projected interval and then tombstoned: it stays in the tree, keeping it balanced, but owns no shape and is counted by nothing, so every query ignores it. The shape itself is swap-removed from storage, so shapes() stays compact and only the element order may change; the last live node moves into the freed slot so that a node ID keeps being the index of the shape it owns.

Once tombstones outnumber the live nodes, the index is rebuilt from the surviving shapes, yielding a structure with the same red-black and augmentation invariants as a freshly constructed tree. A rebuild costs O(n log n) but follows at least n / 2 removals, so a removal costs O(log n + k) amortized, where k is the number of stored intervals sharing the projected endpoints of shape.

Parameters
shapeShape to remove.
Returns
true if a matching shape was found and removed, false otherwise.

◆ has()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
bool pgl::IntervalTree< S, Axis >::has ( const ShapeType & shape) const
inlinenodiscard

Returns whether a shape equal to shape is stored.

◆ insert()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
void pgl::IntervalTree< S, Axis >::insert ( const ShapeType & shape)
inline

Inserts shape and its selected closed bounding-box interval.

◆ reportContainedIn()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
template<class Q>
std::vector< ShapeType > pgl::IntervalTree< S, Axis >::reportContainedIn ( const Q & q) const
inlinenodiscard

Returns copies of stored shapes geometrically contained in q.

◆ reportIntersecting()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
template<class Q>
std::vector< ShapeType > pgl::IntervalTree< S, Axis >::reportIntersecting ( const Q & q) const
inlinenodiscard

Returns copies of stored shapes that geometrically intersect q.

◆ reportProjectionsContainedIn()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
template<class Q>
std::vector< ShapeType > pgl::IntervalTree< S, Axis >::reportProjectionsContainedIn ( const Q & q) const
inlinenodiscard

Returns copies of shapes whose projected interval is contained in that of q.

◆ reportProjectionsIntersecting()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
template<class Q>
std::vector< ShapeType > pgl::IntervalTree< S, Axis >::reportProjectionsIntersecting ( const Q & q) const
inlinenodiscard

Returns copies of shapes whose projected interval intersects that of q.

◆ shapes()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
const std::vector< ShapeType > & pgl::IntervalTree< S, Axis >::shapes ( ) const
inlinenodiscard

Returns the stored shapes in internal storage order.

◆ size()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
std::size_t pgl::IntervalTree< S, Axis >::size ( ) const
inlinenodiscard

Returns the number of stored shapes.

◆ visitContainedIn()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
template<class Q, class Fn>
bool pgl::IntervalTree< S, Axis >::visitContainedIn ( const Q & q,
Fn fn ) const
inline

Visits stored shapes geometrically contained in q.

◆ visitIntersecting()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
template<class Q, class Fn>
bool pgl::IntervalTree< S, Axis >::visitIntersecting ( const Q & q,
Fn fn ) const
inline

Visits stored shapes that geometrically intersect q.

A bool-returning visitor stops when it returns true; a void visitor examines every geometrically intersecting shape.

◆ visitProjectionsContainedIn()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
template<class Q, class Fn>
bool pgl::IntervalTree< S, Axis >::visitProjectionsContainedIn ( const Q & q,
Fn fn ) const
inline

Visits projected intervals contained in q, stopping early if fn returns true.

◆ visitProjectionsIntersecting()

template<class S, ProjectionAxis Axis = ProjectionAxis::x>
template<class Q, class Fn>
bool pgl::IntervalTree< S, Axis >::visitProjectionsIntersecting ( const Q & q,
Fn fn ) const
inline

Visits projected-interval intersections, stopping early if fn returns true.