//! Crater provides KD Trees ([`kdtree::KdTree`]), minmax heaps ([`mmheap::MmHeap`]), and intrusive Fibonacci heaps ([`fheap::FibHeap`]) with as much flexibility as possible.
//! To get started quickly, look at [`cuboid::CuPoint`] and [`cuboid::CuRegion`] and the tests in [`cuboid::tests::pointcloud`].
//! This will provide an overview of how to use KD trees with the prebuilt Cartesian points/regions.
//! To associate custom data to points, create structs wrapping [`cuboid::CuPoint`] and [`cuboid::CuRegion`] which delegate to their [`KdPoint`]
//! and [`KdRegion`] implementations. To implement [`KdPoint`] and [`KdRegion`] for arbitrary custom types,
/// NB: If `T: KdPoint`, `<T as Eq>::eq` can be implemented by comparing `T::sqdist` to `T::Distance::zero()`
/// and totally ordered. See KdRegion::min_sqdist for more info. The return value should be >= Distance::zero().
/// coupled to some type implementing [`KdPoint`]. For example, the prebuilt [`cuboid::CuPoint`] struct
/// represents a point in Cartesian space with Euclidean distance, and the prebuilt [`cuboid::CuRegion`]
/// Given a point `p` in this region `A` and a layer `l`, split `A` into two subregions `B` and `C` so that:
/// - Any point `q` in `A` is in `B` or `C`, that is, if `A.min_sqdist(q) == 0`, then either `B.min_sqdist(q) == 0`
/// or `C.min_sqdist(q) == 0` (possibly both). Note that strictly speaking this only *needs* to be
/// true over all points in the tree, not all points in space, but in practice it is almost always
/// - Any point `q` in `B` is `<= p` in layer `l`, using [`KdPoint::cmp`], and any point `q` in `C` is `>= p`
/// - Any point not in `A` should hopefully be farther from `B` than from `C` (or visa versa) in at least
/// That is, if `A.min_dist(q) == d where d > 0`, then `B.min_sqdist(q), C.min_sqdist(q) >= d` (are both at least `d`),
/// Given a region and a point possibly not in the region, extend the region to include the point if
/// `self.min_sqdist(q)` can only decrease or remain the same for any fixed `q`, and in particular `self.extend(q)`
/// Create a region consisting of a single point. For cuboid regions for example, this is represented as
/// a cuboid whose inclusive "start" and "end" points are both the same. Types implementing this trait
/// should be able to represent single points fairly well, but because of the conservative nature of
/// The return value must be `<= KdPoint::sqdist` between the given point and any point within this region.
/// It's safe to return a smaller value, or even always return `Distance::zero()`, but this degrades performance because
/// If `B` is a subregion of `A` and `p` is a point not in `A`, then `B.min_sqdist(p) >= A.min_sqdist(p)`
/// Return the maximal squared distance any point in this region could have to a given point, or `None` if infinite.
/// The return value must be `>= KdPoint::sqdist` between the given point and any point within this region.
/// `None` is considered infinitely far away. It's safe to return a larger value, or even always return `None`,
/// Currently, this only happens for [`kdtree::KdTree::k_closest`] where [`kdtree::QueryOptions::lower_bound`] is [`kdtree::QueryBound::SqDist`].
/// If `B` is a subregion of `A` and `p` is a point not in `A`, then `B.max_sqdist(p) <= A.max_sqdist(p)`.
/// Return true if this region and another region might overlap, or false if they are definitely disjoint.
/// Currently only used by [`kdtree::KdTree::k_closest`] if [`kdtree::QueryOptions::outer_bound`] is [`kdtree::QueryBound::Region`].
/// Return true if this region is DEFINITELY a superset of another region, or false if it is not.
/// May return false even if self is a superset of other, if it would be expensive or difficult to compute correctly.
/// Currently only used by [`kdtree::KdTree::k_closest`] if [`kdtree::QueryOptions::inner_bound`] is [`kdtree::QueryBound::Region`]
/// Get the bounding box of a set of points. For [`cuboid::CuRegion`] and [`cuboid::CuPoint`], this will be an
/// AABB (Axis Aligned Bounding Box). For general [`KdRegion`], the bounds are not required to be tight
pub fn get_bounds<'a, R: KdRegion>(points: impl IntoIterator<Item = &'a R::Point>) -> Option<R> where R: 'a {