polygon-art/src/bin/asteroids.rs

92 lines
2.9 KiB
Rust

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<MultiPolygon<f64>> = 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<f64> {
let mut asteroid_points: Vec<Point<f64>> = 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(),
)
}