leodos_protocols/network/isl/
aoi.rs1use crate::network::isl::torus::{Point, Torus};
8
9#[derive(Debug, Clone, Copy)]
10struct WrappedRange {
11 start: u8,
12 end: u8,
13 modulus: u8,
14}
15
16impl WrappedRange {
17 fn new(start: u8, end: u8, modulus: u8) -> Self {
18 Self { start, end, modulus }
19 }
20
21 fn contains(&self, val: u8) -> bool {
22 if self.start <= self.end {
23 val >= self.start && val <= self.end
24 } else {
25 val >= self.start || val <= self.end
26 }
27 }
28
29 fn span(&self) -> u8 {
30 if self.end >= self.start {
31 self.end - self.start + 1
32 } else {
33 self.modulus - self.start + self.end + 1
34 }
35 }
36
37 fn midpoint(&self) -> u8 {
38 let forward = Torus::distance(self.start, self.end, self.modulus);
39 let backward = Torus::distance(self.end, self.start, self.modulus);
40
41 if forward <= backward {
42 (self.start as u16 + forward as u16 / 2) as u8 % self.modulus
43 } else {
44 self.start.wrapping_sub(backward / 2) % self.modulus
45 }
46 }
47}
48
49#[derive(Debug, Clone, Copy)]
51pub struct Aoi {
52 pub upper_left: Point,
54 pub lower_right: Point,
56}
57
58impl Aoi {
59 pub fn new(upper_left: Point, lower_right: Point) -> Self {
61 Self { upper_left, lower_right }
62 }
63
64 fn y_range(&self, torus: &Torus) -> WrappedRange {
65 WrappedRange::new(self.upper_left.orb, self.lower_right.orb, torus.num_orbs)
66 }
67
68 fn x_range(&self, torus: &Torus) -> WrappedRange {
69 WrappedRange::new(self.upper_left.sat, self.lower_right.sat, torus.num_sats)
70 }
71
72 pub fn center(&self, torus: &Torus) -> Point {
74 Point::new(self.y_range(torus).midpoint(), self.x_range(torus).midpoint())
75 }
76
77 pub fn contains(&self, torus: &Torus, point: Point) -> bool {
79 self.y_range(torus).contains(point.orb) && self.x_range(torus).contains(point.sat)
80 }
81
82 pub fn width(&self, torus: &Torus) -> u8 {
84 self.x_range(torus).span()
85 }
86
87 pub fn height(&self, torus: &Torus) -> u8 {
89 self.y_range(torus).span()
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn test_center_simple() {
99 let torus = Torus::new(8, 8);
100 let aoi = Aoi::new(Point::new(1, 1), Point::new(3, 3));
101 assert_eq!(aoi.center(&torus), Point::new(2, 2));
102 }
103
104 #[test]
105 fn test_center_wraparound() {
106 let torus = Torus::new(8, 8);
107 let aoi = Aoi::new(Point::new(6, 6), Point::new(2, 2));
108 assert_eq!(aoi.center(&torus), Point::new(0, 0));
109 }
110
111 #[test]
112 fn test_contains_simple() {
113 let torus = Torus::new(8, 8);
114 let aoi = Aoi::new(Point::new(1, 1), Point::new(3, 3));
115
116 assert!(aoi.contains(&torus, Point::new(2, 2)));
117 assert!(aoi.contains(&torus, Point::new(1, 1)));
118 assert!(aoi.contains(&torus, Point::new(3, 3)));
119 assert!(!aoi.contains(&torus, Point::new(0, 0)));
120 assert!(!aoi.contains(&torus, Point::new(4, 4)));
121 }
122
123 #[test]
124 fn test_contains_wraparound() {
125 let torus = Torus::new(8, 8);
126 let aoi = Aoi::new(Point::new(6, 6), Point::new(2, 2));
127
128 assert!(aoi.contains(&torus, Point::new(0, 0)));
129 assert!(aoi.contains(&torus, Point::new(7, 7)));
130 assert!(aoi.contains(&torus, Point::new(6, 6)));
131 assert!(aoi.contains(&torus, Point::new(2, 2)));
132 assert!(!aoi.contains(&torus, Point::new(4, 4)));
133 }
134
135 #[test]
136 fn test_dimensions() {
137 let torus = Torus::new(8, 8);
138
139 let aoi = Aoi::new(Point::new(1, 1), Point::new(3, 5));
140 assert_eq!(aoi.height(&torus), 3);
141 assert_eq!(aoi.width(&torus), 5);
142
143 let aoi_wrap = Aoi::new(Point::new(6, 6), Point::new(2, 2));
144 assert_eq!(aoi_wrap.height(&torus), 5);
145 assert_eq!(aoi_wrap.width(&torus), 5);
146 }
147}