this repo has no description
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

:memo: Intro > Procedural approach done

+367 -63
+2
Justfile
··· 30 30 paper: 31 31 just 32 32 ./shapemaker examples dna-analysis-machine --resolution 1920 paper/dna-analysis-machine.png 33 + ./shapemaker examples shapeshed --resolution 1920 paper/shapeshed.svg 34 + ./shapemaker examples colors-shed --resolution 1920 paper/colorshed.svg 33 35 typst compile --root . paper/main.typ 34 36 35 37 readme:
+80
paper/colorshed.svg
··· 1 + <svg height="150" viewBox="0 0 200 150" width="200" xmlns="http://www.w3.org/2000/svg"> 2 + <rect fill="black" height="150" width="200" x="0" y="0"/> 3 + <g class="layer" data-layer="root"> 4 + <g data-object="--pink_bg" style="fill: green;transform-box: fill-box;" transform-origin="125 125"> 5 + <rect height="50" width="50" x="100" y="100"/> 6 + </g> 7 + <g data-object="--orange_bg" style="fill: red;transform-box: fill-box;" transform-origin="125 75"> 8 + <rect height="50" width="50" x="100" y="50"/> 9 + </g> 10 + <g data-object="--gray_bg" style="fill: black;transform-box: fill-box;" transform-origin="25 25"> 11 + <rect height="50" width="50" x="0" y="0"/> 12 + </g> 13 + <g data-object="--yellow_bg" style="fill: orange;transform-box: fill-box;" transform-origin="75 75"> 14 + <rect height="50" width="50" x="50" y="50"/> 15 + </g> 16 + <g data-object="--blue_bg" style="fill: cyan;transform-box: fill-box;" transform-origin="125 25"> 17 + <rect height="50" width="50" x="100" y="0"/> 18 + </g> 19 + <g data-object="--purple_bg" style="fill: pink;transform-box: fill-box;" transform-origin="75 125"> 20 + <rect height="50" width="50" x="50" y="100"/> 21 + </g> 22 + <g data-object="--white_bg" style="fill: yellow;transform-box: fill-box;" transform-origin="25 75"> 23 + <rect height="50" width="50" x="0" y="50"/> 24 + </g> 25 + <g data-object="--brown_bg" style="fill: purple;transform-box: fill-box;" transform-origin="25 125"> 26 + <rect height="50" width="50" x="0" y="100"/> 27 + </g> 28 + <g data-object="--green_bg" style="fill: gray;transform-box: fill-box;" transform-origin="175 125"> 29 + <rect height="50" width="50" x="150" y="100"/> 30 + </g> 31 + <g data-object="--red_bg" style="fill: brown;transform-box: fill-box;" transform-origin="175 75"> 32 + <rect height="50" width="50" x="150" y="50"/> 33 + </g> 34 + <g data-object="--cyan_bg" style="fill: white;transform-box: fill-box;" transform-origin="175 25"> 35 + <rect height="50" width="50" x="150" y="0"/> 36 + </g> 37 + <g data-object="--black_bg" style="fill: blue;transform-box: fill-box;" transform-origin="75 25"> 38 + <rect height="50" width="50" x="50" y="0"/> 39 + </g> 40 + </g> 41 + <g class="layer" data-layer="circles"> 42 + <g data-object="--gray" style="fill: gray;transform-box: fill-box;" transform-origin="25 25"> 43 + <circle cx="25" cy="25" r="25"/> 44 + </g> 45 + <g data-object="--brown" style="fill: brown;transform-box: fill-box;" transform-origin="25 125"> 46 + <circle cx="25" cy="125" r="25"/> 47 + </g> 48 + <g data-object="--purple" style="fill: purple;transform-box: fill-box;" transform-origin="75 125"> 49 + <circle cx="75" cy="125" r="25"/> 50 + </g> 51 + <g data-object="--white" style="fill: white;transform-box: fill-box;" transform-origin="25 75"> 52 + <circle cx="25" cy="75" r="25"/> 53 + </g> 54 + <g data-object="--green" style="fill: green;transform-box: fill-box;" transform-origin="175 125"> 55 + <circle cx="175" cy="125" r="25"/> 56 + </g> 57 + <g data-object="--cyan" style="fill: cyan;transform-box: fill-box;" transform-origin="175 25"> 58 + <circle cx="175" cy="25" r="25"/> 59 + </g> 60 + <g data-object="--black" style="fill: black;transform-box: fill-box;" transform-origin="75 25"> 61 + <circle cx="75" cy="25" r="25"/> 62 + </g> 63 + <g data-object="--yellow" style="fill: yellow;transform-box: fill-box;" transform-origin="75 75"> 64 + <circle cx="75" cy="75" r="25"/> 65 + </g> 66 + <g data-object="--blue" style="fill: blue;transform-box: fill-box;" transform-origin="125 25"> 67 + <circle cx="125" cy="25" r="25"/> 68 + </g> 69 + <g data-object="--pink" style="fill: pink;transform-box: fill-box;" transform-origin="125 125"> 70 + <circle cx="125" cy="125" r="25"/> 71 + </g> 72 + <g data-object="--orange" style="fill: orange;transform-box: fill-box;" transform-origin="125 75"> 73 + <circle cx="125" cy="75" r="25"/> 74 + </g> 75 + <g data-object="--red" style="fill: red;transform-box: fill-box;" transform-origin="175 75"> 76 + <circle cx="175" cy="75" r="25"/> 77 + </g> 78 + </g> 79 + <defs/> 80 + </svg>
paper/dna-analysis-machine.png

This is a binary file and will not be displayed.

paper/main.pdf

This is a binary file and will not be displayed.

+29
paper/main.typ
··· 73 73 "weaving").map(artwork => grid.cell(image("../examples/gallery/" + artwork + ".svg", width: 100%)) ) 74 74 )) 75 75 76 + L'étape prochaine dans cette démarche était évidemment donc de générer procéduralement ces formes. Afin d'avoir des résultats intéréssants, et devant l'évidente absurdité d'un projet d'énumération _complète_ de _toutes les formes_, on préfèrera des générations procédurales dites "semi-aléatoires", dans le sens où certains aspects du résultat final sont laissés à l'aléatoire, comme le placement des formes élémentaires, tandis que de d'autres, comme la palette de couleurs, sont des décisions de l'artiste. 77 + 78 + Le modèle initialement choisi dans les premières ébauches de Shapemaker est le suivant: 79 + 80 + #figure( 81 + caption: "Vocabulaire visuel des premières ébauches: grille de placement à 9 points, formes et couleurs", 82 + grid( 83 + columns: (1fr, 1fr, 1fr), 84 + gutter:3em, 85 + grid.cell( 86 + align: center, 87 + grid( 88 + columns: (2em, 2em, 2em), 89 + rows: (2em, 2em, 2em), 90 + gutter: 1em, 91 + ..range(9).map(it => circle(radius: 0.2em, fill: black)) 92 + ) 93 + ), 94 + grid.cell(image("./shapeshed.svg"), align: center), 95 + grid.cell(image("./colorshed.svg"), align: center) 96 + ) 97 + ) 98 + 99 + L'idée est donc de limiter la part d'aléatoire à des choix dans des ensembles prédéfinis d'éléments, que ce soit dans le choix des couleurs, des placements ou des formes élémentaires. 100 + 101 + Cette méthode amène donc l'artiste à définir, d'une certaine manière, son _propre langage visuel_, où les éléments de langage sont les couleurs, formes, placements et post-traitements (flou, rotations, etc) utilisables. 102 + 103 + La part aléatoire engendre _une_ infinité réduite d'œuvres, qui naissent dans les confins du langage visuel devisé par l'artiste. 104 + 76 105 == Excursion dans le monde physique 77 106 78 107 === Interprétation collective
+30
paper/shapeshed.svg
··· 1 + <svg height="170" viewBox="-10 -10 170 170" width="170" xmlns="http://www.w3.org/2000/svg"> 2 + <rect fill="white" height="170" width="170" x="-10" y="-10"/> 3 + <g class="layer" data-layer="root"> 4 + <g data-object="--7" style="fill: black;transform-box: fill-box;" transform-origin="25 125"> 5 + <rect height="50" width="50" x="0" y="100"/> 6 + </g> 7 + <g data-object="--5" style="stroke: black; fill: transparent;transform-box: fill-box;" transform-origin="100 100"> 8 + <line stroke-width="5" x1="50" x2="100" y1="50" y2="100"/> 9 + </g> 10 + <g data-object="--4" style="fill: black;transform-box: fill-box;" transform-origin="25 75"> 11 + <circle cx="0" cy="50" r="5"/> 12 + </g> 13 + <g data-object="--3" style="stroke: black; fill: transparent;transform-box: fill-box;" transform-origin="150 50"> 14 + <path d="M100,50 Q100,0,150,0" stroke-width="5"/> 15 + </g> 16 + <g data-object="--2" style="stroke: black; fill: transparent;transform-box: fill-box;" transform-origin="100 50"> 17 + <path d="M50,50 Q100,50,100,0" stroke-width="5"/> 18 + </g> 19 + <g data-object="--6" style="fill: black;transform-box: fill-box;" transform-origin="150 100"> 20 + <path d="M100,50 L150,50 L150,100 z"/> 21 + </g> 22 + <g data-object="--8" style="fill: black;transform-box: fill-box;" transform-origin="125 175"> 23 + <circle cx="100" cy="150" r="2"/> 24 + </g> 25 + <g data-object="--1" style="fill: black;transform-box: fill-box;" transform-origin="25 25"> 26 + <circle cx="25" cy="25" r="25"/> 27 + </g> 28 + </g> 29 + <defs/> 30 + </svg>
+3 -1
src/cli/mod.rs
··· 14 14 15 15 Usage: shapemaker (image|video) [options] [--color <mapping>...] <file> 16 16 shapemaker beacon start [options] [--color <mapping>...] <file> 17 - shapemaker examples (dna-analysis-machine) [options] <file> 17 + shapemaker examples (dna-analysis-machine|shapeshed|colors-shed) [options] <file> 18 18 shapemaker --help 19 19 shapemaker --version 20 20 ··· 82 82 pub cmd_start: bool, 83 83 pub cmd_examples: bool, 84 84 pub cmd_dna_analysis_machine: bool, 85 + pub cmd_shapeshed: bool, 86 + pub cmd_colors_shed: bool, 85 87 pub arg_file: String, 86 88 pub flag_version: bool, 87 89 pub flag_color: Vec<String>,
+99 -1
src/examples.rs
··· 1 + use std::iter; 2 + 1 3 use crate::*; 2 4 use rand::Rng; 3 5 6 + pub fn shapes_shed() -> Canvas { 7 + let mut canvas = Canvas::new(vec![]); 8 + 9 + canvas.set_grid_size(3, 3); 10 + canvas.set_background(Color::White); 11 + 12 + let root = canvas.layer("root"); 13 + 14 + root.add_object( 15 + "1", 16 + Object::BigCircle(Point(0, 0)).color(Fill::Solid(Color::Black)), 17 + ); 18 + root.add_object( 19 + "2", 20 + Object::CurveOutward(Point(1, 1), Point(2, 0), 5.0) 21 + .color(Fill::Solid(Color::Black)), 22 + ); 23 + root.add_object( 24 + "3", 25 + Object::CurveInward(Point(2, 1), Point(3, 0), 5.0) 26 + .color(Fill::Solid(Color::Black)), 27 + ); 28 + root.add_object( 29 + "4", 30 + Object::SmallCircle(Point(0, 1)).color(Fill::Solid(Color::Black)), 31 + ); 32 + root.add_object( 33 + "5", 34 + Object::Line(Point(1, 1), Point(2, 2), 5.0) 35 + .color(Fill::Solid(Color::Black)), 36 + ); 37 + root.add_object( 38 + "6", 39 + Object::Polygon( 40 + Point(2, 1), 41 + vec![ 42 + LineSegment::Straight(Point(3, 1)), 43 + LineSegment::Straight(Point(3, 2)), 44 + ], 45 + ) 46 + .color(Fill::Solid(Color::Black)), 47 + ); 48 + root.add_object( 49 + "7", 50 + Object::Rectangle(Point(0, 2), Point(0, 2)) 51 + .color(Fill::Solid(Color::Black)), 52 + ); 53 + root.add_object( 54 + "8", 55 + Object::Dot(Point(2, 3)).color(Fill::Solid(Color::Black)), 56 + ); 57 + 58 + canvas 59 + } 60 + 61 + pub fn colors_shed() -> Canvas { 62 + let mut canvas = Canvas::new(vec!["circles"]); 63 + canvas.set_grid_size(4, 3); 64 + canvas.canvas_outter_padding = 0; 65 + 66 + let all_colors = vec![ 67 + Color::Gray, 68 + Color::Black, 69 + Color::Blue, 70 + Color::Cyan, 71 + Color::White, 72 + Color::Yellow, 73 + Color::Orange, 74 + Color::Red, 75 + Color::Brown, 76 + Color::Purple, 77 + Color::Pink, 78 + Color::Green, 79 + ]; 80 + 81 + let foregrounds = all_colors.iter(); 82 + let backgrounds = all_colors.iter().cycle().skip(1); 83 + let colors = iter::zip(foregrounds, backgrounds); 84 + 85 + for ((color, bgcolor), point) in 86 + iter::zip(colors, canvas.world_region.iter()) 87 + { 88 + println!("{}: {:?} {:?}", point, color, bgcolor); 89 + canvas.layer("circles").add_object( 90 + color.name(), 91 + Object::BigCircle(point).color(Fill::Solid(*color)), 92 + ); 93 + canvas.layer("root").add_object( 94 + format!("{}_bg", color.name()), 95 + Object::Rectangle(point, point).color(Fill::Solid(*bgcolor)), 96 + ); 97 + } 98 + 99 + canvas 100 + } 101 + 4 102 pub fn dna_analysis_machine() -> Canvas { 5 103 let mut canvas = Canvas::new(vec![]); 6 104 ··· 67 165 } 68 166 69 167 let mut filaments = 70 - canvas.n_random_linelikes_within("splines", &filaments_area, 30); 168 + canvas.n_random_curves_within("splines", &filaments_area, 30); 71 169 72 170 for (i, object) in filaments.objects.values_mut().enumerate() { 73 171 object.recolor(Fill::Solid(if i % 2 == 0 {
+33 -19
src/graphics/canvas.rs
··· 7 7 8 8 use crate::{ 9 9 fonts::{load_fonts, FontOptions}, 10 - Color, ColorMapping, Fill, Filter, Layer, Object, ObjectSizes, Point, Region, 10 + Color, ColorMapping, Fill, Filter, Layer, Object, ObjectSizes, Point, 11 + Region, 11 12 }; 13 + 14 + use super::ColoredObject; 12 15 13 16 #[derive(Debug, Clone)] 14 17 pub struct Canvas { ··· 106 109 /// puts this layer on top, and the others below, without changing their order 107 110 pub fn put_layer_on_top(&mut self, name: &str) { 108 111 self.ensure_layer_exists(name); 109 - let target_index = self.layers.iter().position(|l| l.name == name).unwrap(); 112 + let target_index = 113 + self.layers.iter().position(|l| l.name == name).unwrap(); 110 114 self.layers.swap(0, target_index) 111 115 } 112 116 113 117 /// puts this layer on bottom, and the others above, without changing their order 114 118 pub fn put_layer_on_bottom(&mut self, name: &str) { 115 119 self.ensure_layer_exists(name); 116 - let target_index = self.layers.iter().position(|l| l.name == name).unwrap(); 120 + let target_index = 121 + self.layers.iter().position(|l| l.name == name).unwrap(); 117 122 let last_index = self.layers.len() - 1; 118 123 self.layers.swap(last_index, target_index) 119 124 } ··· 139 144 assert!(new_order.iter().all(|name| self.layer_exists(name))); 140 145 141 146 self.layers.sort_by_key(|o| { 142 - new_order 143 - .iter() 144 - .position(|&n| n == o.name) 145 - .unwrap_or(current_order.iter().position(|n| *n == o.name).unwrap()) 147 + new_order.iter().position(|&n| n == o.name).unwrap_or( 148 + current_order.iter().position(|n| *n == o.name).unwrap(), 149 + ) 146 150 }); 147 151 } 148 152 ··· 161 165 match self.layer_safe(layer) { 162 166 None => Err(format!("Layer {} does not exist", layer)), 163 167 Some(layer) => { 164 - layer.add_object(name, (object, fill).into()); 168 + layer.add_object(name, ColoredObject::from((object, fill))); 165 169 Ok(()) 166 170 } 167 171 } ··· 255 259 None => { 256 260 std::fs::copy(previous_frame_at, at)?; 257 261 } 258 - Some(pixmap) => { 259 - pixmap_to_png_data(pixmap).and_then(|data| write_png_data(data, at))? 260 - } 262 + Some(pixmap) => pixmap_to_png_data(pixmap) 263 + .and_then(|data| write_png_data(data, at))?, 261 264 } 262 265 return Ok(()); 263 266 } 264 267 265 268 self.render_to_pixmap_no_cache(width, height) 266 - .and_then(|pixmap| pixmap_to_png_data(pixmap).and_then(|data| write_png_data(data, at))) 269 + .and_then(|pixmap| { 270 + pixmap_to_png_data(pixmap) 271 + .and_then(|data| write_png_data(data, at)) 272 + }) 267 273 } 268 274 } 269 275 ··· 280 286 281 287 impl Canvas { 282 288 pub fn width(&self) -> usize { 283 - self.cell_size * self.world_region.width() + 2 * self.canvas_outter_padding 289 + self.cell_size * self.world_region.width() 290 + + 2 * self.canvas_outter_padding 284 291 } 285 292 286 293 pub fn height(&self) -> usize { 287 - self.cell_size * self.world_region.height() + 2 * self.canvas_outter_padding 294 + self.cell_size * self.world_region.height() 295 + + 2 * self.canvas_outter_padding 288 296 } 289 297 290 298 pub fn aspect_ratio(&self) -> f32 { ··· 303 311 pub fn unique_filters(&self) -> Vec<Filter> { 304 312 self.layers 305 313 .iter() 306 - .flat_map(|layer| layer.objects.iter().flat_map(|(_, o)| o.filters.clone())) 314 + .flat_map(|layer| { 315 + layer.objects.iter().flat_map(|(_, o)| o.filters.clone()) 316 + }) 307 317 .unique() 308 318 .collect() 309 319 } ··· 326 336 ); 327 337 layer.add_object( 328 338 format!("{}_corner_se", region).as_str(), 329 - Object::Dot(region.topright().translated(1, 0)).color(Fill::Solid(color)), 339 + Object::Dot(region.topright().translated(1, 0)) 340 + .color(Fill::Solid(color)), 330 341 ); 331 342 layer.add_object( 332 343 format!("{}_corner_ne", region).as_str(), 333 - Object::Dot(region.bottomright().translated(1, 1)).color(Fill::Solid(color)), 344 + Object::Dot(region.bottomright().translated(1, 1)) 345 + .color(Fill::Solid(color)), 334 346 ); 335 347 layer.add_object( 336 348 format!("{}_corner_nw", region).as_str(), 337 - Object::Dot(region.bottomleft().translated(0, 1)).color(Fill::Solid(color)), 349 + Object::Dot(region.bottomleft().translated(0, 1)) 350 + .color(Fill::Solid(color)), 338 351 ); 339 352 layer.add_object( 340 353 format!("{}_region", region).as_str(), 341 - Object::Rectangle(region.start, region.end).color(Fill::Translucent(color, 0.25)), 354 + Object::Rectangle(region.start, region.end) 355 + .color(Fill::Translucent(color, 0.25)), 342 356 ) 343 357 } 344 358 }
+3 -3
src/graphics/layer.rs
··· 84 84 self.flush(); 85 85 } 86 86 87 - pub fn add_object<N: Display>(&mut self, name: N, object: ColoredObject) { 87 + pub fn add_object<N: Display>(&mut self, name: N, object: impl Into<ColoredObject>) { 88 88 let name_str = format!("{}", name); 89 89 90 90 if self.objects.contains_key(&name_str) { ··· 94 94 self.set_object(name_str, object); 95 95 } 96 96 97 - pub fn set_object<N: Display>(&mut self, name: N, object: ColoredObject) { 97 + pub fn set_object<N: Display>(&mut self, name: N, object: impl Into<ColoredObject>) { 98 98 let name_str = format!("{}", name); 99 99 100 - self.objects.insert(name_str, object); 100 + self.objects.insert(name_str, object.into()); 101 101 self.flush(); 102 102 } 103 103
+30 -12
src/main.rs
··· 21 21 info_time!("run"); 22 22 let mut canvas = canvas_from_cli(&args); 23 23 24 - if args.cmd_examples && args.cmd_dna_analysis_machine { 25 - canvas = examples::dna_analysis_machine(); 24 + if args.cmd_examples { 25 + canvas = if args.cmd_dna_analysis_machine { 26 + examples::dna_analysis_machine() 27 + } else if args.cmd_shapeshed { 28 + examples::shapes_shed() 29 + } else if args.cmd_colors_shed { 30 + examples::colors_shed() 31 + } else { 32 + panic!("Specify the example to use") 33 + }; 26 34 27 35 if args.arg_file.ends_with(".svg") { 28 36 std::fs::write( ··· 38 46 ) 39 47 .unwrap(); 40 48 } else { 41 - match canvas.render_to_png(&args.arg_file, args.flag_resolution.unwrap_or(1000), None) { 49 + match canvas.render_to_png( 50 + &args.arg_file, 51 + args.flag_resolution.unwrap_or(1000), 52 + None, 53 + ) { 42 54 Ok(_) => println!("Image saved to {}", args.arg_file), 43 55 Err(e) => println!("Error saving image: {}", e), 44 56 } ··· 55 67 56 68 #[cfg(not(feature = "vst"))] 57 69 fn run_beacon_start(_args: cli::Args, _canvas: Canvas) -> Result<()> { 58 - println!("VST support is disabled. Enable the vst feature to use VST beaconing."); 70 + println!( 71 + "VST support is disabled. Enable the vst feature to use VST beaconing." 72 + ); 59 73 Ok(()) 60 74 } 61 75 ··· 67 81 68 82 #[cfg(not(feature = "mp4"))] 69 83 fn run_video(_args: cli::Args, _canvas: Canvas) -> Result<()> { 70 - println!("Video rendering is disabled. Enable the mp4 feature to render videos."); 84 + println!( 85 + "Video rendering is disabled. Enable the mp4 feature to render videos." 86 + ); 71 87 Ok(()) 72 88 } 73 89 ··· 83 99 .expect("Provide audio with --audio to render a video") 84 100 .into(); 85 101 video 86 - .sync_audio_with( 87 - &args 88 - .flag_sync_with 89 - .expect("Provide MIDI sync file with --sync-with to render a video"), 90 - ) 102 + .sync_audio_with(&args.flag_sync_with.expect( 103 + "Provide MIDI sync file with --sync-with to render a video", 104 + )) 91 105 .each_frame(&|canvas, ctx| { 92 106 let center = canvas.world_region.center(); 93 107 canvas.root().clear(); ··· 98 112 ); 99 113 canvas.root().add_object( 100 114 "beat", 101 - Object::CenteredText(center.translated(0, 3), format!("beat {}", ctx.beat), 30.0) 102 - .color(Fill::Solid(Color::Cyan)), 115 + Object::CenteredText( 116 + center.translated(0, 3), 117 + format!("beat {}", ctx.beat), 118 + 30.0, 119 + ) 120 + .color(Fill::Solid(Color::Cyan)), 103 121 ); 104 122 Ok(()) 105 123 })
+5 -5
src/random/canvas.rs
··· 15 15 ) 16 16 } 17 17 18 - pub fn n_random_linelikes_within( 18 + pub fn n_random_curves_within( 19 19 &self, 20 20 layer_name: &str, 21 21 region: &Region, ··· 24 24 let mut objects: HashMap<String, ColoredObject> = HashMap::new(); 25 25 for i in 0..count { 26 26 let object = 27 - Object::random_linelike_within(region, self.object_sizes.default_line_width); 27 + Object::random_curve_within(region, self.object_sizes.default_line_width); 28 28 objects.insert( 29 29 format!("{}#{}", layer_name, i), 30 30 ColoredObject::from(( ··· 46 46 } 47 47 } 48 48 49 - pub fn random_linelikes_within( 49 + pub fn random_curves_within( 50 50 &self, 51 51 layer_name: &str, 52 52 region: &Region, 53 53 object_counts: impl SampleRange<usize>, 54 54 ) -> Layer { 55 55 let number_of_objects = rand::thread_rng().gen_range(object_counts); 56 - self.n_random_linelikes_within(layer_name, region, number_of_objects) 56 + self.n_random_curves_within(layer_name, region, number_of_objects) 57 57 } 58 58 59 59 pub fn random_layer_within(&self, name: &str, region: &Region) -> Layer { ··· 85 85 } 86 86 87 87 pub fn random_linelikes(&self, layer_name: &str) -> Layer { 88 - self.random_linelikes_within( 88 + self.random_curves_within( 89 89 layer_name, 90 90 &self.world_region, 91 91 self.objects_count_range.clone(),
+3 -3
src/random/objects.rs
··· 27 27 let mut lines: Vec<LineSegment> = vec![]; 28 28 for _ in 0..number_of_anchors { 29 29 let next_anchor = Point::random(region); 30 - lines.push(Self::random_line(next_anchor)); 30 + lines.push(Self::random_line_segment(next_anchor)); 31 31 } 32 32 Object::Polygon(start, lines) 33 33 } 34 34 35 - pub fn random_line(end: Point) -> LineSegment { 35 + pub fn random_line_segment(end: Point) -> LineSegment { 36 36 match rand::thread_rng().gen_range(1..=3) { 37 37 1 => LineSegment::Straight(end), 38 38 2 => LineSegment::InwardCurve(end), ··· 50 50 Object::random_starting_at(start, region, line_width, polygon_vertices_range) 51 51 } 52 52 53 - pub fn random_linelike_within(region: &Region, line_width: f32) -> Object { 53 + pub fn random_curve_within(region: &Region, line_width: f32) -> Object { 54 54 let start = region.random_point(); 55 55 match rand::thread_rng().gen_range(1..=3) { 56 56 1 => Object::CurveInward(start, region.random_end(start), line_width),
+50 -19
src/rendering/objects.rs
··· 5 5 ColoredObject, Object, 6 6 }; 7 7 8 - use super::{renderable::SVGRenderable, CSSRenderable, SVGAttributesRenderable}; 8 + use super::{ 9 + renderable::SVGRenderable, CSSRenderable, SVGAttributesRenderable, 10 + }; 9 11 10 12 impl SVGRenderable for ColoredObject { 11 13 fn render_to_svg( ··· 15 17 object_sizes: crate::graphics::objects::ObjectSizes, 16 18 id: &str, 17 19 ) -> anyhow::Result<svg::node::element::Element> { 18 - let mut group = self 19 - .object 20 - .render_to_svg(colormap.clone(), cell_size, object_sizes, id)?; 20 + let mut group = self.object.render_to_svg( 21 + colormap.clone(), 22 + cell_size, 23 + object_sizes, 24 + id, 25 + )?; 21 26 22 27 let attributes = group.get_attributes_mut(); 23 28 ··· 79 84 let group = svg::node::element::Group::new(); 80 85 81 86 let rendered = match self { 82 - Object::Text(..) | Object::CenteredText(..) => self.render_text(cell_size), 87 + Object::Text(..) | Object::CenteredText(..) => { 88 + self.render_text(cell_size) 89 + } 83 90 Object::Rectangle(..) => self.render_rectangle(cell_size), 84 91 Object::Polygon(..) => self.render_polygon(cell_size), 85 92 Object::Line(..) => self.render_line(cell_size), 86 - Object::CurveInward(..) | Object::CurveOutward(..) => self.render_curve(cell_size), 87 - Object::SmallCircle(..) => self.render_small_circle(cell_size, object_sizes), 93 + Object::CurveInward(..) | Object::CurveOutward(..) => { 94 + self.render_curve(cell_size) 95 + } 96 + Object::SmallCircle(..) => { 97 + self.render_small_circle(cell_size, object_sizes) 98 + } 88 99 Object::Dot(..) => self.render_dot(cell_size, object_sizes), 89 100 Object::BigCircle(..) => self.render_big_circle(cell_size), 90 101 Object::Image(..) => self.render_image(cell_size), ··· 196 207 path = match line { 197 208 LineSegment::Straight(end) 198 209 | LineSegment::InwardCurve(end) 199 - | LineSegment::OutwardCurve(end) => path.line_to(end.coords(cell_size)), 210 + | LineSegment::OutwardCurve(end) => { 211 + path.line_to(end.coords(cell_size)) 212 + } 200 213 }; 201 214 } 202 215 path = path.close(); ··· 222 235 } 223 236 224 237 fn render_curve(&self, cell_size: usize) -> Box<dyn svg::node::Node> { 225 - if let Object::CurveOutward(start, end, _) | Object::CurveInward(start, end, _) = self { 238 + if let Object::CurveOutward(start, end, stroke_width) 239 + | Object::CurveInward(start, end, stroke_width) = self 240 + { 226 241 let inward = matches!(self, Object::CurveInward(..)); 227 242 228 243 let (start_x, start_y) = start.coords(cell_size); 229 244 let (end_x, end_y) = end.coords(cell_size); 230 245 231 246 let midpoint = ((start_x + end_x) / 2.0, (start_y + end_y) / 2.0); 232 - let start_from_midpoint = (start_x - midpoint.0, start_y - midpoint.1); 247 + let start_from_midpoint = 248 + (start_x - midpoint.0, start_y - midpoint.1); 233 249 let end_from_midpoint = (end_x - midpoint.0, end_y - midpoint.1); 234 250 235 251 let control = { ··· 267 283 } else if start_y == end_y { 268 284 ( 269 285 midpoint.0, 270 - midpoint.1 + (if inward { -1.0 } else { 1.0 }) * relative.0.abs() / 2.0, 286 + midpoint.1 287 + + (if inward { -1.0 } else { 1.0 }) 288 + * relative.0.abs() 289 + / 2.0, 271 290 ) 272 291 // line is vertical 273 292 } else if start_x == end_x { 274 293 ( 275 - midpoint.0 + (if inward { -1.0 } else { 1.0 }) * relative.1.abs() / 2.0, 294 + midpoint.0 295 + + (if inward { -1.0 } else { 1.0 }) 296 + * relative.1.abs() 297 + / 2.0, 276 298 midpoint.1, 277 299 ) 278 300 } else { ··· 281 303 }; 282 304 283 305 return Box::new( 284 - svg::node::element::Path::new().set( 285 - "d", 286 - svg::node::element::path::Data::new() 287 - .move_to(start.coords(cell_size)) 288 - .quadratic_curve_to((control, end.coords(cell_size))), 289 - ), 306 + svg::node::element::Path::new() 307 + .set( 308 + "d", 309 + svg::node::element::path::Data::new() 310 + .move_to(start.coords(cell_size)) 311 + .quadratic_curve_to(( 312 + control, 313 + end.coords(cell_size), 314 + )), 315 + ) 316 + .set("stroke-width", format!("{stroke_width}")), 290 317 ); 291 318 } 292 319 ··· 310 337 panic!("Expected SmallCircle, got {:?}", self); 311 338 } 312 339 313 - fn render_dot(&self, cell_size: usize, object_sizes: ObjectSizes) -> Box<dyn svg::node::Node> { 340 + fn render_dot( 341 + &self, 342 + cell_size: usize, 343 + object_sizes: ObjectSizes, 344 + ) -> Box<dyn svg::node::Node> { 314 345 if let Object::Dot(center) = self { 315 346 return Box::new( 316 347 svg::node::element::Circle::new()