use geo::algorithm::intersects::Intersects; use geo::algorithm::rotate::Rotate; use geo::prelude::Translate; use geo::rotate::RotatePoint; use geo::LineString; use geo::{Coordinate, MultiPolygon, Point, Polygon}; use geo_clipper::Clipper; use polygon_art::MultiPolygonExt; use polygon_art::{load_multipolygon_from_svg_include, Context}; use rand::prelude::StdRng; use rand::Rng; /// A more or less complete example that illustrates various technics fn main() { let mut context = Context::create(); let mut rng = context.gen_rng(); let width = context.width; let height = context.height; let diagonal = f64::sqrt(width * width + height * height); // todo : it does not make to much sense to define all parameters like this // todo : it makes more sense to create a static (diagonal / width /height ratio ) setup and scale it up let frame_offset = diagonal * 0.01; let max_asteroid = (diagonal / 40.) as usize; let min_asteroid_size = diagonal / 40.; let max_asteroid_size = diagonal / 12.; let ship_length = diagonal / 23.; let ship_orbit = 3.0; let center_point = MultiPolygon(vec![create_asteroid(&mut rng, 8, 2)]) .scale_to_width(ship_orbit * ship_length) .translate(width / 2., height / 2.); // create asteroid let mut asteroids: Vec> = Vec::new(); for _ in 0..(max_asteroid * 2) { let without_orbit = rng.gen_range(min_asteroid_size..max_asteroid_size) 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() > max_asteroid { break; } } // load ships let rotation = rng.gen_range(0..360); let ship_yard = [ include_str!("../../pool/asteroids/ship1.svg"), include_str!("../../pool/asteroids/ship2.svg"), include_str!("../../pool/asteroids/ship3.svg"), ]; let chosen_ship = rng.gen_range(0..3); let ship = load_multipolygon_from_svg_include(ship_yard[chosen_ship]) .unwrap() .rotate(90.) // rotate to scale ship with width .scale_to_width(ship_length) .translate_center() .rotate(rotation as f64); context.translate_center(); context.draw_multipolygon(&ship); context.restore(); // drawing and clipping let window = context.frame(frame_offset, frame_offset, frame_offset, frame_offset); 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(), ) }