1#[derive(Debug, Clone, Copy, PartialEq)]
5pub struct Point {
6 pub x: f64,
8 pub y: f64,
10}
11
12impl Point {
13 pub fn new(x: f64, y: f64) -> Self {
15 Self { x, y }
16 }
17
18 pub fn origin() -> Self {
20 Self { x: 0.0, y: 0.0 }
21 }
22}
23
24impl From<(f64, f64)> for Point {
25 fn from((x, y): (f64, f64)) -> Self {
26 Self::new(x, y)
27 }
28}
29
30#[derive(Debug, Clone, Copy, PartialEq)]
32pub struct Rectangle {
33 pub lower_left: Point,
35 pub upper_right: Point,
37}
38
39impl Rectangle {
40 pub fn new(lower_left: Point, upper_right: Point) -> Self {
42 Self {
43 lower_left,
44 upper_right,
45 }
46 }
47
48 pub fn from_position_and_size(x: f64, y: f64, width: f64, height: f64) -> Self {
50 Self {
51 lower_left: Point::new(x, y),
52 upper_right: Point::new(x + width, y + height),
53 }
54 }
55
56 pub fn width(&self) -> f64 {
58 self.upper_right.x - self.lower_left.x
59 }
60
61 pub fn height(&self) -> f64 {
63 self.upper_right.y - self.lower_left.y
64 }
65
66 pub fn center(&self) -> Point {
68 Point::new(
69 (self.lower_left.x + self.upper_right.x) / 2.0,
70 (self.lower_left.y + self.upper_right.y) / 2.0,
71 )
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn test_point() {
81 let p = Point::new(10.0, 20.0);
82 assert_eq!(p.x, 10.0);
83 assert_eq!(p.y, 20.0);
84
85 let origin = Point::origin();
86 assert_eq!(origin.x, 0.0);
87 assert_eq!(origin.y, 0.0);
88 }
89
90 #[test]
91 fn test_rectangle() {
92 let rect = Rectangle::new(Point::new(10.0, 20.0), Point::new(110.0, 120.0));
93
94 assert_eq!(rect.width(), 100.0);
95 assert_eq!(rect.height(), 100.0);
96
97 let center = rect.center();
98 assert_eq!(center.x, 60.0);
99 assert_eq!(center.y, 70.0);
100 }
101
102 #[test]
103 fn test_rectangle_from_position_and_size() {
104 let rect = Rectangle::from_position_and_size(10.0, 20.0, 50.0, 30.0);
105 assert_eq!(rect.lower_left.x, 10.0);
106 assert_eq!(rect.lower_left.y, 20.0);
107 assert_eq!(rect.upper_right.x, 60.0);
108 assert_eq!(rect.upper_right.y, 50.0);
109 }
110
111 #[test]
112 fn test_point_edge_cases() {
113 let p = Point::new(-10.0, -20.0);
115 assert_eq!(p.x, -10.0);
116 assert_eq!(p.y, -20.0);
117
118 let p = Point::new(0.0, 0.0);
120 assert_eq!(p.x, 0.0);
121 assert_eq!(p.y, 0.0);
122
123 let p = Point::new(f64::MAX, f64::MIN);
125 assert_eq!(p.x, f64::MAX);
126 assert_eq!(p.y, f64::MIN);
127
128 let p = Point::new(f64::INFINITY, f64::NEG_INFINITY);
130 assert_eq!(p.x, f64::INFINITY);
131 assert_eq!(p.y, f64::NEG_INFINITY);
132
133 let p = Point::new(f64::NAN, 0.0);
134 assert!(p.x.is_nan());
135 assert_eq!(p.y, 0.0);
136 }
137
138 #[test]
139 fn test_point_copy_clone_debug() {
140 let p1 = Point::new(5.0, 10.0);
141 let p2 = p1; let p3 = p1; assert_eq!(p1, p2);
145 assert_eq!(p1, p3);
146 assert_eq!(p2, p3);
147
148 let debug_str = format!("{p1:?}");
150 assert!(debug_str.contains("Point"));
151 assert!(debug_str.contains("5.0"));
152 assert!(debug_str.contains("10.0"));
153 }
154
155 #[test]
156 fn test_point_partial_eq() {
157 let p1 = Point::new(1.0, 2.0);
158 let p2 = Point::new(1.0, 2.0);
159 let p3 = Point::new(1.0, 3.0);
160 let p4 = Point::new(2.0, 2.0);
161
162 assert_eq!(p1, p2);
163 assert_ne!(p1, p3);
164 assert_ne!(p1, p4);
165 assert_ne!(p3, p4);
166
167 let p_inf = Point::new(f64::INFINITY, f64::INFINITY);
169 let p_inf2 = Point::new(f64::INFINITY, f64::INFINITY);
170 assert_eq!(p_inf, p_inf2);
171
172 let p_nan = Point::new(f64::NAN, 0.0);
173 let p_nan2 = Point::new(f64::NAN, 0.0);
174 assert_ne!(p_nan, p_nan2); }
176
177 #[test]
178 fn test_rectangle_edge_cases() {
179 let rect = Rectangle::from_position_and_size(-10.0, -20.0, 5.0, 10.0);
181 assert_eq!(rect.width(), 5.0);
182 assert_eq!(rect.height(), 10.0);
183 assert_eq!(rect.lower_left.x, -10.0);
184 assert_eq!(rect.lower_left.y, -20.0);
185 assert_eq!(rect.upper_right.x, -5.0);
186 assert_eq!(rect.upper_right.y, -10.0);
187
188 let rect = Rectangle::from_position_and_size(0.0, 0.0, 0.0, 0.0);
190 assert_eq!(rect.width(), 0.0);
191 assert_eq!(rect.height(), 0.0);
192 let center = rect.center();
193 assert_eq!(center.x, 0.0);
194 assert_eq!(center.y, 0.0);
195
196 let rect = Rectangle::from_position_and_size(0.0, 0.0, f64::MAX / 2.0, f64::MAX / 2.0);
198 assert_eq!(rect.width(), f64::MAX / 2.0);
199 assert_eq!(rect.height(), f64::MAX / 2.0);
200 }
201
202 #[test]
203 fn test_rectangle_negative_dimensions() {
204 let rect = Rectangle::new(Point::new(10.0, 20.0), Point::new(5.0, 15.0));
206 assert_eq!(rect.width(), -5.0); assert_eq!(rect.height(), -5.0); let center = rect.center();
210 assert_eq!(center.x, 7.5);
211 assert_eq!(center.y, 17.5);
212 }
213
214 #[test]
215 fn test_rectangle_center_precision() {
216 let rect = Rectangle::from_position_and_size(1.0, 1.0, 3.0, 5.0);
218 let center = rect.center();
219 assert_eq!(center.x, 2.5); assert_eq!(center.y, 3.5); let rect = Rectangle::from_position_and_size(0.1, 0.1, 0.2, 0.2);
224 let center = rect.center();
225 assert!((center.x - 0.2).abs() < f64::EPSILON);
226 assert!((center.y - 0.2).abs() < f64::EPSILON);
227 }
228
229 #[test]
230 fn test_rectangle_copy_clone_debug_partial_eq() {
231 let rect1 = Rectangle::new(Point::new(0.0, 0.0), Point::new(10.0, 20.0));
232 let rect2 = rect1; let rect3 = rect1; let rect4 = Rectangle::new(Point::new(0.0, 0.0), Point::new(10.0, 21.0));
235
236 assert_eq!(rect1, rect2);
237 assert_eq!(rect1, rect3);
238 assert_ne!(rect1, rect4);
239
240 let debug_str = format!("{rect1:?}");
242 assert!(debug_str.contains("Rectangle"));
243 assert!(debug_str.contains("lower_left"));
244 assert!(debug_str.contains("upper_right"));
245 }
246
247 #[test]
248 fn test_rectangle_with_special_float_values() {
249 let rect = Rectangle::new(
251 Point::new(f64::NEG_INFINITY, f64::NEG_INFINITY),
252 Point::new(f64::INFINITY, f64::INFINITY),
253 );
254 assert_eq!(rect.width(), f64::INFINITY);
255 assert_eq!(rect.height(), f64::INFINITY);
256
257 let rect = Rectangle::new(Point::new(0.0, 0.0), Point::new(f64::NAN, 10.0));
259 assert!(rect.width().is_nan());
260 assert_eq!(rect.height(), 10.0);
261
262 let center = rect.center();
263 assert!(center.x.is_nan());
264 assert_eq!(center.y, 5.0);
265 }
266
267 #[test]
268 fn test_rectangle_extreme_coordinates() {
269 let rect = Rectangle::new(
271 Point::new(f64::MIN, f64::MIN),
272 Point::new(f64::MAX, f64::MAX),
273 );
274
275 assert!(rect.width().is_infinite() && rect.width() > 0.0);
277 assert!(rect.height().is_infinite() && rect.height() > 0.0);
278 }
279
280 #[test]
281 fn test_point_origin_function() {
282 let origin1 = Point::origin();
283 let origin2 = Point::new(0.0, 0.0);
284
285 assert_eq!(origin1, origin2);
286 assert_eq!(origin1.x, 0.0);
287 assert_eq!(origin1.y, 0.0);
288
289 let origin3 = Point::origin();
291 assert_eq!(origin1, origin3);
292 }
293
294 #[test]
295 fn test_rectangle_construction_methods() {
296 let rect1 = Rectangle::new(Point::new(5.0, 10.0), Point::new(15.0, 25.0));
298 let rect2 = Rectangle::from_position_and_size(5.0, 10.0, 10.0, 15.0);
299
300 assert_eq!(rect1.lower_left, rect2.lower_left);
301 assert_eq!(rect1.upper_right, rect2.upper_right);
302 assert_eq!(rect1.width(), rect2.width());
303 assert_eq!(rect1.height(), rect2.height());
304 assert_eq!(rect1.center(), rect2.center());
305 }
306
307 #[test]
308 fn test_geometric_calculations() {
309 let rect = Rectangle::from_position_and_size(2.0, 3.0, 8.0, 6.0);
310
311 assert_eq!(rect.lower_left.x, 2.0);
313 assert_eq!(rect.lower_left.y, 3.0);
314 assert_eq!(rect.upper_right.x, 10.0);
315 assert_eq!(rect.upper_right.y, 9.0);
316 assert_eq!(rect.width(), 8.0);
317 assert_eq!(rect.height(), 6.0);
318
319 let center = rect.center();
320 assert_eq!(center.x, 6.0); assert_eq!(center.y, 6.0); }
323
324 #[test]
325 fn test_floating_point_precision() {
326 let p1 = Point::new(1.0 / 3.0, 2.0 / 3.0);
328 let p2 = Point::new(4.0 / 3.0, 5.0 / 3.0);
329 let rect = Rectangle::new(p1, p2);
330
331 let width = rect.width();
332 let height = rect.height();
333 let center = rect.center();
334
335 assert!((width - 1.0).abs() < f64::EPSILON);
337 assert!((height - 1.0).abs() < f64::EPSILON);
338
339 let expected_center_x = 5.0 / 6.0;
341 let expected_center_y = 7.0 / 6.0;
342 assert!((center.x - expected_center_x).abs() < f64::EPSILON);
343 assert!((center.y - expected_center_y).abs() < f64::EPSILON);
344 }
345
346 #[test]
347 fn test_point_with_mathematical_constants() {
348 use std::f64::consts::*;
349 let p = Point::new(PI, E);
350 assert_eq!(p.x, PI);
351 assert_eq!(p.y, E);
352
353 let origin = Point::origin();
354 assert_ne!(p, origin);
355 }
356
357 #[test]
358 fn test_rectangle_area_and_perimeter_concepts() {
359 let rect = Rectangle::from_position_and_size(0.0, 0.0, 4.0, 3.0);
361
362 let width = rect.width();
363 let height = rect.height();
364
365 let calculated_area = width * height;
367 let calculated_perimeter = 2.0 * (width + height);
368
369 assert_eq!(calculated_area, 12.0);
370 assert_eq!(calculated_perimeter, 14.0);
371 }
372
373 #[test]
374 fn test_point_distance_concepts() {
375 let p1 = Point::new(0.0, 0.0);
377 let p2 = Point::new(3.0, 4.0);
378
379 let dx = p2.x - p1.x;
380 let dy = p2.y - p1.y;
381 let distance_squared = dx * dx + dy * dy;
382 let distance = distance_squared.sqrt();
383
384 assert_eq!(dx, 3.0);
385 assert_eq!(dy, 4.0);
386 assert_eq!(distance_squared, 25.0);
387 assert_eq!(distance, 5.0);
388 }
389
390 #[test]
391 fn test_rectangle_contains_concepts() {
392 let rect = Rectangle::from_position_and_size(10.0, 20.0, 30.0, 40.0);
394 let test_point = Point::new(25.0, 35.0);
395
396 let within_x = test_point.x >= rect.lower_left.x && test_point.x <= rect.upper_right.x;
398 let within_y = test_point.y >= rect.lower_left.y && test_point.y <= rect.upper_right.y;
399 let would_contain = within_x && within_y;
400
401 assert!(within_x);
402 assert!(within_y);
403 assert!(would_contain);
404
405 let outside_point = Point::new(5.0, 35.0);
407 let outside_x =
408 outside_point.x >= rect.lower_left.x && outside_point.x <= rect.upper_right.x;
409 assert!(!outside_x);
410 }
411
412 #[test]
413 fn test_rectangle_intersection_concepts() {
414 let rect1 = Rectangle::from_position_and_size(0.0, 0.0, 10.0, 10.0);
415 let rect2 = Rectangle::from_position_and_size(5.0, 5.0, 10.0, 10.0);
416
417 let left = rect1.lower_left.x.max(rect2.lower_left.x);
419 let bottom = rect1.lower_left.y.max(rect2.lower_left.y);
420 let right = rect1.upper_right.x.min(rect2.upper_right.x);
421 let top = rect1.upper_right.y.min(rect2.upper_right.y);
422
423 let intersects = left < right && bottom < top;
424
425 assert_eq!(left, 5.0);
426 assert_eq!(bottom, 5.0);
427 assert_eq!(right, 10.0);
428 assert_eq!(top, 10.0);
429 assert!(intersects);
430
431 let rect3 = Rectangle::from_position_and_size(20.0, 20.0, 5.0, 5.0);
433 let left3 = rect1.lower_left.x.max(rect3.lower_left.x);
434 let right3 = rect1.upper_right.x.min(rect3.upper_right.x);
435 let no_intersection = left3 >= right3;
436 assert!(no_intersection);
437 }
438}