diff --git a/src/bin/asteroids.rs b/src/bin/asteroids.rs index e3ed65f..076ff93 100644 --- a/src/bin/asteroids.rs +++ b/src/bin/asteroids.rs @@ -2,8 +2,8 @@ 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::{LineString}; use geo_clipper::Clipper; use polygon_art::MultiPolygonExt; use polygon_art::{load_multipolgon_from_svg, Context}; @@ -14,15 +14,28 @@ 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.); + 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..40 { - let without_orbit = rng.gen_range(40..140) as f64; + 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; @@ -30,14 +43,15 @@ fn main() { .scale_to_width(with_orbit) .translate(x, y); - if !center_point.intersects(&asteroid) && asteroids - .iter() - .find(|&m| *&m.intersects(&asteroid)) - .is_none() + 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 { + if asteroids.len() > max_asteroid { break; } } @@ -46,7 +60,8 @@ fn main() { let rotation = rng.gen_range(0..360); let ship = load_multipolgon_from_svg("pool/asteroids/ship3.svg") .unwrap() - .scale_to_width(ship_width) + .rotate(90.) // rotate to scale ship with width + .scale_to_width(ship_length) .translate_center() .rotate(rotation as f64); context.translate_center(); @@ -54,8 +69,7 @@ fn main() { context.restore(); // drawing and clipping - let frame_space = 10.; - let window = context.frame(frame_space, frame_space, frame_space, frame_space); + let window = context.frame(frame_offset, frame_offset, frame_offset, frame_offset); context.draw_polygon(&window); for asteroid in asteroids.iter() { diff --git a/src/context.rs b/src/context.rs index 8983be5..0919b70 100644 --- a/src/context.rs +++ b/src/context.rs @@ -91,12 +91,29 @@ impl Context { 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()); - let width = f64::from(opt.width.clone()); let line_size = opt.line_size.clone(); + let mm = 3.779527547619048; // calculated with inkscape 1587.40157 (px) / 420 (mm) (from a3) + let (mut height, mut width) = match opt.format { + None => (f64::from(opt.height.clone()), f64::from(opt.width.clone())), + Some(format) => match &format[..] { + "a3" => (297. * mm, 420. * mm), + "a4" => (210. * mm, 297. * mm), + "a5" => (148. * mm, 210. * mm), + "x220" => (768., 1366.), + _ => (f64::from(opt.height.clone()), f64::from(opt.width.clone())), + }, + }; + + if opt.orientation == "portrait" { + let cache = height; + height = width; + width = cache; + } + let random_seed = match opt.random_seed { Some(random_seed) => random_seed, None => match opt.random_seed_date { @@ -128,9 +145,8 @@ impl Context { .expect("Can't svg surface"); Box::new(SvgRenderContainer::new(svg_surface, palette)) as Box } else if opt.output_type == "png" { - let png_surface = - ImageSurface::create(Format::Rgb24, opt.width.clone(), opt.height.clone()) - .expect("Can't create png surface"); + let png_surface = ImageSurface::create(Format::Rgb24, width as i32, height as i32) + .expect("Can't create png surface"); Box::new(PngRenderContainer::new( opt.output.to_string_lossy().to_string(), png_surface, diff --git a/src/context/commandline.rs b/src/context/commandline.rs index f019227..b246a6c 100644 --- a/src/context/commandline.rs +++ b/src/context/commandline.rs @@ -13,13 +13,30 @@ pub struct Opt { pub output: PathBuf, /// define width in pixels - #[structopt(long, default_value = "400")] + #[structopt(long, default_value = "600")] pub width: i32, /// define height in pixels #[structopt(long, default_value = "400")] pub height: i32, + /// use a predefined format + #[structopt( + long, + conflicts_with="height", + conflicts_with="width", + possible_values=&["a3", "a4", "a5", "x220"] + )] + pub format: Option, + + /// change orientation + #[structopt( + long, + default_value="landscape", + possible_values=&["portrait", "landscape"] + )] + pub orientation: String, + /// define line size in pixels, all lines will be this thick #[structopt(long, default_value = "1.0")] pub line_size: f64,