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
24#[derive(Debug, Clone, Copy, PartialEq)]
26pub struct Rectangle {
27 pub lower_left: Point,
29 pub upper_right: Point,
31}
32
33impl Rectangle {
34 pub fn new(lower_left: Point, upper_right: Point) -> Self {
36 Self {
37 lower_left,
38 upper_right,
39 }
40 }
41
42 pub fn from_position_and_size(x: f64, y: f64, width: f64, height: f64) -> Self {
44 Self {
45 lower_left: Point::new(x, y),
46 upper_right: Point::new(x + width, y + height),
47 }
48 }
49
50 pub fn width(&self) -> f64 {
52 self.upper_right.x - self.lower_left.x
53 }
54
55 pub fn height(&self) -> f64 {
57 self.upper_right.y - self.lower_left.y
58 }
59
60 pub fn center(&self) -> Point {
62 Point::new(
63 (self.lower_left.x + self.upper_right.x) / 2.0,
64 (self.lower_left.y + self.upper_right.y) / 2.0,
65 )
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn test_point() {
75 let p = Point::new(10.0, 20.0);
76 assert_eq!(p.x, 10.0);
77 assert_eq!(p.y, 20.0);
78
79 let origin = Point::origin();
80 assert_eq!(origin.x, 0.0);
81 assert_eq!(origin.y, 0.0);
82 }
83
84 #[test]
85 fn test_rectangle() {
86 let rect = Rectangle::new(Point::new(10.0, 20.0), Point::new(110.0, 120.0));
87
88 assert_eq!(rect.width(), 100.0);
89 assert_eq!(rect.height(), 100.0);
90
91 let center = rect.center();
92 assert_eq!(center.x, 60.0);
93 assert_eq!(center.y, 70.0);
94 }
95
96 #[test]
97 fn test_rectangle_from_position_and_size() {
98 let rect = Rectangle::from_position_and_size(10.0, 20.0, 50.0, 30.0);
99 assert_eq!(rect.lower_left.x, 10.0);
100 assert_eq!(rect.lower_left.y, 20.0);
101 assert_eq!(rect.upper_right.x, 60.0);
102 assert_eq!(rect.upper_right.y, 50.0);
103 }
104
105 #[test]
106 fn test_point_edge_cases() {
107 let p = Point::new(-10.0, -20.0);
109 assert_eq!(p.x, -10.0);
110 assert_eq!(p.y, -20.0);
111
112 let p = Point::new(0.0, 0.0);
114 assert_eq!(p.x, 0.0);
115 assert_eq!(p.y, 0.0);
116
117 let p = Point::new(f64::MAX, f64::MIN);
119 assert_eq!(p.x, f64::MAX);
120 assert_eq!(p.y, f64::MIN);
121
122 let p = Point::new(f64::INFINITY, f64::NEG_INFINITY);
124 assert_eq!(p.x, f64::INFINITY);
125 assert_eq!(p.y, f64::NEG_INFINITY);
126
127 let p = Point::new(f64::NAN, 0.0);
128 assert!(p.x.is_nan());
129 assert_eq!(p.y, 0.0);
130 }
131
132 #[test]
133 fn test_point_copy_clone_debug() {
134 let p1 = Point::new(5.0, 10.0);
135 let p2 = p1; let p3 = p1.clone(); assert_eq!(p1, p2);
139 assert_eq!(p1, p3);
140 assert_eq!(p2, p3);
141
142 let debug_str = format!("{:?}", p1);
144 assert!(debug_str.contains("Point"));
145 assert!(debug_str.contains("5.0"));
146 assert!(debug_str.contains("10.0"));
147 }
148
149 #[test]
150 fn test_point_partial_eq() {
151 let p1 = Point::new(1.0, 2.0);
152 let p2 = Point::new(1.0, 2.0);
153 let p3 = Point::new(1.0, 3.0);
154 let p4 = Point::new(2.0, 2.0);
155
156 assert_eq!(p1, p2);
157 assert_ne!(p1, p3);
158 assert_ne!(p1, p4);
159 assert_ne!(p3, p4);
160
161 let p_inf = Point::new(f64::INFINITY, f64::INFINITY);
163 let p_inf2 = Point::new(f64::INFINITY, f64::INFINITY);
164 assert_eq!(p_inf, p_inf2);
165
166 let p_nan = Point::new(f64::NAN, 0.0);
167 let p_nan2 = Point::new(f64::NAN, 0.0);
168 assert_ne!(p_nan, p_nan2); }
170
171 #[test]
172 fn test_rectangle_edge_cases() {
173 let rect = Rectangle::from_position_and_size(-10.0, -20.0, 5.0, 10.0);
175 assert_eq!(rect.width(), 5.0);
176 assert_eq!(rect.height(), 10.0);
177 assert_eq!(rect.lower_left.x, -10.0);
178 assert_eq!(rect.lower_left.y, -20.0);
179 assert_eq!(rect.upper_right.x, -5.0);
180 assert_eq!(rect.upper_right.y, -10.0);
181
182 let rect = Rectangle::from_position_and_size(0.0, 0.0, 0.0, 0.0);
184 assert_eq!(rect.width(), 0.0);
185 assert_eq!(rect.height(), 0.0);
186 let center = rect.center();
187 assert_eq!(center.x, 0.0);
188 assert_eq!(center.y, 0.0);
189
190 let rect = Rectangle::from_position_and_size(0.0, 0.0, f64::MAX / 2.0, f64::MAX / 2.0);
192 assert_eq!(rect.width(), f64::MAX / 2.0);
193 assert_eq!(rect.height(), f64::MAX / 2.0);
194 }
195
196 #[test]
197 fn test_rectangle_negative_dimensions() {
198 let rect = Rectangle::new(Point::new(10.0, 20.0), Point::new(5.0, 15.0));
200 assert_eq!(rect.width(), -5.0); assert_eq!(rect.height(), -5.0); let center = rect.center();
204 assert_eq!(center.x, 7.5);
205 assert_eq!(center.y, 17.5);
206 }
207
208 #[test]
209 fn test_rectangle_center_precision() {
210 let rect = Rectangle::from_position_and_size(1.0, 1.0, 3.0, 5.0);
212 let center = rect.center();
213 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);
218 let center = rect.center();
219 assert!((center.x - 0.2).abs() < f64::EPSILON);
220 assert!((center.y - 0.2).abs() < f64::EPSILON);
221 }
222
223 #[test]
224 fn test_rectangle_copy_clone_debug_partial_eq() {
225 let rect1 = Rectangle::new(Point::new(0.0, 0.0), Point::new(10.0, 20.0));
226 let rect2 = rect1; let rect3 = rect1.clone(); let rect4 = Rectangle::new(Point::new(0.0, 0.0), Point::new(10.0, 21.0));
229
230 assert_eq!(rect1, rect2);
231 assert_eq!(rect1, rect3);
232 assert_ne!(rect1, rect4);
233
234 let debug_str = format!("{:?}", rect1);
236 assert!(debug_str.contains("Rectangle"));
237 assert!(debug_str.contains("lower_left"));
238 assert!(debug_str.contains("upper_right"));
239 }
240
241 #[test]
242 fn test_rectangle_with_special_float_values() {
243 let rect = Rectangle::new(
245 Point::new(f64::NEG_INFINITY, f64::NEG_INFINITY),
246 Point::new(f64::INFINITY, f64::INFINITY),
247 );
248 assert_eq!(rect.width(), f64::INFINITY);
249 assert_eq!(rect.height(), f64::INFINITY);
250
251 let rect = Rectangle::new(Point::new(0.0, 0.0), Point::new(f64::NAN, 10.0));
253 assert!(rect.width().is_nan());
254 assert_eq!(rect.height(), 10.0);
255
256 let center = rect.center();
257 assert!(center.x.is_nan());
258 assert_eq!(center.y, 5.0);
259 }
260
261 #[test]
262 fn test_rectangle_extreme_coordinates() {
263 let rect = Rectangle::new(
265 Point::new(f64::MIN, f64::MIN),
266 Point::new(f64::MAX, f64::MAX),
267 );
268
269 assert!(rect.width().is_infinite() && rect.width() > 0.0);
271 assert!(rect.height().is_infinite() && rect.height() > 0.0);
272 }
273
274 #[test]
275 fn test_point_origin_function() {
276 let origin1 = Point::origin();
277 let origin2 = Point::new(0.0, 0.0);
278
279 assert_eq!(origin1, origin2);
280 assert_eq!(origin1.x, 0.0);
281 assert_eq!(origin1.y, 0.0);
282
283 let origin3 = Point::origin();
285 assert_eq!(origin1, origin3);
286 }
287
288 #[test]
289 fn test_rectangle_construction_methods() {
290 let rect1 = Rectangle::new(Point::new(5.0, 10.0), Point::new(15.0, 25.0));
292 let rect2 = Rectangle::from_position_and_size(5.0, 10.0, 10.0, 15.0);
293
294 assert_eq!(rect1.lower_left, rect2.lower_left);
295 assert_eq!(rect1.upper_right, rect2.upper_right);
296 assert_eq!(rect1.width(), rect2.width());
297 assert_eq!(rect1.height(), rect2.height());
298 assert_eq!(rect1.center(), rect2.center());
299 }
300
301 #[test]
302 fn test_geometric_calculations() {
303 let rect = Rectangle::from_position_and_size(2.0, 3.0, 8.0, 6.0);
304
305 assert_eq!(rect.lower_left.x, 2.0);
307 assert_eq!(rect.lower_left.y, 3.0);
308 assert_eq!(rect.upper_right.x, 10.0);
309 assert_eq!(rect.upper_right.y, 9.0);
310 assert_eq!(rect.width(), 8.0);
311 assert_eq!(rect.height(), 6.0);
312
313 let center = rect.center();
314 assert_eq!(center.x, 6.0); assert_eq!(center.y, 6.0); }
317
318 #[test]
319 fn test_floating_point_precision() {
320 let p1 = Point::new(1.0 / 3.0, 2.0 / 3.0);
322 let p2 = Point::new(4.0 / 3.0, 5.0 / 3.0);
323 let rect = Rectangle::new(p1, p2);
324
325 let width = rect.width();
326 let height = rect.height();
327 let center = rect.center();
328
329 assert!((width - 1.0).abs() < f64::EPSILON);
331 assert!((height - 1.0).abs() < f64::EPSILON);
332
333 let expected_center_x = 5.0 / 6.0;
335 let expected_center_y = 7.0 / 6.0;
336 assert!((center.x - expected_center_x).abs() < f64::EPSILON);
337 assert!((center.y - expected_center_y).abs() < f64::EPSILON);
338 }
339
340 #[test]
341 fn test_point_with_mathematical_constants() {
342 use std::f64::consts::*;
343 let p = Point::new(PI, E);
344 assert_eq!(p.x, PI);
345 assert_eq!(p.y, E);
346
347 let origin = Point::origin();
348 assert_ne!(p, origin);
349 }
350
351 #[test]
352 fn test_rectangle_area_and_perimeter_concepts() {
353 let rect = Rectangle::from_position_and_size(0.0, 0.0, 4.0, 3.0);
355
356 let width = rect.width();
357 let height = rect.height();
358
359 let calculated_area = width * height;
361 let calculated_perimeter = 2.0 * (width + height);
362
363 assert_eq!(calculated_area, 12.0);
364 assert_eq!(calculated_perimeter, 14.0);
365 }
366
367 #[test]
368 fn test_point_distance_concepts() {
369 let p1 = Point::new(0.0, 0.0);
371 let p2 = Point::new(3.0, 4.0);
372
373 let dx = p2.x - p1.x;
374 let dy = p2.y - p1.y;
375 let distance_squared = dx * dx + dy * dy;
376 let distance = distance_squared.sqrt();
377
378 assert_eq!(dx, 3.0);
379 assert_eq!(dy, 4.0);
380 assert_eq!(distance_squared, 25.0);
381 assert_eq!(distance, 5.0);
382 }
383
384 #[test]
385 fn test_rectangle_contains_concepts() {
386 let rect = Rectangle::from_position_and_size(10.0, 20.0, 30.0, 40.0);
388 let test_point = Point::new(25.0, 35.0);
389
390 let within_x = test_point.x >= rect.lower_left.x && test_point.x <= rect.upper_right.x;
392 let within_y = test_point.y >= rect.lower_left.y && test_point.y <= rect.upper_right.y;
393 let would_contain = within_x && within_y;
394
395 assert!(within_x);
396 assert!(within_y);
397 assert!(would_contain);
398
399 let outside_point = Point::new(5.0, 35.0);
401 let outside_x =
402 outside_point.x >= rect.lower_left.x && outside_point.x <= rect.upper_right.x;
403 assert!(!outside_x);
404 }
405
406 #[test]
407 fn test_rectangle_intersection_concepts() {
408 let rect1 = Rectangle::from_position_and_size(0.0, 0.0, 10.0, 10.0);
409 let rect2 = Rectangle::from_position_and_size(5.0, 5.0, 10.0, 10.0);
410
411 let left = rect1.lower_left.x.max(rect2.lower_left.x);
413 let bottom = rect1.lower_left.y.max(rect2.lower_left.y);
414 let right = rect1.upper_right.x.min(rect2.upper_right.x);
415 let top = rect1.upper_right.y.min(rect2.upper_right.y);
416
417 let intersects = left < right && bottom < top;
418
419 assert_eq!(left, 5.0);
420 assert_eq!(bottom, 5.0);
421 assert_eq!(right, 10.0);
422 assert_eq!(top, 10.0);
423 assert!(intersects);
424
425 let rect3 = Rectangle::from_position_and_size(20.0, 20.0, 5.0, 5.0);
427 let left3 = rect1.lower_left.x.max(rect3.lower_left.x);
428 let right3 = rect1.upper_right.x.min(rect3.upper_right.x);
429 let no_intersection = left3 >= right3;
430 assert!(no_intersection);
431 }
432}