use crate::Point;
#[derive(Debug, Clone, PartialEq)]
pub enum Completeness<R> {
Complete,
Incomplete {
reason: IncompleteReason,
regions: Vec<R>,
},
Sampled,
}
impl<R> Completeness<R> {
pub fn is_complete(&self) -> bool {
matches!(self, Completeness::Complete)
}
}
pub(super) fn of_unsettled<R: Region>(regions: Vec<R>, exhausted: bool) -> Completeness<R> {
if regions.is_empty() {
return Completeness::Complete;
}
Completeness::Incomplete {
reason: if exhausted {
IncompleteReason::BudgetExhausted
} else {
IncompleteReason::Unseparated
},
regions: merged(regions),
}
}
pub(super) fn both<R: Region>(a: Completeness<R>, b: Completeness<R>) -> Completeness<R> {
use Completeness::{Complete, Incomplete, Sampled};
match (a, b) {
(Sampled, _) | (_, Sampled) => Sampled,
(Complete, other) | (other, Complete) => other,
(
Incomplete {
reason: ra,
mut regions,
},
Incomplete {
reason: rb,
regions: more,
},
) => {
regions.extend(more);
let exhausted = [ra, rb].contains(&IncompleteReason::BudgetExhausted);
of_unsettled(regions, exhausted)
}
}
}
pub(super) trait Region: Sized {
fn touches(&self, other: &Self) -> bool;
fn union(&self, other: &Self) -> Self;
fn start(&self) -> f64;
}
pub(super) fn meet((a0, a1): (f64, f64), (b0, b1): (f64, f64)) -> bool {
a0 <= b1 && b0 <= a1
}
pub(super) fn span((a0, a1): (f64, f64), (b0, b1): (f64, f64)) -> (f64, f64) {
(a0.min(b0), a1.max(b1))
}
pub(super) fn box_union((p, r): (Point, Point), (q, s): (Point, Point)) -> (Point, Point) {
(
Point::new(p.x.min(q.x), p.y.min(q.y), p.z.min(q.z)),
Point::new(r.x.max(s.x), r.y.max(s.y), r.z.max(s.z)),
)
}
pub(super) fn merged<R: Region>(mut regions: Vec<R>) -> Vec<R> {
let mut out: Vec<R> = Vec::new();
while let Some(mut region) = regions.pop() {
loop {
let before = out.len();
out.retain(|r| {
let touches = region.touches(r);
if touches {
region = region.union(r);
}
!touches
});
if out.len() == before {
break;
}
}
out.push(region);
}
out.sort_by(|a, b| a.start().total_cmp(&b.start()));
out
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IncompleteReason {
BudgetExhausted,
Unseparated,
}