diff -r 703242ade2c1 -r c416d32764b7 rust/integral-geometry/src/lib.rs --- 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 { + fn contains(&self, value: T) -> bool; +} + +impl RangeContains for Range { + fn contains(&self, value: T) -> bool { + value >= self.start && value < self.end + } +} + +impl RangeContains for RangeInclusive { + fn contains(&self, value: T) -> bool { + value >= *self.start() && value <= *self.end() + } +} + +trait RangeClamp { + fn clamp(&self, value: T) -> T; +} + +impl RangeClamp for RangeInclusive { + 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()) } }