use crate::{Px, PxBox, PxPoint, PxRect, PxSize, PxVector};
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
pub enum Orientation2D {
Above,
Right,
Below,
Left,
}
impl Orientation2D {
pub fn point_is(self, origin: PxPoint, point: PxPoint) -> bool {
let (a, b, c, d) = match self {
Orientation2D::Above => (point.y, origin.y, point.x, origin.x),
Orientation2D::Right => (origin.x, point.x, point.y, origin.y),
Orientation2D::Below => (origin.y, point.y, point.x, origin.x),
Orientation2D::Left => (point.x, origin.x, point.y, origin.y),
};
let mut is = false;
if a < b {
if c > d {
is = c <= d + (b - a);
} else {
is = c >= d - (b - a);
}
}
is
}
pub fn box_is(self, origin: PxBox, b: PxBox) -> bool {
fn d_intersects(a_min: Px, a_max: Px, b_min: Px, b_max: Px) -> bool {
a_min < b_max && a_max > b_min
}
match self {
Orientation2D::Above => b.min.y <= origin.min.y && d_intersects(b.min.x, b.max.x, origin.min.x, origin.max.x),
Orientation2D::Left => b.min.x <= origin.min.x && d_intersects(b.min.y, b.max.y, origin.min.y, origin.max.y),
Orientation2D::Below => b.max.y >= origin.max.y && d_intersects(b.min.x, b.max.x, origin.min.x, origin.max.x),
Orientation2D::Right => b.max.x >= origin.max.x && d_intersects(b.min.y, b.max.y, origin.min.y, origin.max.y),
}
}
pub fn search_bounds(self, origin: PxPoint, max_distance: Px, spatial_bounds: PxBox) -> impl Iterator<Item = PxBox> {
let mut bounds = PxRect::new(origin, PxSize::splat(max_distance));
match self {
Orientation2D::Above => {
bounds.origin.x -= max_distance / Px(2);
bounds.origin.y -= max_distance;
}
Orientation2D::Right => bounds.origin.y -= max_distance / Px(2),
Orientation2D::Below => bounds.origin.x -= max_distance / Px(2),
Orientation2D::Left => {
bounds.origin.y -= max_distance / Px(2);
bounds.origin.x -= max_distance;
}
}
let max_quad = spatial_bounds.intersection_unchecked(&bounds.to_box2d());
let mut is_none = max_quad.is_empty();
let mut source_quad = PxRect::new(origin - PxVector::splat(Px(64)), PxSize::splat(Px(128))).to_box2d();
let mut search_quad = source_quad.intersection_unchecked(&max_quad);
is_none |= search_quad.is_empty();
let max_diameter = max_distance * Px(2);
let mut is_first = true;
std::iter::from_fn(move || {
let source_width = source_quad.width();
if is_none {
None
} else if is_first {
is_first = false;
Some(search_quad)
} else if source_width >= max_diameter {
is_none = true;
None
} else {
source_quad = source_quad.inflate(source_width, source_width);
let mut new_search = source_quad.intersection_unchecked(&max_quad);
if new_search == source_quad || new_search.is_empty() {
is_none = true; return None;
}
match self {
Orientation2D::Above => {
new_search.max.y = search_quad.min.y;
}
Orientation2D::Right => {
new_search.min.x = search_quad.max.x;
}
Orientation2D::Below => {
new_search.min.y = search_quad.max.y;
}
Orientation2D::Left => {
new_search.max.x = search_quad.min.x;
}
}
search_quad = new_search;
Some(search_quad)
}
})
}
}