summary refs log tree commit diff
path: root/src/geometry.rs
blob: 3d25b5dc30a7391b6c12237cb55217c610dc407a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use std::ops::Sub;


#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Side { Top, Bottom, Left, Right }

#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Corner { TopLeft, TopRight, BottomRight, BottomLeft }

impl Side {
  pub fn opposite(&self) -> Side {
    match self {
      Side::Top => Side::Bottom,
      Side::Right => Side::Left,
      Side::Bottom => Side::Top,
      Side::Left => Side::Right,
    }
  }

  pub fn corners_on_side(&self) -> &[Corner] {
    match self {
      Side::Top => &[ Corner::TopLeft, Corner::TopRight ],
      Side::Right => &[ Corner::TopRight, Corner::BottomRight ],
      Side::Bottom => &[ Corner::BottomRight, Corner::BottomLeft ],
      Side::Left => &[ Corner::BottomLeft, Corner::TopLeft ],
    }
  }
}

impl Corner {
  pub fn first_clockwise_side(&self) -> Side {
    match self {
      Corner::TopLeft => Side::Left,
      Corner::TopRight => Side::Top,
      Corner::BottomRight => Side::Right,
      Corner::BottomLeft => Side::Bottom,
    }
  }
}


pub trait Coordinate: Copy + From<u8> + Ord + Sub<Output=Self> { }
impl<T: Copy + From<u8> + Ord + Sub<Output=T>> Coordinate for T { }


#[derive(Debug)]
pub struct Point<T: Coordinate> {
  pub x: T,
  pub y: T,
}

#[derive(Debug)]
pub struct Rectangle<T: Coordinate> {
  pub left: T,
  pub top: T,
  pub width: T,
  pub height: T,
}

impl<T: Coordinate> Rectangle<T> {
  pub fn corner_point(&self, corner: Corner) -> Point<T> {
    match corner {
      Corner::TopLeft => Point { x: T::from(0), y: T::from(0) },
      Corner::TopRight => Point { x: self.width, y: T::from(0) },
      Corner::BottomRight => Point { x: self.width, y: self.height },
      Corner::BottomLeft => Point { x: T::from(0), y: self.height },
    }
  }

  pub fn inset_from_corner_point(&self, corner: Corner, distance: T)
    -> Point<T>
  {
    match corner {
      Corner::TopLeft => Point { x: distance, y: distance },
      Corner::TopRight => Point { x: self.width - distance, y: distance },
      Corner::BottomRight => Point {
        x: self.width - distance,
        y: self.height - distance
      },
      Corner::BottomLeft => Point { x: distance, y: self.height - distance },
    }
  }

  pub fn corner_square(&self, corner: Corner, size: T) -> Rectangle<T> {
    let corner_point = self.corner_point(corner);
    let inset_point = self.inset_from_corner_point(corner, size);

    let left = corner_point.x.min(inset_point.x);
    let top = corner_point.y.min(inset_point.y);
    let right = corner_point.x.max(inset_point.x);
    let bottom = corner_point.y.max(inset_point.y);

    Rectangle {
      left, top,
      width: right - left,
      height: bottom - top,
    }
  }
}