--- a/rust/integral-geometry/src/lib.rs Mon Nov 05 21:21:53 2018 +0300
+++ b/rust/integral-geometry/src/lib.rs Mon Nov 05 22:43:58 2018 +0300
@@ -73,7 +73,7 @@
}
#[inline]
- pub fn clamp(self, rect: &Rect) -> Point {
+ pub fn clamp(self, rect: &RectInclusive) -> Point {
Point::new(
rect.x_range().clamp(self.x),
rect.y_range().clamp(self.y)
@@ -260,28 +260,16 @@
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct Rect {
- pub x: i32,
- pub y: i32,
- pub width: u32,
- pub height: u32,
+ x: i32,
+ y: i32,
+ width: u32,
+ height: u32
}
impl Rect {
#[inline]
pub fn new(x: i32, y: i32, width: u32, height: u32) -> Self {
- Self {
- x,
- y,
- width,
- height,
- }
- }
-
- pub fn from_box(left: i32, right: i32, top: i32, bottom: i32) -> Self {
- assert!(left <= right);
- assert!(top <= bottom);
-
- Rect::new(left, top, (right - left) as u32, (bottom - top) as u32)
+ Self { x, y, width, height }
}
pub fn from_size(top_left: Point, size: Size) -> Self {
@@ -298,8 +286,18 @@
}
#[inline]
+ pub fn width(&self) -> usize {
+ self.width as usize
+ }
+
+ #[inline]
+ pub fn height(&self) -> usize {
+ self.height as usize
+ }
+
+ #[inline]
pub fn size(&self) -> Size {
- Size::new(self.width as usize, self.height as usize)
+ Size::new(self.width(), self.height())
}
#[inline]
@@ -319,12 +317,12 @@
#[inline]
pub fn right(&self) -> i32 {
- self.x + self.width as i32
+ self.x + self.width as i32 - 1
}
#[inline]
pub fn bottom(&self) -> i32 {
- self.y + self.height as i32
+ self.y + self.height as i32 - 1
}
#[inline]
@@ -343,23 +341,13 @@
}
#[inline]
- pub fn with_margin(&self, margin: i32) -> Self {
- Rect::from_box(
- self.left() + margin,
- self.right() - margin,
- self.top() + margin,
- self.bottom() - margin,
- )
+ pub fn x_range(&self) -> Range<i32> {
+ self.x..self.x + self.width as i32
}
#[inline]
- pub fn x_range(&self) -> RangeInclusive<i32> {
- self.x..=self.x + self.width as i32
- }
-
- #[inline]
- pub fn y_range(&self) -> RangeInclusive<i32> {
- self.y..=self.y + self.height as i32
+ pub fn y_range(&self) -> Range<i32> {
+ self.y..self.y + self.height as i32
}
#[inline]
@@ -384,14 +372,8 @@
}
#[inline]
- pub fn split_at(&self, point: Point) -> [Rect; 4] {
- assert!(self.contains_inside(point));
- [
- Rect::from_box(self.left(), point.x, self.top(), point.y),
- Rect::from_box(point.x, self.right(), self.top(), point.y),
- Rect::from_box(point.x, self.right(), point.y, self.bottom()),
- Rect::from_box(self.left(), point.x, point.y, self.bottom()),
- ]
+ pub fn split_at(&self, point: Point) -> [RectInclusive; 4] {
+ RectInclusive::from(self.clone()).split_at(point)
}
#[inline]
@@ -404,6 +386,153 @@
}
}
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct RectInclusive {
+ top_left: Point,
+ bottom_right: Point,
+}
+
+impl RectInclusive {
+ #[inline]
+ pub fn new(top_left: Point, bottom_right: Point) -> Self {
+ assert!(top_left.x <= bottom_right.x);
+ assert!(top_left.y <= bottom_right.y);
+ Self { top_left, bottom_right }
+ }
+
+ pub fn from_box(left: i32, right: i32, top: i32, bottom: i32) -> Self {
+ RectInclusive::new(Point::new(left, top), Point::new(right, bottom))
+ }
+ pub fn from_size(top_left: Point, size: Size) -> Self {
+ RectInclusive::new(
+ top_left,
+ top_left + Point::new(size.width as i32 - 1, size.height as i32 - 1)
+ )
+ }
+
+ pub fn at_origin(size: Size) -> Self {
+ RectInclusive::from_size(Point::zero(), size)
+ }
+
+ #[inline]
+ pub fn width(&self) -> usize {
+ (self.right() - self.left() + 1) as usize
+ }
+
+ #[inline]
+ pub fn height(&self) -> usize {
+ (self.right() - self.left() + 1) as usize
+ }
+
+ #[inline]
+ pub fn size(&self) -> Size {
+ Size::new(self.width(), self.height())
+ }
+
+ #[inline]
+ pub fn area(&self) -> usize {
+ self.size().area()
+ }
+
+ #[inline]
+ pub fn left(&self) -> i32 {
+ self.top_left.x
+ }
+
+ #[inline]
+ pub fn top(&self) -> i32 {
+ self.top_left.y
+ }
+
+ #[inline]
+ pub fn right(&self) -> i32 {
+ self.bottom_right.x
+ }
+
+ #[inline]
+ pub fn bottom(&self) -> i32 {
+ self.bottom_right.y
+ }
+
+ #[inline]
+ pub fn top_left(&self) -> Point {
+ self.top_left
+ }
+
+ #[inline]
+ pub fn bottom_right(&self) -> Point {
+ self.bottom_right
+ }
+
+ #[inline]
+ pub fn center(&self) -> Point {
+ (self.top_left() + self.bottom_right()) / 2
+ }
+
+ #[inline]
+ pub fn with_margin(&self, margin: i32) -> Self {
+ let offset = Point::diag(margin);
+ RectInclusive::new(
+ self.top_left() + offset,
+ self.bottom_right() - offset
+ )
+ }
+
+ #[inline]
+ pub fn x_range(&self) -> RangeInclusive<i32> {
+ self.left()..=self.right()
+ }
+
+ #[inline]
+ pub fn y_range(&self) -> RangeInclusive<i32> {
+ self.top()..=self.bottom()
+ }
+
+ #[inline]
+ pub fn contains(&self, point: Point) -> bool {
+ self.x_range().contains(point.x) && self.y_range().contains(point.y)
+ }
+
+ #[inline]
+ pub fn contains_inside(&self, point: Point) -> bool {
+ point.x > self.left()
+ && point.x < self.right()
+ && point.y > self.top()
+ && point.y < self.bottom()
+ }
+
+ #[inline]
+ pub fn intersects(&self, other: &RectInclusive) -> bool {
+ self.left() <= self.right()
+ && self.right() >= other.left()
+ && self.top() <= other.bottom()
+ && self.bottom() >= other.top()
+ }
+
+ #[inline]
+ pub fn split_at(&self, point: Point) -> [RectInclusive; 4] {
+ assert!(self.contains_inside(point));
+ [
+ RectInclusive::from_box(self.left(), point.x, self.top(), point.y),
+ RectInclusive::from_box(point.x, self.right(), self.top(), point.y),
+ RectInclusive::from_box(point.x, self.right(), point.y, self.bottom()),
+ RectInclusive::from_box(self.left(), point.x, point.y, self.bottom()),
+ ]
+ }
+}
+
+impl From<RectInclusive> for Rect {
+ fn from(r: RectInclusive) -> Self {
+ Self::from_size(r.top_left, r.size())
+ }
+}
+
+impl From<Rect> for RectInclusive {
+ fn from(r: Rect) -> Self {
+ Self::new(r.top_left(), r.bottom_right())
+ }
+}
+
trait RangeContains<T> {
fn contains(&self, value: T) -> bool;
}
@@ -799,20 +928,20 @@
#[test]
fn rect() {
- let r = Rect::from_box(10, 100, 0, 70);
+ let r = RectInclusive::from_box(10, 100, 0, 70);
assert!(r.contains_inside(Point::new(99, 69)));
assert!(!r.contains_inside(Point::new(100, 70)));
assert_eq!(r.top_left(), Point::new(10, 0));
- assert_eq!(r.with_margin(12), Rect::from_box(22, 88, 12, 58));
+ assert_eq!(r.with_margin(12), RectInclusive::from_box(22, 88, 12, 58));
}
#[test]
fn fit() {
- let r = Rect::from_box(10, 100, 0, 70);
+ let r = RectInclusive::from_box(10, 100, 0, 70);
- assert_eq!(Point::new(0, -10).fit(&r), Point::new(10, 0));
- assert_eq!(Point::new(1000, 1000).fit(&r), Point::new(100, 70));
+ assert_eq!(Point::new(0, -10).clamp(&r), Point::new(10, 0));
+ assert_eq!(Point::new(1000, 1000).clamp(&r), Point::new(100, 70));
}
}
--- a/rust/land2d/src/lib.rs Mon Nov 05 21:21:53 2018 +0300
+++ b/rust/land2d/src/lib.rs Mon Nov 05 22:43:58 2018 +0300
@@ -3,12 +3,11 @@
use std::cmp;
-use integral_geometry::{ArcPoints, EquidistantPoints, Line, Point, Rect, Size, SizeMask};
+use integral_geometry::{ArcPoints, EquidistantPoints, Line, Point, RectInclusive, Size, SizeMask};
pub struct Land2D<T> {
pixels: vec2d::Vec2D<T>,
- play_size: Size,
- play_box: Rect,
+ play_box: RectInclusive,
mask: SizeMask,
}
@@ -20,9 +19,8 @@
((real_size.width - play_size.width) / 2) as i32,
(real_size.height - play_size.height) as i32,
);
- let play_box = Rect::from_size(top_left, play_size);
+ let play_box = RectInclusive::from_size(top_left, play_size);
Self {
- play_size,
play_box,
pixels: vec2d::Vec2D::new(real_size, fill_value),
mask: real_size.to_mask(),
@@ -50,21 +48,21 @@
#[inline]
pub fn play_width(&self) -> usize {
- self.play_size.width
+ self.play_box.width()
}
#[inline]
pub fn play_height(&self) -> usize {
- self.play_size.height
+ self.play_box.height()
}
#[inline]
pub fn play_size(&self) -> Size {
- self.play_size
+ self.play_box.size()
}
#[inline]
- pub fn play_box(&self) -> Rect {
+ pub fn play_box(&self) -> RectInclusive {
self.play_box
}
--- a/rust/landgen/src/outline.rs Mon Nov 05 21:21:53 2018 +0300
+++ b/rust/landgen/src/outline.rs Mon Nov 05 22:43:58 2018 +0300
@@ -1,7 +1,7 @@
use itertools::Itertools;
use std::cmp::min;
-use integral_geometry::{Line, Ray, Point, Polygon, Rect, Size};
+use integral_geometry::{Line, Ray, Point, Polygon, Rect, RectInclusive, Size};
use land2d::Land2D;
use outline_template::OutlineTemplate;
@@ -10,14 +10,14 @@
pub islands: Vec<Polygon>,
pub fill_points: Vec<Point>,
pub size: Size,
- pub play_box: Rect,
- intersections_box: Rect,
+ pub play_box: RectInclusive,
+ intersections_box: RectInclusive,
}
impl OutlinePoints {
pub fn from_outline_template<I: Iterator<Item = u32>>(
outline_template: &OutlineTemplate,
- play_box: Rect,
+ play_box: RectInclusive,
size: Size,
random_numbers: &mut I,
) -> Self {
@@ -38,7 +38,7 @@
})
.collect(),
fill_points: outline_template.fill_points.clone(),
- intersections_box: Rect::at_origin(size)
+ intersections_box: RectInclusive::at_origin(size)
.with_margin(size.to_square().width as i32 * -2),
}
}
@@ -73,7 +73,11 @@
}
#[inline]
- fn solve_intersection(intersections_box: &Rect, ray: &Ray, edge: &Line) -> Option<(i32, u32)>
+ fn solve_intersection(
+ intersections_box: &RectInclusive,
+ ray: &Ray,
+ edge: &Line
+ ) -> Option<(i32, u32)>
{
let edge_dir = edge.scaled_direction();
let aqpb = ray.direction.cross(edge_dir) as i64;
@@ -302,15 +306,16 @@
#[test()]
fn points_test() {
+ let size = Size::square(100);
let mut points = OutlinePoints {
islands: vec![
Polygon::new(&[Point::new(0, 0), Point::new(20, 0), Point::new(30, 30)]),
Polygon::new(&[Point::new(10, 15), Point::new(15, 20), Point::new(20, 15)]),
],
fill_points: vec![Point::new(1, 1)],
- play_box: Rect::from_box(0, 100, 0, 100).with_margin(10),
+ play_box: RectInclusive::at_origin(size).with_margin(10),
size: Size::square(100),
- intersections_box: Rect::from_box(0, 0, 100, 100),
+ intersections_box: RectInclusive::at_origin(size),
};
let segments: Vec<Line> = points.segments_iter().collect();