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 @@
+
+
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 @@
+
+
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 @@
+
+
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());