rust/integral-geometry/src/lib.rs
changeset 14137 3119d665d3c6
parent 14135 7f5a591e1c43
child 14139 37c99587825d
equal deleted inserted replaced
14135:7f5a591e1c43 14137:3119d665d3c6
    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: &RectInclusive) -> Point {
    76     pub fn clamp(self, rect: &Rect) -> 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     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 }