1use std::fmt;
2
3#[derive(Debug, Clone, Copy, PartialEq)]
4pub struct Box {
5 x: i32,
6 y: i32,
7 width: i32,
8 height: i32,
9}
10
11impl Box {
12 pub fn new(x: i32, y: i32, width: i32, height: i32) -> Self {
13 Self {
14 x,
15 y,
16 width,
17 height,
18 }
19 }
20
21 pub fn x(&self) -> i32 {
22 self.x
23 }
24
25 pub fn y(&self) -> i32 {
26 self.y
27 }
28
29 pub fn width(&self) -> i32 {
30 self.width
31 }
32
33 pub fn height(&self) -> i32 {
34 self.height
35 }
36
37 pub fn is_empty(&self) -> bool {
38 self.width <= 0 || self.height <= 0
39 }
40
41 pub fn intersects(&self, other: &Box) -> bool {
42 if self.is_empty() || other.is_empty() {
43 return false;
44 }
45
46 let x1 = self.x.max(other.x);
47 let y1 = self.y.max(other.y);
48 let x2 = (self.x + self.width).min(other.x + other.width);
49 let y2 = (self.y + self.height).min(other.y + other.height);
50
51 x2 > x1 && y2 > y1
52 }
53
54 pub fn intersection(&self, other: &Box) -> Option<Box> {
55 if !self.intersects(other) {
56 return None;
57 }
58
59 let x1 = self.x.max(other.x);
60 let y1 = self.y.max(other.y);
61 let x2 = (self.x + self.width).min(other.x + other.width);
62 let y2 = (self.y + self.height).min(other.y + other.height);
63
64 Some(Box::new(x1, y1, x2 - x1, y2 - y1))
65 }
66}
67
68impl fmt::Display for Box {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 write!(f, "{},{} {}x{}", self.x, self.y, self.width, self.height)
71 }
72}
73
74impl std::str::FromStr for Box {
75 type Err = crate::Error;
76
77 fn from_str(s: &str) -> Result<Self, Self::Err> {
78 let parts: Vec<&str> = s.split(' ').collect();
79 if parts.len() != 2 {
80 return Err(crate::Error::InvalidGeometry(s.to_string()));
81 }
82
83 let xy: Vec<&str> = parts[0].split(',').collect();
84 let wh: Vec<&str> = parts[1].split('x').collect();
85
86 if xy.len() != 2 || wh.len() != 2 {
87 return Err(crate::Error::InvalidGeometry(s.to_string()));
88 }
89
90 let x = xy[0]
91 .parse()
92 .map_err(|_| crate::Error::InvalidGeometry(s.to_string()))?;
93 let y = xy[1]
94 .parse()
95 .map_err(|_| crate::Error::InvalidGeometry(s.to_string()))?;
96 let width = wh[0]
97 .parse()
98 .map_err(|_| crate::Error::InvalidGeometry(s.to_string()))?;
99 let height = wh[1]
100 .parse()
101 .map_err(|_| crate::Error::InvalidGeometry(s.to_string()))?;
102
103 Ok(Box::new(x, y, width, height))
104 }
105}