rust/integral-geometry/src/lib.rs
changeset 14131 c416d32764b7
parent 14126 32383b888309
child 14133 a65b60f36b96
--- a/rust/integral-geometry/src/lib.rs	Sun Nov 04 07:19:58 2018 +0300
+++ b/rust/integral-geometry/src/lib.rs	Mon Nov 05 19:53:26 2018 +0300
@@ -2,7 +2,7 @@
 
 use fpnum::distance;
 use std::cmp::max;
-use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, RangeInclusive, Sub, SubAssign};
+use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Range, RangeInclusive, Sub, SubAssign};
 
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
 pub struct Point {
@@ -17,6 +17,11 @@
     }
 
     #[inline]
+    pub fn diag(v: i32) -> Self {
+        Self::new(v, v)
+    }
+
+    #[inline]
     pub fn zero() -> Self {
         Self::new(0, 0)
     }
@@ -65,23 +70,31 @@
     }
 
     #[inline]
-    pub fn fit(self, rect: &Rect) -> Point {
-        let x = if self.x > rect.right() {
-            rect.right()
-        } else if self.x < rect.left() {
-            rect.left()
-        } else {
-            self.x
-        };
-        let y = if self.y > rect.bottom() {
-            rect.bottom()
-        } else if self.y < rect.top() {
-            rect.top()
-        } else {
-            self.y
-        };
+    pub fn clamp(self, rect: &Rect) -> Point {
+        Point::new(
+            rect.x_range().clamp(self.x),
+            rect.y_range().clamp(self.y)
+        )
+    }
+
+    #[inline]
+    pub fn line_to(self, end: Point) -> Line {
+        Line::new(self, end)
+    }
 
-        Point::new(x, y)
+    #[inline]
+    pub fn ray_to(self, end: Point) -> Ray {
+        self.line_to(end).to_ray()
+    }
+
+    #[inline]
+    pub fn tangent(self) -> i32 {
+        self.y / self.x
+    }
+
+    #[inline]
+    pub fn cotangent(self) -> i32 {
+        self.x / self.y
     }
 }
 
@@ -346,11 +359,10 @@
         self.y..=self.y + self.height as i32
     }
 
-    /* requires #[feature(range_contains)]
     #[inline]
     pub fn contains(&self, point: Point) -> bool {
-        x_range().contains(point.x) && y_range.contains(point.y)
-    }*/
+        self.x_range().contains(point.x) && self.y_range().contains(point.y)
+    }
 
     #[inline]
     pub fn contains_inside(&self, point: Point) -> bool {
@@ -378,6 +390,47 @@
             Rect::from_box(self.left(), point.x, point.y, self.bottom()),
         ]
     }
+
+    #[inline]
+    pub fn quotient(self, x: u32, y: u32) -> Point {
+        self.top_left() +
+            Point::new(
+                (x % self.width) as i32,
+                (y % self.height) as i32
+            )
+    }
+}
+
+trait RangeContains<T> {
+    fn contains(&self, value: T) -> bool;
+}
+
+impl <T: Ord> RangeContains<T> for Range<T> {
+    fn contains(&self, value: T) -> bool {
+        value >= self.start && value < self.end
+    }
+}
+
+impl <T: Ord> RangeContains<T> for RangeInclusive<T> {
+    fn contains(&self, value: T) -> bool {
+        value >= *self.start() && value <= *self.end()
+    }
+}
+
+trait RangeClamp<T> {
+    fn clamp(&self, value: T) -> T;
+}
+
+impl <T: Ord + Copy> RangeClamp<T> for RangeInclusive<T> {
+    fn clamp(&self, value: T) -> T {
+        if value < *self.start() {
+            *self.start()
+        } else if value > *self.end() {
+            *self.end()
+        } else {
+            value
+        }
+    }
 }
 
 pub struct Polygon {
@@ -435,6 +488,34 @@
 }
 
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct Ray {
+    pub start: Point,
+    pub direction: Point
+}
+
+impl Ray {
+    #[inline]
+    pub fn new(start: Point, direction: Point) -> Ray {
+        Self { start, direction }
+    }
+
+    #[inline]
+    pub fn tangent(&self) -> i32 {
+        self.direction.tangent()
+    }
+
+    #[inline]
+    pub fn cotangent(&self) -> i32 {
+        self.direction.cotangent()
+    }
+
+    #[inline]
+    pub fn orientation(&self, point: Point) -> i32 {
+        (point - self.start).cross(self.direction).signum()
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
 pub struct Line {
     pub start: Point,
     pub end: Point,
@@ -457,8 +538,18 @@
     }
 
     #[inline]
+    pub fn scaled_direction(&self) -> Point {
+        self.end - self.start
+    }
+
+    #[inline]
     pub fn scaled_normal(&self) -> Point {
-        (self.end - self.start).rotate90()
+        self.scaled_direction().rotate90()
+    }
+
+    #[inline]
+    pub fn to_ray(&self) -> Ray {
+        Ray::new(self.start, self.scaled_direction())
     }
 }