- Add distance-divider option to land_dump
authorunc0rr
Sun, 04 Nov 2018 00:20:27 +0100
changeset 14146 376a0551b00a
parent 14145 6e0be42d0a8f
child 14147 32383b888309
- Add distance-divider option to land_dump - Fix multiplication overflow errors (iy went widly out of bounds)
rust/integral-geometry/src/lib.rs
rust/land_dump/src/main.rs
rust/landgen/src/outline.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<Point>
+    vertices: Vec<Point>,
 }
 
 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));
+    }
 }
--- 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(&params, &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"),
--- 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<Point>,
     pub size: Size,
     pub play_box: Rect,
+    intersections_box: Rect,
 }
 
 impl OutlinePoints {
@@ -39,10 +38,13 @@
                                 )
                                 + play_box.top_left()
                         })
-                        .collect::<Vec<_>>().into()
+                        .collect::<Vec<_>>()
+                        .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<Line> = 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);
 }