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 pub x: i32, |
263 x: i32, |
264 pub y: i32, |
264 y: i32, |
265 pub width: u32, |
265 width: u32, |
266 pub height: u32, |
266 height: u32 |
267 } |
267 } |
268 |
268 |
269 impl Rect { |
269 impl Rect { |
270 #[inline] |
270 #[inline] |
271 pub fn new(x: i32, y: i32, width: u32, height: u32) -> Self { |
271 pub fn new(x: i32, y: i32, width: u32, height: u32) -> Self { |
272 Self { |
272 Self { x, y, width, height } |
273 x, |
|
274 y, |
|
275 width, |
|
276 height, |
|
277 } |
|
278 } |
|
279 |
|
280 pub fn from_box(left: i32, right: i32, top: i32, bottom: i32) -> Self { |
|
281 assert!(left <= right); |
|
282 assert!(top <= bottom); |
|
283 |
|
284 Rect::new(left, top, (right - left) as u32, (bottom - top) as u32) |
|
285 } |
273 } |
286 |
274 |
287 pub fn from_size(top_left: Point, size: Size) -> Self { |
275 pub fn from_size(top_left: Point, size: Size) -> Self { |
288 Rect::new( |
276 Rect::new( |
289 top_left.x, |
277 top_left.x, |
341 pub fn center(&self) -> Point { |
339 pub fn center(&self) -> Point { |
342 (self.top_left() + self.bottom_right()) / 2 |
340 (self.top_left() + self.bottom_right()) / 2 |
343 } |
341 } |
344 |
342 |
345 #[inline] |
343 #[inline] |
346 pub fn with_margin(&self, margin: i32) -> Self { |
344 pub fn x_range(&self) -> Range<i32> { |
347 Rect::from_box( |
345 self.x..self.x + self.width as i32 |
348 self.left() + margin, |
346 } |
349 self.right() - margin, |
347 |
350 self.top() + margin, |
348 #[inline] |
351 self.bottom() - margin, |
349 pub fn y_range(&self) -> Range<i32> { |
352 ) |
350 self.y..self.y + self.height as i32 |
353 } |
|
354 |
|
355 #[inline] |
|
356 pub fn x_range(&self) -> RangeInclusive<i32> { |
|
357 self.x..=self.x + self.width as i32 |
|
358 } |
|
359 |
|
360 #[inline] |
|
361 pub fn y_range(&self) -> RangeInclusive<i32> { |
|
362 self.y..=self.y + self.height as i32 |
|
363 } |
351 } |
364 |
352 |
365 #[inline] |
353 #[inline] |
366 pub fn contains(&self, point: Point) -> bool { |
354 pub fn contains(&self, point: Point) -> bool { |
367 self.x_range().contains(point.x) && self.y_range().contains(point.y) |
355 self.x_range().contains(point.x) && self.y_range().contains(point.y) |
382 && self.top() <= other.bottom() |
370 && self.top() <= other.bottom() |
383 && self.bottom() >= other.top() |
371 && self.bottom() >= other.top() |
384 } |
372 } |
385 |
373 |
386 #[inline] |
374 #[inline] |
387 pub fn split_at(&self, point: Point) -> [Rect; 4] { |
375 pub fn split_at(&self, point: Point) -> [RectInclusive; 4] { |
388 assert!(self.contains_inside(point)); |
376 RectInclusive::from(self.clone()).split_at(point) |
389 [ |
|
390 Rect::from_box(self.left(), point.x, self.top(), point.y), |
|
391 Rect::from_box(point.x, self.right(), self.top(), point.y), |
|
392 Rect::from_box(point.x, self.right(), point.y, self.bottom()), |
|
393 Rect::from_box(self.left(), point.x, point.y, self.bottom()), |
|
394 ] |
|
395 } |
377 } |
396 |
378 |
397 #[inline] |
379 #[inline] |
398 pub fn quotient(self, x: u32, y: u32) -> Point { |
380 pub fn quotient(self, x: u32, y: u32) -> Point { |
399 self.top_left() + |
381 self.top_left() + |
400 Point::new( |
382 Point::new( |
401 (x % self.width) as i32, |
383 (x % self.width) as i32, |
402 (y % self.height) as i32 |
384 (y % self.height) as i32 |
403 ) |
385 ) |
|
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()) |
404 } |
533 } |
405 } |
534 } |
406 |
535 |
407 trait RangeContains<T> { |
536 trait RangeContains<T> { |
408 fn contains(&self, value: T) -> bool; |
537 fn contains(&self, value: T) -> bool; |
797 assert_eq!(l.center(), Point::new(3, 3)); |
926 assert_eq!(l.center(), Point::new(3, 3)); |
798 } |
927 } |
799 |
928 |
800 #[test] |
929 #[test] |
801 fn rect() { |
930 fn rect() { |
802 let r = Rect::from_box(10, 100, 0, 70); |
931 let r = RectInclusive::from_box(10, 100, 0, 70); |
803 |
932 |
804 assert!(r.contains_inside(Point::new(99, 69))); |
933 assert!(r.contains_inside(Point::new(99, 69))); |
805 assert!(!r.contains_inside(Point::new(100, 70))); |
934 assert!(!r.contains_inside(Point::new(100, 70))); |
806 |
935 |
807 assert_eq!(r.top_left(), Point::new(10, 0)); |
936 assert_eq!(r.top_left(), Point::new(10, 0)); |
808 assert_eq!(r.with_margin(12), Rect::from_box(22, 88, 12, 58)); |
937 assert_eq!(r.with_margin(12), RectInclusive::from_box(22, 88, 12, 58)); |
809 } |
938 } |
810 |
939 |
811 #[test] |
940 #[test] |
812 fn fit() { |
941 fn fit() { |
813 let r = Rect::from_box(10, 100, 0, 70); |
942 let r = RectInclusive::from_box(10, 100, 0, 70); |
814 |
943 |
815 assert_eq!(Point::new(0, -10).fit(&r), Point::new(10, 0)); |
944 assert_eq!(Point::new(0, -10).clamp(&r), Point::new(10, 0)); |
816 assert_eq!(Point::new(1000, 1000).fit(&r), Point::new(100, 70)); |
945 assert_eq!(Point::new(1000, 1000).clamp(&r), Point::new(100, 70)); |
817 } |
946 } |
818 } |
947 } |