From 3d86835849b3b30104ec0e2cdba2b9fbbebdc87e Mon Sep 17 00:00:00 2001 From: Ingolf Wagner Date: Thu, 8 Apr 2021 22:06:39 +0200 Subject: [PATCH] feat: add asteroids.rs --- pool/asteroids/ship1.svg | 34 +++++++++++++++ pool/asteroids/ship2.svg | 34 +++++++++++++++ pool/asteroids/ship3.svg | 34 +++++++++++++++ src/bin/asteroids.rs | 91 ++++++++++++++++++++++++++++++++++++++++ src/context.rs | 18 ++++++-- 5 files changed, 207 insertions(+), 4 deletions(-) create mode 100644 pool/asteroids/ship1.svg create mode 100644 pool/asteroids/ship2.svg create mode 100644 pool/asteroids/ship3.svg create mode 100644 src/bin/asteroids.rs diff --git a/pool/asteroids/ship1.svg b/pool/asteroids/ship1.svg new file mode 100644 index 0000000..7837460 --- /dev/null +++ b/pool/asteroids/ship1.svg @@ -0,0 +1,34 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/pool/asteroids/ship2.svg b/pool/asteroids/ship2.svg new file mode 100644 index 0000000..580b04c --- /dev/null +++ b/pool/asteroids/ship2.svg @@ -0,0 +1,34 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/pool/asteroids/ship3.svg b/pool/asteroids/ship3.svg new file mode 100644 index 0000000..439e017 --- /dev/null +++ b/pool/asteroids/ship3.svg @@ -0,0 +1,34 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/bin/asteroids.rs b/src/bin/asteroids.rs new file mode 100644 index 0000000..e3ed65f --- /dev/null +++ b/src/bin/asteroids.rs @@ -0,0 +1,91 @@ +use geo::algorithm::intersects::Intersects; +use geo::algorithm::rotate::Rotate; +use geo::prelude::Translate; +use geo::rotate::RotatePoint; +use geo::{Coordinate, MultiPolygon, Point, Polygon}; +use geo::{LineString}; +use geo_clipper::Clipper; +use polygon_art::MultiPolygonExt; +use polygon_art::{load_multipolgon_from_svg, Context}; +use rand::prelude::StdRng; +use rand::Rng; + +fn main() { + let mut context = Context::create(); + let mut rng = context.gen_rng(); + + let ship_width = 100.; + let center_point = MultiPolygon(vec![create_asteroid(&mut rng, 20, 2)]) + .scale_to_width(2.5 * ship_width) + .translate(context.width / 2., context.height / 2.); + + // create asteroid + let mut asteroids: Vec> = Vec::new(); + for _ in 0..40 { + let without_orbit = rng.gen_range(40..140) as f64; + let with_orbit = without_orbit * 1.32; + let x = rng.gen_range(0..(context.width as i32)) as f64; + let y = rng.gen_range(0..(context.height as i32)) as f64; + let asteroid = MultiPolygon(vec![create_asteroid(&mut rng, 20, 15)]) + .scale_to_width(with_orbit) + .translate(x, y); + + if !center_point.intersects(&asteroid) && asteroids + .iter() + .find(|&m| *&m.intersects(&asteroid)) + .is_none() + { + asteroids.push(asteroid.scale_to_width(without_orbit)); + } + if asteroids.len() > 23 { + break; + } + } + + // load ships + let rotation = rng.gen_range(0..360); + let ship = load_multipolgon_from_svg("pool/asteroids/ship3.svg") + .unwrap() + .scale_to_width(ship_width) + .translate_center() + .rotate(rotation as f64); + context.translate_center(); + context.draw_multipolygon(&ship); + context.restore(); + + // drawing and clipping + let frame_space = 10.; + let window = context.frame(frame_space, frame_space, frame_space, frame_space); + context.draw_polygon(&window); + + for asteroid in asteroids.iter() { + context.draw_multipolygon(&asteroid.intersection(&window, 100.)); + } + + context.render(); +} + +fn create_asteroid(rng: &mut StdRng, subdivisions: i32, radius_randomization: i32) -> Polygon { + let mut asteroid_points: Vec> = Vec::new(); + for _ in 0..subdivisions { + let change = rng.gen_range(0..(radius_randomization * 2)); + asteroid_points.push(Point(Coordinate { + x: 0.0, + y: 100.0 + (change - radius_randomization) as f64, + })); + for point in asteroid_points.iter_mut() { + let (x, y) = point + .rotate_around_point( + 360. / subdivisions as f64, + Point(Coordinate { x: 0., y: 0. }), + ) + .x_y(); + point.set_x(x); + point.set_y(y); + } + } + Polygon::new( + LineString(asteroid_points.iter().map(|point| point.0).collect()), + Vec::new(), + ) +} diff --git a/src/context.rs b/src/context.rs index ab115d7..8983be5 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,6 +1,6 @@ use cairo::Format; use cairo::{ImageSurface, SvgSurface}; -use geo_types::{LineString, MultiPolygon, Polygon}; +use geo::{polygon, LineString, MultiPolygon, Polygon}; use rand::rngs::StdRng; use rand::{Rng, SeedableRng}; @@ -22,6 +22,16 @@ pub struct Context { } impl Context { + /// generate a frame for the image + pub fn frame(&mut self, left: f64, bottom: f64, right: f64, top: f64) -> Polygon { + polygon![ + (x: left, y: top), + (x: self.width - right, y: top), + (x: self.width - right, y: self.height - bottom), + (x: left , y: self.height - bottom), + ] + } + pub fn draw_multipolygon(&self, multi_polygon: &MultiPolygon) { for polygon in multi_polygon.iter() { self.draw_polygon(polygon); @@ -48,10 +58,7 @@ impl Context { } context.stroke(); } -} -// cairo facades -impl Context { /// restore state which was saved before by the context pub fn restore(&self) { self.render_container.context().restore(); @@ -81,6 +88,9 @@ impl Context { self.render_container.render(); } + pub fn gen_rng(&mut self) -> StdRng { + StdRng::seed_from_u64(self.pseudo_random_number_generator.gen()) + } pub fn create() -> Context { let opt = Opt::get_command_line_arguments(); let height = f64::from(opt.height.clone());