zng_unit/
orientation.rs
1use crate::{Px, PxBox, PxPoint, PxRect, PxSize, PxVector};
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
7pub enum Orientation2D {
8 Above,
10 Right,
12 Below,
14 Left,
16}
17impl Orientation2D {
18 pub fn point_is(self, origin: PxPoint, point: PxPoint) -> bool {
22 let (a, b, c, d) = match self {
23 Orientation2D::Above => (point.y, origin.y, point.x, origin.x),
24 Orientation2D::Right => (origin.x, point.x, point.y, origin.y),
25 Orientation2D::Below => (origin.y, point.y, point.x, origin.x),
26 Orientation2D::Left => (point.x, origin.x, point.y, origin.y),
27 };
28
29 let mut is = false;
30
31 if a < b {
34 if c > d {
36 is = c <= d + (b - a);
40 } else {
41 is = c >= d - (b - a);
44 }
45 }
46
47 is
48 }
49
50 pub fn box_is(self, origin: PxBox, b: PxBox) -> bool {
55 fn d_intersects(a_min: Px, a_max: Px, b_min: Px, b_max: Px) -> bool {
56 a_min < b_max && a_max > b_min
57 }
58 match self {
59 Orientation2D::Above => b.min.y <= origin.min.y && d_intersects(b.min.x, b.max.x, origin.min.x, origin.max.x),
60 Orientation2D::Left => b.min.x <= origin.min.x && d_intersects(b.min.y, b.max.y, origin.min.y, origin.max.y),
61 Orientation2D::Below => b.max.y >= origin.max.y && d_intersects(b.min.x, b.max.x, origin.min.x, origin.max.x),
62 Orientation2D::Right => b.max.x >= origin.max.x && d_intersects(b.min.y, b.max.y, origin.min.y, origin.max.y),
63 }
64 }
65
66 pub fn search_bounds(self, origin: PxPoint, max_distance: Px, spatial_bounds: PxBox) -> impl Iterator<Item = PxBox> + 'static {
69 let mut bounds = PxRect::new(origin, PxSize::splat(max_distance));
70 match self {
71 Orientation2D::Above => {
72 bounds.origin.x -= max_distance / Px(2);
73 bounds.origin.y -= max_distance;
74 }
75 Orientation2D::Right => bounds.origin.y -= max_distance / Px(2),
76 Orientation2D::Below => bounds.origin.x -= max_distance / Px(2),
77 Orientation2D::Left => {
78 bounds.origin.y -= max_distance / Px(2);
79 bounds.origin.x -= max_distance;
80 }
81 }
82
83 let max_quad = spatial_bounds.intersection_unchecked(&bounds.to_box2d());
88 let mut is_none = max_quad.is_empty();
89
90 let mut source_quad = PxRect::new(origin - PxVector::splat(Px(64)), PxSize::splat(Px(128))).to_box2d();
91 let mut search_quad = source_quad.intersection_unchecked(&max_quad);
92 is_none |= search_quad.is_empty();
93
94 let max_diameter = max_distance * Px(2);
95
96 let mut is_first = true;
97
98 std::iter::from_fn(move || {
99 let source_width = source_quad.width();
100 if is_none {
101 None
102 } else if is_first {
103 is_first = false;
104 Some(search_quad)
105 } else if source_width >= max_diameter {
106 is_none = true;
107 None
108 } else {
109 source_quad = source_quad.inflate(source_width, source_width);
110 let mut new_search = source_quad.intersection_unchecked(&max_quad);
111 if new_search == source_quad || new_search.is_empty() {
112 is_none = true; return None;
114 }
115
116 match self {
117 Orientation2D::Above => {
118 new_search.max.y = search_quad.min.y;
119 }
120 Orientation2D::Right => {
121 new_search.min.x = search_quad.max.x;
122 }
123 Orientation2D::Below => {
124 new_search.min.y = search_quad.max.y;
125 }
126 Orientation2D::Left => {
127 new_search.max.x = search_quad.min.x;
128 }
129 }
130
131 search_quad = new_search;
132
133 Some(search_quad)
134 }
135 })
136 }
137}