258 bin_assign_op_impl!(MulAssign, mul_assign); |
258 bin_assign_op_impl!(MulAssign, mul_assign); |
259 bin_assign_op_impl!(DivAssign, div_assign); |
259 bin_assign_op_impl!(DivAssign, div_assign); |
260 |
260 |
261 #[derive(PartialEq, Eq, Clone, Copy, Debug)] |
261 #[derive(PartialEq, Eq, Clone, Copy, Debug)] |
262 pub struct Rect { |
262 pub struct Rect { |
263 x: i32, |
263 top_left: Point, |
264 y: i32, |
264 bottom_right: Point, |
265 width: u32, |
|
266 height: u32 |
|
267 } |
265 } |
268 |
266 |
269 impl Rect { |
267 impl Rect { |
270 #[inline] |
268 #[inline] |
271 pub fn new(x: i32, y: i32, width: u32, height: u32) -> Self { |
269 pub fn new(top_left: Point, bottom_right: Point) -> Self { |
272 Self { x, y, width, height } |
270 assert!(top_left.x <= bottom_right.x + 1); |
|
271 assert!(top_left.y <= bottom_right.y + 1); |
|
272 Self { top_left, bottom_right } |
|
273 } |
|
274 |
|
275 pub fn from_box(left: i32, right: i32, top: i32, bottom: i32) -> Self { |
|
276 Self::new(Point::new(left, top), Point::new(right, bottom)) |
273 } |
277 } |
274 |
278 |
275 pub fn from_size(top_left: Point, size: Size) -> Self { |
279 pub fn from_size(top_left: Point, size: Size) -> Self { |
276 Rect::new( |
280 Self::new( |
277 top_left.x, |
281 top_left, |
278 top_left.y, |
282 top_left + Point::new(size.width as i32 - 1, size.height as i32 - 1) |
279 size.width as u32, |
|
280 size.height as u32, |
|
281 ) |
283 ) |
282 } |
284 } |
283 |
285 |
|
286 pub fn from_size_coords(x: i32, y: i32, width: usize, height: usize) -> Self { |
|
287 Self::from_size(Point::new(x, y), Size::new(width, height)) |
|
288 } |
|
289 |
284 pub fn at_origin(size: Size) -> Self { |
290 pub fn at_origin(size: Size) -> Self { |
285 Rect::from_size(Point::zero(), size) |
291 Self::from_size(Point::zero(), size) |
286 } |
292 } |
287 |
293 |
288 #[inline] |
294 #[inline] |
289 pub fn width(&self) -> usize { |
295 pub fn width(&self) -> usize { |
290 self.width as usize |
296 (self.right() - self.left() + 1) as usize |
291 } |
297 } |
292 |
298 |
293 #[inline] |
299 #[inline] |
294 pub fn height(&self) -> usize { |
300 pub fn height(&self) -> usize { |
295 self.height as usize |
301 (self.right() - self.left() + 1) as usize |
296 } |
302 } |
297 |
303 |
298 #[inline] |
304 #[inline] |
299 pub fn size(&self) -> Size { |
305 pub fn size(&self) -> Size { |
300 Size::new(self.width(), self.height()) |
306 Size::new(self.width(), self.height()) |
305 self.size().area() |
311 self.size().area() |
306 } |
312 } |
307 |
313 |
308 #[inline] |
314 #[inline] |
309 pub fn left(&self) -> i32 { |
315 pub fn left(&self) -> i32 { |
310 self.x |
316 self.top_left().x |
311 } |
317 } |
312 |
318 |
313 #[inline] |
319 #[inline] |
314 pub fn top(&self) -> i32 { |
320 pub fn top(&self) -> i32 { |
315 self.y |
321 self.top_left().y |
316 } |
322 } |
317 |
323 |
318 #[inline] |
324 #[inline] |
319 pub fn right(&self) -> i32 { |
325 pub fn right(&self) -> i32 { |
320 self.x + self.width as i32 - 1 |
326 self.bottom_right().x |
321 } |
327 } |
322 |
328 |
323 #[inline] |
329 #[inline] |
324 pub fn bottom(&self) -> i32 { |
330 pub fn bottom(&self) -> i32 { |
325 self.y + self.height as i32 - 1 |
331 self.bottom_right().y |
326 } |
332 } |
327 |
333 |
328 #[inline] |
334 #[inline] |
329 pub fn top_left(&self) -> Point { |
335 pub fn top_left(&self) -> Point { |
330 Point::new(self.x, self.y) |
336 self.top_left |
331 } |
337 } |
332 |
338 |
333 #[inline] |
339 #[inline] |
334 pub fn bottom_right(&self) -> Point { |
340 pub fn bottom_right(&self) -> Point { |
335 Point::new(self.right(), self.bottom()) |
341 self.bottom_right |
336 } |
342 } |
337 |
343 |
338 #[inline] |
344 #[inline] |
339 pub fn center(&self) -> Point { |
345 pub fn center(&self) -> Point { |
340 (self.top_left() + self.bottom_right()) / 2 |
346 (self.top_left() + self.bottom_right()) / 2 |
341 } |
347 } |
342 |
348 |
343 #[inline] |
349 #[inline] |
344 pub fn x_range(&self) -> Range<i32> { |
350 pub fn with_margin(&self, margin: i32) -> Self { |
345 self.x..self.x + self.width as i32 |
351 let offset = Point::diag(margin); |
346 } |
352 Self::new( |
347 |
353 self.top_left() + offset, |
348 #[inline] |
354 self.bottom_right() - offset |
349 pub fn y_range(&self) -> Range<i32> { |
355 ) |
350 self.y..self.y + self.height as i32 |
356 } |
|
357 |
|
358 #[inline] |
|
359 pub fn x_range(&self) -> RangeInclusive<i32> { |
|
360 self.left()..=self.right() |
|
361 } |
|
362 |
|
363 #[inline] |
|
364 pub fn y_range(&self) -> RangeInclusive<i32> { |
|
365 self.top()..=self.bottom() |
351 } |
366 } |
352 |
367 |
353 #[inline] |
368 #[inline] |
354 pub fn contains(&self, point: Point) -> bool { |
369 pub fn contains(&self, point: Point) -> bool { |
355 self.x_range().contains(point.x) && self.y_range().contains(point.y) |
370 self.x_range().contains(point.x) && self.y_range().contains(point.y) |
370 && self.top() <= other.bottom() |
385 && self.top() <= other.bottom() |
371 && self.bottom() >= other.top() |
386 && self.bottom() >= other.top() |
372 } |
387 } |
373 |
388 |
374 #[inline] |
389 #[inline] |
375 pub fn split_at(&self, point: Point) -> [RectInclusive; 4] { |
390 pub fn split_at(&self, point: Point) -> [Rect; 4] { |
376 RectInclusive::from(self.clone()).split_at(point) |
391 assert!(self.contains_inside(point)); |
377 } |
392 [ |
378 |
393 Self::from_box(self.left(), point.x, self.top(), point.y), |
379 #[inline] |
394 Self::from_box(point.x, self.right(), self.top(), point.y), |
380 pub fn quotient(self, x: u32, y: u32) -> Point { |
395 Self::from_box(point.x, self.right(), point.y, self.bottom()), |
|
396 Self::from_box(self.left(), point.x, point.y, self.bottom()), |
|
397 ] |
|
398 } |
|
399 |
|
400 #[inline] |
|
401 pub fn quotient(self, x: usize, y: usize) -> Point { |
381 self.top_left() + |
402 self.top_left() + |
382 Point::new( |
403 Point::new( |
383 (x % self.width) as i32, |
404 (x % self.width()) as i32, |
384 (y % self.height) as i32 |
405 (y % self.height()) as i32 |
385 ) |
406 ) |
386 } |
|
387 } |
|
388 |
|
389 #[derive(PartialEq, Eq, Clone, Copy, Debug)] |
|
390 pub struct RectInclusive { |
|
391 top_left: Point, |
|
392 bottom_right: Point, |
|
393 } |
|
394 |
|
395 impl RectInclusive { |
|
396 #[inline] |
|
397 pub fn new(top_left: Point, bottom_right: Point) -> Self { |
|
398 assert!(top_left.x <= bottom_right.x); |
|
399 assert!(top_left.y <= bottom_right.y); |
|
400 Self { top_left, bottom_right } |
|
401 } |
|
402 |
|
403 pub fn from_box(left: i32, right: i32, top: i32, bottom: i32) -> Self { |
|
404 RectInclusive::new(Point::new(left, top), Point::new(right, bottom)) |
|
405 } |
|
406 pub fn from_size(top_left: Point, size: Size) -> Self { |
|
407 RectInclusive::new( |
|
408 top_left, |
|
409 top_left + Point::new(size.width as i32 - 1, size.height as i32 - 1) |
|
410 ) |
|
411 } |
|
412 |
|
413 pub fn at_origin(size: Size) -> Self { |
|
414 RectInclusive::from_size(Point::zero(), size) |
|
415 } |
|
416 |
|
417 #[inline] |
|
418 pub fn width(&self) -> usize { |
|
419 (self.right() - self.left() + 1) as usize |
|
420 } |
|
421 |
|
422 #[inline] |
|
423 pub fn height(&self) -> usize { |
|
424 (self.right() - self.left() + 1) as usize |
|
425 } |
|
426 |
|
427 #[inline] |
|
428 pub fn size(&self) -> Size { |
|
429 Size::new(self.width(), self.height()) |
|
430 } |
|
431 |
|
432 #[inline] |
|
433 pub fn area(&self) -> usize { |
|
434 self.size().area() |
|
435 } |
|
436 |
|
437 #[inline] |
|
438 pub fn left(&self) -> i32 { |
|
439 self.top_left.x |
|
440 } |
|
441 |
|
442 #[inline] |
|
443 pub fn top(&self) -> i32 { |
|
444 self.top_left.y |
|
445 } |
|
446 |
|
447 #[inline] |
|
448 pub fn right(&self) -> i32 { |
|
449 self.bottom_right.x |
|
450 } |
|
451 |
|
452 #[inline] |
|
453 pub fn bottom(&self) -> i32 { |
|
454 self.bottom_right.y |
|
455 } |
|
456 |
|
457 #[inline] |
|
458 pub fn top_left(&self) -> Point { |
|
459 self.top_left |
|
460 } |
|
461 |
|
462 #[inline] |
|
463 pub fn bottom_right(&self) -> Point { |
|
464 self.bottom_right |
|
465 } |
|
466 |
|
467 #[inline] |
|
468 pub fn center(&self) -> Point { |
|
469 (self.top_left() + self.bottom_right()) / 2 |
|
470 } |
|
471 |
|
472 #[inline] |
|
473 pub fn with_margin(&self, margin: i32) -> Self { |
|
474 let offset = Point::diag(margin); |
|
475 RectInclusive::new( |
|
476 self.top_left() + offset, |
|
477 self.bottom_right() - offset |
|
478 ) |
|
479 } |
|
480 |
|
481 #[inline] |
|
482 pub fn x_range(&self) -> RangeInclusive<i32> { |
|
483 self.left()..=self.right() |
|
484 } |
|
485 |
|
486 #[inline] |
|
487 pub fn y_range(&self) -> RangeInclusive<i32> { |
|
488 self.top()..=self.bottom() |
|
489 } |
|
490 |
|
491 #[inline] |
|
492 pub fn contains(&self, point: Point) -> bool { |
|
493 self.x_range().contains(point.x) && self.y_range().contains(point.y) |
|
494 } |
|
495 |
|
496 #[inline] |
|
497 pub fn contains_inside(&self, point: Point) -> bool { |
|
498 point.x > self.left() |
|
499 && point.x < self.right() |
|
500 && point.y > self.top() |
|
501 && point.y < self.bottom() |
|
502 } |
|
503 |
|
504 #[inline] |
|
505 pub fn intersects(&self, other: &RectInclusive) -> bool { |
|
506 self.left() <= self.right() |
|
507 && self.right() >= other.left() |
|
508 && self.top() <= other.bottom() |
|
509 && self.bottom() >= other.top() |
|
510 } |
|
511 |
|
512 #[inline] |
|
513 pub fn split_at(&self, point: Point) -> [RectInclusive; 4] { |
|
514 assert!(self.contains_inside(point)); |
|
515 [ |
|
516 RectInclusive::from_box(self.left(), point.x, self.top(), point.y), |
|
517 RectInclusive::from_box(point.x, self.right(), self.top(), point.y), |
|
518 RectInclusive::from_box(point.x, self.right(), point.y, self.bottom()), |
|
519 RectInclusive::from_box(self.left(), point.x, point.y, self.bottom()), |
|
520 ] |
|
521 } |
|
522 } |
|
523 |
|
524 impl From<RectInclusive> for Rect { |
|
525 fn from(r: RectInclusive) -> Self { |
|
526 Self::from_size(r.top_left, r.size()) |
|
527 } |
|
528 } |
|
529 |
|
530 impl From<Rect> for RectInclusive { |
|
531 fn from(r: Rect) -> Self { |
|
532 Self::new(r.top_left(), r.bottom_right()) |
|
533 } |
407 } |
534 } |
408 } |
535 |
409 |
536 trait RangeContains<T> { |
410 trait RangeContains<T> { |
537 fn contains(&self, value: T) -> bool; |
411 fn contains(&self, value: T) -> bool; |
926 assert_eq!(l.center(), Point::new(3, 3)); |
800 assert_eq!(l.center(), Point::new(3, 3)); |
927 } |
801 } |
928 |
802 |
929 #[test] |
803 #[test] |
930 fn rect() { |
804 fn rect() { |
931 let r = RectInclusive::from_box(10, 100, 0, 70); |
805 let r = Rect::from_box(10, 100, 0, 70); |
932 |
806 |
933 assert!(r.contains_inside(Point::new(99, 69))); |
807 assert!(r.contains_inside(Point::new(99, 69))); |
934 assert!(!r.contains_inside(Point::new(100, 70))); |
808 assert!(!r.contains_inside(Point::new(100, 70))); |
935 |
809 |
936 assert_eq!(r.top_left(), Point::new(10, 0)); |
810 assert_eq!(r.top_left(), Point::new(10, 0)); |
937 assert_eq!(r.with_margin(12), RectInclusive::from_box(22, 88, 12, 58)); |
811 assert_eq!(r.with_margin(12), Rect::from_box(22, 88, 12, 58)); |
938 } |
812 } |
939 |
813 |
940 #[test] |
814 #[test] |
941 fn fit() { |
815 fn fit() { |
942 let r = RectInclusive::from_box(10, 100, 0, 70); |
816 let r = Rect::from_box(10, 100, 0, 70); |
943 |
817 |
944 assert_eq!(Point::new(0, -10).clamp(&r), Point::new(10, 0)); |
818 assert_eq!(Point::new(0, -10).clamp(&r), Point::new(10, 0)); |
945 assert_eq!(Point::new(1000, 1000).clamp(&r), Point::new(100, 70)); |
819 assert_eq!(Point::new(1000, 1000).clamp(&r), Point::new(100, 70)); |
946 } |
820 } |
947 } |
821 } |