--- 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())
}
}