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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! Support function for 2D geometry
//! 

/// Position on the map
#[derive(Default, PartialEq, Copy, Clone, Debug, Eq, Hash)]
pub struct Point {
    pub x: usize,
    pub y: usize
}

impl Point {
    /// Create new point
    pub fn new(x: usize, y: usize) -> Point {
        Point {x, y}
    }

    /// Create new point from i32 coords
    pub fn new_i32(x: i32, y: i32) -> Point {
        Point::new(x as usize, y as usize)
    }

    /// Euclidean distance to a given point
    pub fn distance_to(self, point: &Point) -> f32 {
        let a = (self.x as f32 - point.x as f32).powf(2.0);
        let b = (self.y as f32 - point.y as f32).powf(2.0);
        (a + b).sqrt()
    }
}

/// Rectangle region on the map
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct Rect {
    pub x1 : usize,
    pub x2 : usize,
    pub y1 : usize,
    pub y2 : usize
}

impl Rect {
    pub fn new(x: usize, y: usize, width: usize, height: usize) -> Rect {
        Rect{x1:x, y1:y, x2:x+width, y2:y+height}
    }

    pub fn new_i32(x:i32, y: i32, width:i32, height:i32) -> Rect {
        Rect::new(x as usize, y as usize, width as usize, height as usize)
    }

    /// Returns true if this overlaps with other
    pub fn intersect(&self, other:&Rect) -> bool {
        self.x1 <= other.x2 && self.x2 >= other.x1 && self.y1 <= other.y2 && self.y2 >= other.y1
    }

    pub fn center(&self) -> Point {
        Point::new((self.x1 + self.x2)/2, (self.y1 + self.y2)/2)
    }

    pub fn width(&self) -> usize {
        if self.x2 >= self.x1 {
            self.x2 - self.x1
        } else {
            self.x1 - self.x2
        }
    }

    pub fn height(&self) -> usize {
        if self.y2 >= self.y1 {
            self.y2 - self.y1
        } else {
            self.y1 - self.y2
        }
    }
}

/// Calculate abs value between 2 usize values
/// Example:
/// ```
/// use mapgen::geometry::usize_abs;
/// 
/// assert_eq!(usize_abs(5, 3), 2);
/// assert_eq!(usize_abs(3, 5), 2);
/// ```
pub fn usize_abs(x: usize, y: usize) -> usize {
    if x >= y {x - y} else {y - x}
}

/// ------------------------------------------------------------------------------------------------
/// Module unit tests
/// ------------------------------------------------------------------------------------------------
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_distance() {
        let p1 = Point::new(10, 10);
        let p2 = Point::new(14, 7);
        let distance = p1.distance_to(&p2);
        assert_eq!(distance, 5.0);
    }

    #[test]
    fn test_intersect() {
        let rect1 = Rect::new(10, 10, 40, 40);
        let rect2 = Rect::new(30, 30, 60, 60);
        assert!(rect1.intersect(&rect2));
    }

    #[test]
    fn test_size() {
        let rect1 = Rect::new(10, 10, 40, 30);
        assert_eq!(rect1.width(), 40);
        assert_eq!(rect1.height(), 30);
    }

}