This repository has no description
0

Configure Feed

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

๐ŸŽ‰ Initial commit

author
Ewen Le Bihan
date (Dec 18, 2022, 12:52 AM +0100) commit 9c0ae470
+512
+1
.gitignore
··· 1 + /target
+50
.portfoliodb/description.md
··· 1 + --- 2 + tags: 3 + - graphism 4 + - programming 5 + - experiment 6 + - language 7 + - command line 8 + made with: 9 + - svg 10 + - rust 11 + --- 12 + 13 + # Shapemaker 14 + 15 + :: en 16 + 17 + I wanted to dabble in generative art, and, as a first project, create a way to generate small, icon-like shapes from a predefined set of possible lines, curves and circles 18 + 19 + ## A restricted set of shapes 20 + 21 + ![]() 22 + 23 + Those shapes are described as sequences of elements, such as lines, either straight or curved, that start and end on fixed "anchor points": south-west, south, south-east, east, north-east, north, north-west, west and center. 24 + 25 + Lines can be grouped to form polygons (with some edges possibly curved), which can be filled with patterns (hatched or dotted) or colors. 26 + 27 + Additionally, dots, points (small circles) or circles can be added. The latter objects take up a full quarter of the block and can be placed in each quarter's center. These can be filled just like polygons. 28 + 29 + ## A language to describe these shapes 30 + 31 + I needed a language to describe these shapes with text, so that a program could generate random shapes, while keeping them coherent by reducing the amount of variables needed (randomly generating SVG text directly, for example, is unfeasable). 32 + 33 + ``` 34 + percent: 35 + top left circle 36 + bottom right -- top left 37 + bottom right circle 38 + 39 + abstract1: 40 + [ bottom left -- left ) top -- bottom -- bottom left ] filled with green 41 + top -- right -- bottom 42 + top left red dot 43 + 44 + lowercase j: 45 + center point 46 + center -- bottom -- bottom left 47 + ``` 48 + 49 + 50 + The idea was to generate SVG from this representation.
+13
.portfoliodb/shape.xml
··· 1 + <shape name="percent"> 2 + <big-circle at="top left"> 3 + <big-circle at="bottom right"> 4 + <line from="bottom left" to="top right"> 5 + </shape> 6 + 7 + <shape name="abstract1"> 8 + <polygon hatched> 9 + <line from="bottom left" to="left"> 10 + <curve down from="left" to="top"> 11 + <line points="top, right, bottom"> 12 + </polygon> 13 + </shape>
+12
.portfoliodb/shapemaker.yaml
··· 1 + shapes: 2 + percent: 3 + - top left: big circle 4 + - bottom right: big circle 5 + - bottom left to top right: line 6 + abstract1: 7 + - hatched polygon: 8 + - bottom left to left: line 9 + - left to top: curve down 10 + - bottom to bottom left: line 11 + - top to right: line 12 + - right to bottom: line
+209
Cargo.lock
··· 1 + # This file is automatically @generated by Cargo. 2 + # It is not intended for manual editing. 3 + version = 3 4 + 5 + [[package]] 6 + name = "ahash" 7 + version = "0.3.8" 8 + source = "registry+https://github.com/rust-lang/crates.io-index" 9 + checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" 10 + dependencies = [ 11 + "const-random", 12 + ] 13 + 14 + [[package]] 15 + name = "cfg-if" 16 + version = "1.0.0" 17 + source = "registry+https://github.com/rust-lang/crates.io-index" 18 + checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 19 + 20 + [[package]] 21 + name = "chumsky" 22 + version = "0.8.0" 23 + source = "registry+https://github.com/rust-lang/crates.io-index" 24 + checksum = "8d02796e4586c6c41aeb68eae9bfb4558a522c35f1430c14b40136c3706e09e4" 25 + dependencies = [ 26 + "ahash", 27 + ] 28 + 29 + [[package]] 30 + name = "const-random" 31 + version = "0.1.15" 32 + source = "registry+https://github.com/rust-lang/crates.io-index" 33 + checksum = "368a7a772ead6ce7e1de82bfb04c485f3db8ec744f72925af5735e29a22cc18e" 34 + dependencies = [ 35 + "const-random-macro", 36 + "proc-macro-hack", 37 + ] 38 + 39 + [[package]] 40 + name = "const-random-macro" 41 + version = "0.1.15" 42 + source = "registry+https://github.com/rust-lang/crates.io-index" 43 + checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb" 44 + dependencies = [ 45 + "getrandom", 46 + "once_cell", 47 + "proc-macro-hack", 48 + "tiny-keccak", 49 + ] 50 + 51 + [[package]] 52 + name = "crunchy" 53 + version = "0.2.2" 54 + source = "registry+https://github.com/rust-lang/crates.io-index" 55 + checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 56 + 57 + [[package]] 58 + name = "docopt" 59 + version = "1.1.1" 60 + source = "registry+https://github.com/rust-lang/crates.io-index" 61 + checksum = "7f3f119846c823f9eafcf953a8f6ffb6ed69bf6240883261a7f13b634579a51f" 62 + dependencies = [ 63 + "lazy_static", 64 + "regex", 65 + "serde", 66 + "strsim", 67 + ] 68 + 69 + [[package]] 70 + name = "getrandom" 71 + version = "0.2.8" 72 + source = "registry+https://github.com/rust-lang/crates.io-index" 73 + checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" 74 + dependencies = [ 75 + "cfg-if", 76 + "libc", 77 + "wasi", 78 + ] 79 + 80 + [[package]] 81 + name = "lazy_static" 82 + version = "1.4.0" 83 + source = "registry+https://github.com/rust-lang/crates.io-index" 84 + checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 85 + 86 + [[package]] 87 + name = "libc" 88 + version = "0.2.137" 89 + source = "registry+https://github.com/rust-lang/crates.io-index" 90 + checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" 91 + 92 + [[package]] 93 + name = "once_cell" 94 + version = "1.16.0" 95 + source = "registry+https://github.com/rust-lang/crates.io-index" 96 + checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" 97 + 98 + [[package]] 99 + name = "proc-macro-hack" 100 + version = "0.5.19" 101 + source = "registry+https://github.com/rust-lang/crates.io-index" 102 + checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" 103 + 104 + [[package]] 105 + name = "proc-macro2" 106 + version = "1.0.47" 107 + source = "registry+https://github.com/rust-lang/crates.io-index" 108 + checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" 109 + dependencies = [ 110 + "unicode-ident", 111 + ] 112 + 113 + [[package]] 114 + name = "quote" 115 + version = "1.0.21" 116 + source = "registry+https://github.com/rust-lang/crates.io-index" 117 + checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" 118 + dependencies = [ 119 + "proc-macro2", 120 + ] 121 + 122 + [[package]] 123 + name = "regex" 124 + version = "1.7.0" 125 + source = "registry+https://github.com/rust-lang/crates.io-index" 126 + checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" 127 + dependencies = [ 128 + "regex-syntax", 129 + ] 130 + 131 + [[package]] 132 + name = "regex-syntax" 133 + version = "0.6.28" 134 + source = "registry+https://github.com/rust-lang/crates.io-index" 135 + checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" 136 + 137 + [[package]] 138 + name = "serde" 139 + version = "1.0.147" 140 + source = "registry+https://github.com/rust-lang/crates.io-index" 141 + checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" 142 + dependencies = [ 143 + "serde_derive", 144 + ] 145 + 146 + [[package]] 147 + name = "serde_derive" 148 + version = "1.0.147" 149 + source = "registry+https://github.com/rust-lang/crates.io-index" 150 + checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" 151 + dependencies = [ 152 + "proc-macro2", 153 + "quote", 154 + "syn", 155 + ] 156 + 157 + [[package]] 158 + name = "shapemaker" 159 + version = "0.1.0" 160 + dependencies = [ 161 + "chumsky", 162 + "docopt", 163 + "serde", 164 + "svg", 165 + ] 166 + 167 + [[package]] 168 + name = "strsim" 169 + version = "0.10.0" 170 + source = "registry+https://github.com/rust-lang/crates.io-index" 171 + checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 172 + 173 + [[package]] 174 + name = "svg" 175 + version = "0.12.1" 176 + source = "registry+https://github.com/rust-lang/crates.io-index" 177 + checksum = "a6e6ff893392e6a1eb94a210562432c6380cebf09d30962a012a655f7dde2ff8" 178 + 179 + [[package]] 180 + name = "syn" 181 + version = "1.0.103" 182 + source = "registry+https://github.com/rust-lang/crates.io-index" 183 + checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" 184 + dependencies = [ 185 + "proc-macro2", 186 + "quote", 187 + "unicode-ident", 188 + ] 189 + 190 + [[package]] 191 + name = "tiny-keccak" 192 + version = "2.0.2" 193 + source = "registry+https://github.com/rust-lang/crates.io-index" 194 + checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" 195 + dependencies = [ 196 + "crunchy", 197 + ] 198 + 199 + [[package]] 200 + name = "unicode-ident" 201 + version = "1.0.5" 202 + source = "registry+https://github.com/rust-lang/crates.io-index" 203 + checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" 204 + 205 + [[package]] 206 + name = "wasi" 207 + version = "0.11.0+wasi-snapshot-preview1" 208 + source = "registry+https://github.com/rust-lang/crates.io-index" 209 + checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+12
Cargo.toml
··· 1 + [package] 2 + name = "shapemaker" 3 + version = "0.1.0" 4 + edition = "2021" 5 + 6 + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 + 8 + [dependencies] 9 + chumsky = "0.8.0" 10 + docopt = "1.1.1" 11 + serde = "1.0.147" 12 + svg = "0.12.1"
+215
src/main.rs
··· 1 + use std::collections::HashMap; 2 + 3 + use chumsky::prelude::*; 4 + use chumsky::text; 5 + use chumsky::text::{newline, whitespace}; 6 + use docopt::Docopt; 7 + use serde::Deserialize; 8 + 9 + const USAGE: &'static str = " 10 + โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„โ–„ 11 + โ–ˆโ–‘โ–„โ–„โ–ˆโ–‘โ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–„โ–„โ–€โ–ˆโ–€โ–„โ–„โ–€โ–ˆโ–‘โ–„โ–„โ–ˆโ–‘โ–„โ–€โ–„โ–‘โ–ˆโ–‘โ–„โ–„โ–€โ–ˆโ–‘โ–ˆโ–€โ–ˆโ–‘โ–„โ–„โ–ˆโ–‘โ–„โ–„โ–€โ–ˆ 12 + โ–ˆโ–„โ–„โ–€โ–ˆโ–‘โ–„โ–„โ–‘โ–ˆโ–‘โ–€โ–€โ–‘โ–ˆโ–‘โ–€โ–€โ–‘โ–ˆโ–‘โ–„โ–„โ–ˆโ–‘โ–ˆโ–„โ–ˆโ–‘โ–ˆโ–‘โ–€โ–€โ–‘โ–ˆโ–‘โ–„โ–€โ–ˆโ–‘โ–„โ–„โ–ˆโ–‘โ–€โ–€โ–„โ–ˆ 13 + โ–ˆโ–„โ–„โ–„โ–ˆโ–„โ–ˆโ–ˆโ–„โ–ˆโ–„โ–ˆโ–ˆโ–„โ–ˆโ–‘โ–ˆโ–ˆโ–ˆโ–ˆโ–„โ–„โ–„โ–ˆโ–„โ–ˆโ–ˆโ–ˆโ–„โ–ˆโ–„โ–ˆโ–ˆโ–„โ–ˆโ–„โ–ˆโ–„โ–ˆโ–„โ–„โ–„โ–ˆโ–„โ–ˆโ–„โ–„โ–ˆ 14 + โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€ 15 + 16 + Usage: shapemaker [options] <file> 17 + shapemaker (-h | --help) 18 + "; 19 + 20 + #[derive(Debug, Deserialize)] 21 + struct Args { 22 + arg_file: String, 23 + flag_verbose: bool, 24 + } 25 + 26 + fn main() { 27 + let args: Args = Docopt::new(USAGE) 28 + .and_then(|d| d.deserialize()) 29 + .unwrap_or_else(|e| e.exit()); 30 + 31 + let file_contents = std::fs::read_to_string(&args.arg_file).unwrap(); 32 + let shapes: Vec<Shape> = match parser().parse(file_contents) { 33 + Ok(shapes) => { 34 + println!("Parsed shapes: {:#?}", shapes); 35 + shapes 36 + } 37 + Err(e) => { 38 + println!("Error: {:?}", e); 39 + std::process::exit(1); 40 + } 41 + }; 42 + } 43 + 44 + #[derive(Debug)] 45 + struct Shape { 46 + name: String, 47 + objects: Vec<(Object, Option<Fill>)>, 48 + } 49 + 50 + #[derive(Debug)] 51 + enum Object { 52 + Polygon(Vec<Line>), 53 + SmallCircle(Anchor), 54 + Dot(Anchor), 55 + BigCircle(CenterAnchor), 56 + } 57 + 58 + #[derive(Debug, Clone)] 59 + enum Anchor { 60 + Top, 61 + TopRight, 62 + Right, 63 + BottomRight, 64 + Bottom, 65 + BottomLeft, 66 + Left, 67 + TopLeft, 68 + Center, 69 + } 70 + 71 + #[derive(Debug, Clone)] 72 + enum CenterAnchor { 73 + TopLeft, 74 + TopRight, 75 + BottomLeft, 76 + BottomRight, 77 + Center, 78 + } 79 + 80 + #[derive(Debug, Clone)] 81 + enum Line { 82 + Line(Anchor, Anchor), 83 + InwardCurve(Anchor, Anchor), 84 + OutwardCurve(Anchor, Anchor), 85 + } 86 + 87 + #[derive(Debug, Clone)] 88 + enum Fill { 89 + Solid(Color), 90 + Hatched, 91 + Dotted, 92 + } 93 + 94 + #[derive(Debug, Clone)] 95 + enum Color { 96 + Named(ColorName), 97 + RGBA(u8, u8, u8, u8), 98 + } 99 + 100 + #[derive(Debug, Clone)] 101 + enum ColorName { 102 + Black, 103 + White, 104 + Grey, 105 + Red, 106 + Green, 107 + Blue, 108 + Yellow, 109 + Cyan, 110 + Magenta, 111 + Orange, 112 + } 113 + 114 + fn parser() -> impl Parser<char, Vec<Shape>, Error = Simple<char>> { 115 + let anchor = choice(( 116 + just("top").to(Anchor::Top), 117 + just("top right").to(Anchor::TopRight), 118 + just("right").to(Anchor::Right), 119 + just("bottom right").to(Anchor::BottomRight), 120 + just("bottom").to(Anchor::Bottom), 121 + just("bottom left").to(Anchor::BottomLeft), 122 + just("left").to(Anchor::Left), 123 + just("top left").to(Anchor::TopLeft), 124 + just("center").to(Anchor::Center), 125 + )); 126 + let center_anchor = choice(( 127 + just("top left").to(CenterAnchor::TopLeft), 128 + just("top right").to(CenterAnchor::TopRight), 129 + just("bottom left").to(CenterAnchor::BottomLeft), 130 + just("bottom right").to(CenterAnchor::BottomRight), 131 + just("center").to(CenterAnchor::Center), 132 + )); 133 + 134 + let straight_line = anchor 135 + .then_ignore(just("--").padded()) 136 + .then(anchor) 137 + .map(|(a, b)| Line::Line(a, b)); 138 + let inward_curve = anchor 139 + .then_ignore(one_of("n(").padded()) 140 + .then(anchor) 141 + .map(|(a, b)| Line::InwardCurve(a, b)); 142 + let outward_curve = anchor 143 + .then_ignore(one_of("u(").padded()) 144 + .then(anchor) 145 + .map(|(a, b)| Line::OutwardCurve(a, b)); 146 + let line = choice((straight_line, inward_curve, outward_curve)); 147 + let polygon = line.padded().repeated().boxed().map(Object::Polygon); 148 + let point = anchor 149 + .then_ignore(whitespace()) 150 + .then_ignore(just("point")) 151 + .map(Object::SmallCircle); 152 + let circle = center_anchor 153 + .then_ignore(whitespace()) 154 + .then_ignore(just("circle")) 155 + .map(Object::BigCircle); 156 + let dot = anchor 157 + .then_ignore(whitespace()) 158 + .then_ignore(just("dot")) 159 + .map(Object::Dot); 160 + let object = choice((polygon, point, dot, circle)); 161 + let color = choice(( 162 + just("black").to(Color::Named(ColorName::Black)), 163 + just("white").to(Color::Named(ColorName::White)), 164 + just("grey").to(Color::Named(ColorName::Grey)), 165 + just("red").to(Color::Named(ColorName::Red)), 166 + just("green").to(Color::Named(ColorName::Green)), 167 + just("blue").to(Color::Named(ColorName::Blue)), 168 + just("yellow").to(Color::Named(ColorName::Yellow)), 169 + just("cyan").to(Color::Named(ColorName::Cyan)), 170 + just("magenta").to(Color::Named(ColorName::Magenta)), 171 + just("orange").to(Color::Named(ColorName::Orange)), 172 + just("#").ignored().then(text::int(16)).map(|(_, i)| { 173 + Color::RGBA( 174 + ((i >> 24) & 0xFF) as u8, 175 + ((i >> 16) & 0xFF) as u8, 176 + ((i >> 8) & 0xFF) as u8, 177 + (i & 0xFF) as u8, 178 + ) 179 + }), 180 + )); 181 + let fill = choice(( 182 + just("filled with") 183 + .ignored() 184 + .then_ignore(whitespace()) 185 + .then(color) 186 + .map(|(_, c)| Fill::Solid(c)), 187 + just("hatched").to(Fill::Hatched), 188 + just("dotted").to(Fill::Dotted), 189 + )); 190 + let filled_object = just("[") 191 + .padded() 192 + .ignored() 193 + .then(object) 194 + .then_ignore(just("]").padded()) 195 + .then(fill) 196 + .map(|((_, o), f)| (o, Some(f))); 197 + let separator = newline().then_ignore(whitespace()).then_ignore(newline()); 198 + let header = take_until(just(":")) 199 + .then_ignore(whitespace()) 200 + .then_ignore(newline()) 201 + .map(|(i, _)| i); 202 + let shape = header 203 + .then_ignore(whitespace()) 204 + .then( 205 + filled_object 206 + .or(object.map(|o| (o, None))) 207 + .separated_by(newline()), 208 + ) 209 + .map(|(name, objects)| Shape { 210 + name: name.into_iter().collect(), 211 + objects, 212 + }); 213 + 214 + shape.separated_by(separator) 215 + }