rust/integral-geometry/src/lib.rs
changeset 14135 7f5a591e1c43
parent 14134 09f62bb046ef
child 14137 3119d665d3c6
equal deleted inserted replaced
14134:09f62bb046ef 14135:7f5a591e1c43
    71     pub fn cross(self, other: Point) -> i32 {
    71     pub fn cross(self, other: Point) -> i32 {
    72         self.dot(other.rotate90())
    72         self.dot(other.rotate90())
    73     }
    73     }
    74 
    74 
    75     #[inline]
    75     #[inline]
    76     pub fn clamp(self, rect: &Rect) -> Point {
    76     pub fn clamp(self, rect: &RectInclusive) -> Point {
    77         Point::new(
    77         Point::new(
    78             rect.x_range().clamp(self.x),
    78             rect.x_range().clamp(self.x),
    79             rect.y_range().clamp(self.y)
    79             rect.y_range().clamp(self.y)
    80         )
    80         )
    81     }
    81     }
   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,
   296     pub fn at_origin(size: Size) -> Self {
   284     pub fn at_origin(size: Size) -> Self {
   297         Rect::from_size(Point::zero(), size)
   285         Rect::from_size(Point::zero(), size)
   298     }
   286     }
   299 
   287 
   300     #[inline]
   288     #[inline]
       
   289     pub fn width(&self) -> usize {
       
   290         self.width as usize
       
   291     }
       
   292 
       
   293     #[inline]
       
   294     pub fn height(&self) -> usize {
       
   295         self.height as usize
       
   296     }
       
   297 
       
   298     #[inline]
   301     pub fn size(&self) -> Size {
   299     pub fn size(&self) -> Size {
   302         Size::new(self.width as usize, self.height as usize)
   300         Size::new(self.width(), self.height())
   303     }
   301     }
   304 
   302 
   305     #[inline]
   303     #[inline]
   306     pub fn area(&self) -> usize {
   304     pub fn area(&self) -> usize {
   307         self.size().area()
   305         self.size().area()
   317         self.y
   315         self.y
   318     }
   316     }
   319 
   317 
   320     #[inline]
   318     #[inline]
   321     pub fn right(&self) -> i32 {
   319     pub fn right(&self) -> i32 {
   322         self.x + self.width as i32
   320         self.x + self.width as i32 - 1
   323     }
   321     }
   324 
   322 
   325     #[inline]
   323     #[inline]
   326     pub fn bottom(&self) -> i32 {
   324     pub fn bottom(&self) -> i32 {
   327         self.y + self.height as i32
   325         self.y + self.height as i32 - 1
   328     }
   326     }
   329 
   327 
   330     #[inline]
   328     #[inline]
   331     pub fn top_left(&self) -> Point {
   329     pub fn top_left(&self) -> Point {
   332         Point::new(self.x, self.y)
   330         Point::new(self.x, self.y)
   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 }