WIP: Wall intersection
[kaka/rust-sdl-test.git] / src / common / geometry.rs
index 02f93b1..455e600 100644 (file)
@@ -1,5 +1,7 @@
 use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Neg};
 
+////////// POINT ///////////////////////////////////////////////////////////////
+
 #[macro_export]
 macro_rules! point {
     ( $x:expr, $y:expr ) => {
@@ -181,45 +183,66 @@ impl Radians {
     }
 }
 
+////////// INTERSECTION ////////////////////////////////////////////////////////
+
+#[derive(Debug)]
+pub enum Intersection {
+    Point(Point<f64>),
+    //Line(Point<f64>, Point<f64>), // TODO: overlapping collinear
+    None,
+}
+
+impl Intersection {
+    pub fn lines(p1: Point<f64>, p2: Point<f64>, p3: Point<f64>, p4: Point<f64>) -> Intersection {
+       let s1 = p2 - p1;
+       let s2 = p4 - p3;
+
+       let denomimator = -s2.x * s1.y + s1.x * s2.y;
+       if denomimator != 0.0 {
+           let s = (-s1.y * (p1.x - p3.x) + s1.x * (p1.y - p3.y)) / denomimator;
+           let t = ( s2.x * (p1.y - p3.y) - s2.y * (p1.x - p3.x)) / denomimator;
+
+           if s >= 0.0 && s <= 1.0 && t >= 0.0 && t <= 1.0 {
+               return Intersection::Point(p1 + (s1 * t))
+           }
+       }
+
+       Intersection::None
+    }
+}
+
+////////// DIMENSION ///////////////////////////////////////////////////////////
+
 #[macro_export]
-macro_rules! rect {
-    ( $x:expr, $y:expr ) => {
-        Rect { x: $x, y: $y }
+macro_rules! dimen {
+    ( $w:expr, $h:expr ) => {
+        Dimension { width: $w, height: $h }
     };
 }
 
-#[derive(Default)]
-pub struct Rect<T> {
+#[derive(Debug, Default)]
+pub struct Dimension<T> {
     pub width: T,
     pub height: T,
 }
 
-impl<T: Mul<Output = T> + Copy> Rect<T> {
+impl<T: Mul<Output = T> + Copy> Dimension<T> {
     #[allow(dead_code)]
     pub fn area(&self) -> T {
         self.width * self.height
     }
 }
 
-impl<T> From<(T, T)> for Rect<T> {
+impl<T> From<(T, T)> for Dimension<T> {
     fn from(item: (T, T)) -> Self {
-        Rect {
+        Dimension {
             width: item.0,
             height: item.1,
         }
     }
 }
 
-#[macro_export]
-macro_rules! hashmap {
-    ($($k:expr => $v:expr),*) => {
-       {
-           let mut map = std::collections::HashMap::new();
-           $(map.insert($k, $v);)*
-           map
-       }
-    }
-}
+////////// TESTS ///////////////////////////////////////////////////////////////
 
 #[cfg(test)]
 mod tests {
@@ -291,9 +314,23 @@ mod tests {
     }
 
     #[test]
-    fn area_for_rect_of_multipliable_type() {
-        let r: Rect<_> = (30, 20).into(); // the Into trait uses the From trait
+    fn area_for_dimension_of_multipliable_type() {
+        let r: Dimension<_> = (30, 20).into(); // the Into trait uses the From trait
         assert_eq!(r.area(), 30 * 20);
-        // let a = Rect::from(("a".to_string(), "b".to_string())).area(); // this doesn't work, because area() is not implemented for String
+        // let a = Dimension::from(("a".to_string(), "b".to_string())).area(); // this doesn't work, because area() is not implemented for String
+    }
+
+    #[test]
+    fn intersection_of_lines() {
+        let p1 = point!(0.0, 0.0);
+        let p2 = point!(2.0, 2.0);
+        let p3 = point!(0.0, 2.0);
+        let p4 = point!(2.0, 0.0);
+       let r = Intersection::lines(p1, p2, p3, p4);
+       if let Intersection::Point(p) = r {
+            assert_eq!(p, point!(1.0, 1.0));
+       } else {
+           panic!();
+       }
     }
 }