# HG changeset patch # User unc0rr # Date 1541287227 -3600 # Node ID 376a0551b00a51893496aeabaf00b76e2d4fdc1d # Parent 6e0be42d0a8f63cc46631a1a7879b5a3747b4836 - Add distance-divider option to land_dump - Fix multiplication overflow errors (iy went widly out of bounds) diff -r 6e0be42d0a8f -r 376a0551b00a rust/integral-geometry/src/lib.rs --- a/rust/integral-geometry/src/lib.rs Sun Nov 04 00:25:27 2018 +0300 +++ b/rust/integral-geometry/src/lib.rs Sun Nov 04 00:20:27 2018 +0100 @@ -1,13 +1,8 @@ extern crate fpnum; use fpnum::distance; -use std::ops::{ - Add, AddAssign, - Div, DivAssign, - Mul, MulAssign, - Sub, SubAssign, - RangeInclusive -}; +use std::cmp::max; +use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, RangeInclusive, Sub, SubAssign}; #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub struct Point { @@ -68,6 +63,26 @@ pub fn cross(self, other: Point) -> i32 { self.dot(other.rotate90()) } + + #[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 + }; + + Point::new(x, y) + } } #[derive(PartialEq, Eq, Clone, Copy, Debug)] @@ -118,6 +133,11 @@ SizeMask::new(*self) } + #[inline] + pub fn to_square(&self) -> Size { + Size::square(max(self.width, self.height)) + } + pub fn to_grid_index(&self) -> GridIndex { GridIndex::new(*self) } @@ -355,13 +375,13 @@ 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()) + Rect::from_box(self.left(), point.x, point.y, self.bottom()), ] } } pub struct Polygon { - vertices: Vec + vertices: Vec, } impl Polygon { @@ -657,4 +677,12 @@ assert_eq!(r.top_left(), Point::new(10, 0)); assert_eq!(r.with_margin(12), Rect::from_box(22, 88, 12, 58)); } + + #[test] + fn fit() { + let r = Rect::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)); + } } diff -r 6e0be42d0a8f -r 376a0551b00a rust/land_dump/src/main.rs --- a/rust/land_dump/src/main.rs Sun Nov 04 00:25:27 2018 +0300 +++ b/rust/land_dump/src/main.rs Sun Nov 04 00:20:27 2018 +0100 @@ -27,6 +27,8 @@ dump_before_distort: bool, #[structopt(short = "b", long = "dump-before-bezierize")] dump_before_bezierize: bool, + #[structopt(short = "f", long = "distance-divisor", default_value = "100")] + distance_divisor: u32, } fn template() -> OutlineTemplate { @@ -44,11 +46,12 @@ fn dump( seed: &[u8], + distance_divisor: u32, skip_distort: bool, skip_bezier: bool, file_name: &Path, ) -> std::io::Result<()> { - let params = LandGenerationParameters::new(0 as u8, 255, 100, skip_distort, skip_bezier); + let params = LandGenerationParameters::new(0 as u8, 255, distance_divisor, skip_distort, skip_bezier); let landgen = TemplatedLandGenerator::new(template()); let mut prng = LaggedFibonacciPRNG::new(seed); let land = landgen.generate_land(¶ms, &mut prng); @@ -74,6 +77,7 @@ if opt.dump_before_distort { dump( opt.seed.as_str().as_bytes(), + opt.distance_divisor, true, true, Path::new("out.before_distort.png"), @@ -83,6 +87,7 @@ if opt.dump_before_bezierize { dump( opt.seed.as_str().as_bytes(), + opt.distance_divisor, false, true, Path::new("out.before_bezier.png"), @@ -91,6 +96,7 @@ } dump( opt.seed.as_str().as_bytes(), + opt.distance_divisor, false, true, Path::new("out.full.png"), diff -r 6e0be42d0a8f -r 376a0551b00a rust/landgen/src/outline.rs --- a/rust/landgen/src/outline.rs Sun Nov 04 00:25:27 2018 +0300 +++ b/rust/landgen/src/outline.rs Sun Nov 04 00:20:27 2018 +0100 @@ -1,9 +1,7 @@ use itertools::Itertools; use std::cmp::min; -use integral_geometry::{ - Line, Point, Rect, Size, Polygon -}; +use integral_geometry::{Line, Point, Polygon, Rect, Size}; use land2d::Land2D; use outline_template::OutlineTemplate; @@ -13,6 +11,7 @@ pub fill_points: Vec, pub size: Size, pub play_box: Rect, + intersections_box: Rect, } impl OutlinePoints { @@ -39,10 +38,13 @@ ) + play_box.top_left() }) - .collect::>().into() + .collect::>() + .into() }) .collect(), fill_points: outline_template.fill_points.clone(), + intersections_box: Rect::at_origin(size) + .with_margin(size.to_square().width as i32 * -2), } } @@ -79,15 +81,29 @@ } #[inline] - fn solve_intersection(p: &Point, m: &Point, s: &Point, e: &Point) -> Option<(i32, u32)> { + fn solve_intersection( + intersections_box: &Rect, + p: &Point, + m: &Point, + s: &Point, + e: &Point, + ) -> Option<(i32, u32)> { let f = *e - *s; let aqpb = p.cross(f) as i64; if aqpb != 0 { - let iy = ((((s.x - m.x) as i64 * p.y as i64 + m.y as i64 * p.x as i64) + let mut iy = ((((s.x - m.x) as i64 * p.y as i64 + m.y as i64 * p.x as i64) * f.y as i64 - s.y as i64 * f.x as i64 * p.y as i64) / aqpb) as i32; + + // is there better way to do it? + if iy < intersections_box.top() { + iy = intersections_box.top(); + } else if iy > intersections_box.bottom() { + iy = intersections_box.bottom(); + } + let ix = if p.y.abs() > f.y.abs() { (iy - m.y) * p.x / p.y + m.x } else { @@ -173,7 +189,13 @@ for s in self.segments_iter() { if s != segment { if intersect(&p, &mid_point, &s.start, &s.end) { - if let Some((t, d)) = solve_intersection(&p, &mid_point, &s.start, &s.end) { + if let Some((t, d)) = solve_intersection( + &self.intersections_box, + &p, + &mid_point, + &s.start, + &s.end, + ) { if t > 0 { dist_right = min(dist_right, d); } else { @@ -189,7 +211,13 @@ if *pi != segment.start && *pi != segment.end { if intersect(&p, &pi, &segment.start, &segment.end) { // ray from segment.start - if let Some((t, d)) = solve_intersection(&p, &mid_point, &segment.start, &pi) { + if let Some((t, d)) = solve_intersection( + &self.intersections_box, + &p, + &mid_point, + &segment.start, + &pi, + ) { if t > 0 { dist_right = min(dist_right, d); } else { @@ -198,7 +226,13 @@ } // ray from segment.end - if let Some((t, d)) = solve_intersection(&p, &mid_point, &segment.end, &pi) { + if let Some((t, d)) = solve_intersection( + &self.intersections_box, + &p, + &mid_point, + &segment.end, + &pi, + ) { if t > 0 { dist_right = min(dist_right, d); } else { @@ -239,7 +273,8 @@ let mut i = 0; while i < self.islands[is].edges_count() { let segment = self.islands[is].get_edge(i); - if let Some(new_point) = self.divide_edge(segment, distance_divisor, random_numbers) { + if let Some(new_point) = self.divide_edge(segment, distance_divisor, random_numbers) + { self.islands[is].split_edge(i, new_point); i += 2; } else { @@ -291,9 +326,7 @@ #[test()] fn points_test() { - ; 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)]), @@ -301,6 +334,7 @@ fill_points: vec![Point::new(1, 1)], play_box: Rect::from_box(0, 100, 0, 100).with_margin(10), size: Size::square(100), + intersections_box: Rect::from_box(0, 0, 100, 100), }; let segments: Vec = points.segments_iter().collect(); @@ -314,6 +348,7 @@ ); points.iter_mut().for_each(|p| p.x = 2); + assert_eq!(points.fill_points[0].x, 2); assert_eq!(points.islands[0].get_edge(0).start.x, 2); }