pub struct Context { /* private fields */ }
Expand description
§Context
A Context is a drawing context, used to perform operations against a pseudo-canvas. Those operations are later collected up and turned into an SVG, including line strokes, fills, and all the other useful tools that we need to drive a plotter robot.
§Example
use aoer_plotty_rs::context::Context;
let mut ctx = Context::new();
ctx.stroke("black")
.fill("red")
.pen(0.5)
.outline(Some(5.0))
.poly(vec![(0.0,0.0),
(25.0,0.0),
(25.0,25.0),
(0.0,25.0)],
vec![])
.outline(None)
.hatch(135.0)
.stroke("blue")
.fill("yellow")
.circle(12.5,12.5, 5.0)
.push()
.hatch(180.0)
.stroke("red")
.fill("green")
.circle(17.5,12.5,2.5)
.pop().unwrap()
.hatch(0.0)
.clip(true)
.circle(7.5,12.5,2.5)
.clip(false)
.stroke("brown")
.pen(1.0)
.line(0.0, 0.0, 3.0, 3.0)
.pen(0.1)
.outline(Some(1.0))
.stroke("pink")
.line(3.0, 0.0, 0.0, 3.0)
.stroke("purple")
.spline(&vec![(0.0, 25.0), (0.0, 25.0), (10.0, 20.0), (20.0,25.0), (25.0, 25.0)],
8, 0.5)
.push() // Prepare for this transformation stuff...
.transform(Some(
&(Context::translate_matrix(25.0, 25.0)
* Context::rotate_matrix(45.0)
* Context::scale_matrix(1.0, 0.5)
))) // Holy crap we can multiply these?! ;)
.stroke("cyan")
.circle(0.0, 0.0, 8.0)
.pop().unwrap() // We're back to purple and regular coords
.outline(None)
.stroke("green")
.regular_poly(8, 80.0, 80.0, 20.0, 0.0)
.star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
;
Implementations§
Source§impl Context
impl Context
Sourcepub fn accuracy(&mut self, accuracy: f64) -> &mut Self
pub fn accuracy(&mut self, accuracy: f64) -> &mut Self
Set accuracy (allowed tolerance) in mm
Examples found in repository?
45 fn generate(&self) -> AOERCTX {
46 let mut ctx = AOERCTX::new();
47 let mut count = 0;
48
49 ctx.pen(1.5).accuracy(0.3);
50 if self.settings.draft {
51 ctx.pattern(Hatches::none());
52 } else {
53 ctx.pattern(Hatches::line());
54 }
55 let mut typo = Typography::new();
56 typo.size(4.5).align(Center);
57
58 for (name, geo) in CarlsonSmithTruchet::full_set()
59 .iter()
60 .filter(|(x, _y)| !x.starts_with("^"))
61 {
62 println!("Plotting {}", name);
63 let yofs: f64 = -256.0f64 + 128.0f64 * <f64 as From<i32>>::from((count / 6) as i32);
64 let xofs: f64 = -512.0f64 + 96.0f64 * <f64 as From<i32>>::from((count % 6) as i32);
65 // println!("xy is {},{}", xofs, yofs);
66 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(64.0, 64.0);
67 count += 1;
68 ctx.transform(Some(&tx)).geometry(&geo);
69 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(1.0, -1.0);
70
71 ctx.transform(Some(&tx)).typography(&name, 0.0, 60.0, &typo);
72 }
73 count = 0;
74 for (name, geo) in self
75 .full_set
76 .clone()
77 .iter()
78 .filter(|(x, _y)| x.starts_with("^"))
79 {
80 println!("Plotting inverse scale/2 {}", name);
81 let yofs: f64 =
82 -256.0f64 - 16.0f64 + 128.0f64 * <f64 as From<i32>>::from((count / 6) as i32);
83 let xofs: f64 = -512.0f64
84 + (96.0f64 * 6.0f64)
85 + 96.0f64 * <f64 as From<i32>>::from((count % 6) as i32);
86 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(32.0, 32.0);
87 count += 1;
88 ctx.transform(Some(&tx)).geometry(&geo);
89 ctx.transform(Some(&tx)).geometry(&geo);
90 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(1.0, -1.0);
91
92 ctx.transform(Some(&tx)).typography(&name, 0.0, 40.0, &typo);
93 }
94 ctx
95 }
Sourcepub fn default_font() -> Font
pub fn default_font() -> Font
Default font
Sourcepub fn finalize_arrangement(
&self,
arrangement: &Arrangement<f64>,
) -> Arrangement<f64>
pub fn finalize_arrangement( &self, arrangement: &Arrangement<f64>, ) -> Arrangement<f64>
Finalize Arrangement
Examples found in repository?
8fn main() {
9 let pen_width = 0.3;
10 let cols = 23;
11 let rows = 16;
12 let size = (cols * rows) / 2;
13 let days = 365;
14 let cellw = f64::from(size) / f64::from(cols);
15 let cellh = f64::from(size) / f64::from(rows);
16
17 let mut ctx = Context::new();
18
19 // Set the default stroke/hatch/pen.
20 ctx.stroke("black")
21 .hatch(45.0)
22 .pen(pen_width)
23 .pattern(Hatches::line())
24 .fill("black");
25
26 for day in 0..days {
27 let col = f64::from(day / rows);
28 let row = f64::from(day % rows);
29 let x = col * cellw;
30 let y = row * cellh;
31 let w = 2.0f64;
32 let h = 30.0f64;
33
34 let phi = (f64::from(day) / f64::from(days)) * PI;
35 let theta = phi.sin() * 80.0 + 45.0;
36
37 // We scale w and h by the scale here because of implementation differences
38 // between JS canvas context and our context.
39 let scale = phi.cos().abs() * 2.0 + 1.0;
40 let w = scale * w;
41 let h = scale * h;
42
43 ctx.push()
44 .transform(Some(&(Context::translate_matrix(x, y))))
45 .mask_box(cellw * -0.5, cellh * -0.5, cellw * 0.5, cellh * 0.5)
46 .transform(Some(
47 &(Context::translate_matrix(x, y) * Context::rotate_matrix(theta)),
48 ))
49 .hatch(-90.0 + theta)
50 .rect(w * -0.5, h * -0.5, w * 0.5, h * 0.5)
51 .pop()
52 .expect("Somehow lost track of my internal stack");
53 }
54
55 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
56 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
57 // to match the context's bounds, giving us back an Arrangement::Transform with the
58 // affine txform that gives us a nicely centered drawing.
59 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
60 25.4,
61 Context::viewbox(0.0, 0.0, 216.0, 216.0),
62 false,
63 ));
64
65 let document = ctx.to_svg(&arrangement).unwrap();
66
67 // Write it to the images folder, so we can use it as an example!
68 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
69 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
70 svg::save(format!("images/{}.svg", fname), &document).unwrap();
71}
More examples
56fn main() {
57 let pen_width = 0.5f64;
58 let size: i32 = 224;
59 let square_count = 8;
60 let white = "#F2F5F1";
61 let colors = vec!["#D40920", "#1356A2", "#F7D842"];
62 let square_weight = 2.0f64; // How thick the dividing lines are
63
64 // We're using a static random generator here so that our SVG files
65 // don't get regenerated every time we run the examples.
66 let mut rng = SmallRng::seed_from_u64(1234567);
67 let mut ctx = Context::new();
68
69 let mut squares: Vec<Rect<f64>> = vec![Rect::new(
70 coord! {x:0.0, y:0.0},
71 coord! {x: f64::from(size), y: f64::from(size)},
72 )];
73
74 // split_squares_at(&mut squares, coord!{x: f64::from(size)/2.0, y: -1.0});
75 // split_squares_at(&mut squares, coord!{x:-1.0, y: f64::from(size)/2.0});
76 for i in (0..(size)).step_by((size / square_count) as usize) {
77 split_squares_at(&mut squares, coord! {x: f64::from(i), y: -1.0}, &mut rng);
78 split_squares_at(&mut squares, coord! {x:-1.0, y: f64::from(i)}, &mut rng);
79 }
80
81 // Create an array of the same length as the squares array, and fill it with "white"
82 let mut square_colors: Vec<&str> = squares.iter().map(|_s| white.clone()).collect();
83
84 for color in colors.clone() {
85 // Note, this might overlap an existing colored square. More often than you'd think actually.
86 square_colors[rng.gen_range(0..squares.len())] = color;
87 }
88
89 // Set the default stroke/hatch/pen.
90 ctx.stroke("black").hatch(45.0).pen(pen_width);
91
92 // for square in squares {
93 for i in 0..squares.len() {
94 let square = squares[i].clone();
95 let color = square_colors[i].clone();
96
97 // Don't bother hatching if it's white.
98 if color != white {
99 ctx.pattern(Hatches::line());
100 } else {
101 ctx.pattern(Hatches::none());
102 }
103
104 // And set the fill color.
105 ctx.fill(color).rect(
106 square.min().x + square_weight,
107 square.min().y + square_weight,
108 square.max().x - square_weight,
109 square.max().y - square_weight,
110 );
111
112 // Now we just draw the rest of the outlines, inside to outside, no fill.
113 ctx.pattern(Hatches::none());
114 let mut remaining_width = square_weight - (pen_width / 2.0);
115 let s = squares[i].clone();
116 while remaining_width >= 0.0 {
117 ctx.geometry(&Geometry::Rect(Rect::new(
118 coord! {x: &s.min().x+remaining_width, y: &s.min().y+remaining_width},
119 coord! {x: &s.max().x-remaining_width, y: &s.max().y-remaining_width},
120 )));
121 remaining_width -= pen_width;
122 }
123 }
124
125 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
126 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
127 // to match the context's bounds, giving us back an Arrangement::Transform with the
128 // affine txform that gives us a nicely centered drawing.
129 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
130 25.4,
131 Context::viewbox(0.0, 0.0, 216.0, 216.0),
132 false,
133 ));
134
135 let document = ctx.to_svg(&arrangement).unwrap();
136
137 // Write it to the images folder, so we can use it as an example!
138 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
139 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
140 svg::save(format!("images/{}.svg", fname), &document).unwrap();
141}
Sourcepub fn viewbox(x0: f64, y0: f64, x1: f64, y1: f64) -> Rect<f64>
pub fn viewbox(x0: f64, y0: f64, x1: f64, y1: f64) -> Rect<f64>
Viewbox helper. Useful to create an arbitrary viewbox for your SVGs.
Examples found in repository?
8fn main() {
9 let pen_width = 0.3;
10 let cols = 23;
11 let rows = 16;
12 let size = (cols * rows) / 2;
13 let days = 365;
14 let cellw = f64::from(size) / f64::from(cols);
15 let cellh = f64::from(size) / f64::from(rows);
16
17 let mut ctx = Context::new();
18
19 // Set the default stroke/hatch/pen.
20 ctx.stroke("black")
21 .hatch(45.0)
22 .pen(pen_width)
23 .pattern(Hatches::line())
24 .fill("black");
25
26 for day in 0..days {
27 let col = f64::from(day / rows);
28 let row = f64::from(day % rows);
29 let x = col * cellw;
30 let y = row * cellh;
31 let w = 2.0f64;
32 let h = 30.0f64;
33
34 let phi = (f64::from(day) / f64::from(days)) * PI;
35 let theta = phi.sin() * 80.0 + 45.0;
36
37 // We scale w and h by the scale here because of implementation differences
38 // between JS canvas context and our context.
39 let scale = phi.cos().abs() * 2.0 + 1.0;
40 let w = scale * w;
41 let h = scale * h;
42
43 ctx.push()
44 .transform(Some(&(Context::translate_matrix(x, y))))
45 .mask_box(cellw * -0.5, cellh * -0.5, cellw * 0.5, cellh * 0.5)
46 .transform(Some(
47 &(Context::translate_matrix(x, y) * Context::rotate_matrix(theta)),
48 ))
49 .hatch(-90.0 + theta)
50 .rect(w * -0.5, h * -0.5, w * 0.5, h * 0.5)
51 .pop()
52 .expect("Somehow lost track of my internal stack");
53 }
54
55 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
56 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
57 // to match the context's bounds, giving us back an Arrangement::Transform with the
58 // affine txform that gives us a nicely centered drawing.
59 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
60 25.4,
61 Context::viewbox(0.0, 0.0, 216.0, 216.0),
62 false,
63 ));
64
65 let document = ctx.to_svg(&arrangement).unwrap();
66
67 // Write it to the images folder, so we can use it as an example!
68 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
69 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
70 svg::save(format!("images/{}.svg", fname), &document).unwrap();
71}
More examples
56fn main() {
57 let pen_width = 0.5f64;
58 let size: i32 = 224;
59 let square_count = 8;
60 let white = "#F2F5F1";
61 let colors = vec!["#D40920", "#1356A2", "#F7D842"];
62 let square_weight = 2.0f64; // How thick the dividing lines are
63
64 // We're using a static random generator here so that our SVG files
65 // don't get regenerated every time we run the examples.
66 let mut rng = SmallRng::seed_from_u64(1234567);
67 let mut ctx = Context::new();
68
69 let mut squares: Vec<Rect<f64>> = vec![Rect::new(
70 coord! {x:0.0, y:0.0},
71 coord! {x: f64::from(size), y: f64::from(size)},
72 )];
73
74 // split_squares_at(&mut squares, coord!{x: f64::from(size)/2.0, y: -1.0});
75 // split_squares_at(&mut squares, coord!{x:-1.0, y: f64::from(size)/2.0});
76 for i in (0..(size)).step_by((size / square_count) as usize) {
77 split_squares_at(&mut squares, coord! {x: f64::from(i), y: -1.0}, &mut rng);
78 split_squares_at(&mut squares, coord! {x:-1.0, y: f64::from(i)}, &mut rng);
79 }
80
81 // Create an array of the same length as the squares array, and fill it with "white"
82 let mut square_colors: Vec<&str> = squares.iter().map(|_s| white.clone()).collect();
83
84 for color in colors.clone() {
85 // Note, this might overlap an existing colored square. More often than you'd think actually.
86 square_colors[rng.gen_range(0..squares.len())] = color;
87 }
88
89 // Set the default stroke/hatch/pen.
90 ctx.stroke("black").hatch(45.0).pen(pen_width);
91
92 // for square in squares {
93 for i in 0..squares.len() {
94 let square = squares[i].clone();
95 let color = square_colors[i].clone();
96
97 // Don't bother hatching if it's white.
98 if color != white {
99 ctx.pattern(Hatches::line());
100 } else {
101 ctx.pattern(Hatches::none());
102 }
103
104 // And set the fill color.
105 ctx.fill(color).rect(
106 square.min().x + square_weight,
107 square.min().y + square_weight,
108 square.max().x - square_weight,
109 square.max().y - square_weight,
110 );
111
112 // Now we just draw the rest of the outlines, inside to outside, no fill.
113 ctx.pattern(Hatches::none());
114 let mut remaining_width = square_weight - (pen_width / 2.0);
115 let s = squares[i].clone();
116 while remaining_width >= 0.0 {
117 ctx.geometry(&Geometry::Rect(Rect::new(
118 coord! {x: &s.min().x+remaining_width, y: &s.min().y+remaining_width},
119 coord! {x: &s.max().x-remaining_width, y: &s.max().y-remaining_width},
120 )));
121 remaining_width -= pen_width;
122 }
123 }
124
125 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
126 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
127 // to match the context's bounds, giving us back an Arrangement::Transform with the
128 // affine txform that gives us a nicely centered drawing.
129 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
130 25.4,
131 Context::viewbox(0.0, 0.0, 216.0, 216.0),
132 false,
133 ));
134
135 let document = ctx.to_svg(&arrangement).unwrap();
136
137 // Write it to the images folder, so we can use it as an example!
138 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
139 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
140 svg::save(format!("images/{}.svg", fname), &document).unwrap();
141}
Sourcepub fn scale_matrix(sx: f64, sy: f64) -> Affine2<f64>
pub fn scale_matrix(sx: f64, sy: f64) -> Affine2<f64>
Helper to create a scaling matrix
Examples found in repository?
45 fn generate(&self) -> AOERCTX {
46 let mut ctx = AOERCTX::new();
47 let mut count = 0;
48
49 ctx.pen(1.5).accuracy(0.3);
50 if self.settings.draft {
51 ctx.pattern(Hatches::none());
52 } else {
53 ctx.pattern(Hatches::line());
54 }
55 let mut typo = Typography::new();
56 typo.size(4.5).align(Center);
57
58 for (name, geo) in CarlsonSmithTruchet::full_set()
59 .iter()
60 .filter(|(x, _y)| !x.starts_with("^"))
61 {
62 println!("Plotting {}", name);
63 let yofs: f64 = -256.0f64 + 128.0f64 * <f64 as From<i32>>::from((count / 6) as i32);
64 let xofs: f64 = -512.0f64 + 96.0f64 * <f64 as From<i32>>::from((count % 6) as i32);
65 // println!("xy is {},{}", xofs, yofs);
66 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(64.0, 64.0);
67 count += 1;
68 ctx.transform(Some(&tx)).geometry(&geo);
69 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(1.0, -1.0);
70
71 ctx.transform(Some(&tx)).typography(&name, 0.0, 60.0, &typo);
72 }
73 count = 0;
74 for (name, geo) in self
75 .full_set
76 .clone()
77 .iter()
78 .filter(|(x, _y)| x.starts_with("^"))
79 {
80 println!("Plotting inverse scale/2 {}", name);
81 let yofs: f64 =
82 -256.0f64 - 16.0f64 + 128.0f64 * <f64 as From<i32>>::from((count / 6) as i32);
83 let xofs: f64 = -512.0f64
84 + (96.0f64 * 6.0f64)
85 + 96.0f64 * <f64 as From<i32>>::from((count % 6) as i32);
86 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(32.0, 32.0);
87 count += 1;
88 ctx.transform(Some(&tx)).geometry(&geo);
89 ctx.transform(Some(&tx)).geometry(&geo);
90 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(1.0, -1.0);
91
92 ctx.transform(Some(&tx)).typography(&name, 0.0, 40.0, &typo);
93 }
94 ctx
95 }
More examples
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
Sourcepub fn unit_matrix() -> Affine2<f64>
pub fn unit_matrix() -> Affine2<f64>
Unit matrix. Basically a no-op
Sourcepub fn translate_matrix(tx: f64, ty: f64) -> Affine2<f64>
pub fn translate_matrix(tx: f64, ty: f64) -> Affine2<f64>
Helper to create a translation matrix
Examples found in repository?
45 fn generate(&self) -> AOERCTX {
46 let mut ctx = AOERCTX::new();
47 let mut count = 0;
48
49 ctx.pen(1.5).accuracy(0.3);
50 if self.settings.draft {
51 ctx.pattern(Hatches::none());
52 } else {
53 ctx.pattern(Hatches::line());
54 }
55 let mut typo = Typography::new();
56 typo.size(4.5).align(Center);
57
58 for (name, geo) in CarlsonSmithTruchet::full_set()
59 .iter()
60 .filter(|(x, _y)| !x.starts_with("^"))
61 {
62 println!("Plotting {}", name);
63 let yofs: f64 = -256.0f64 + 128.0f64 * <f64 as From<i32>>::from((count / 6) as i32);
64 let xofs: f64 = -512.0f64 + 96.0f64 * <f64 as From<i32>>::from((count % 6) as i32);
65 // println!("xy is {},{}", xofs, yofs);
66 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(64.0, 64.0);
67 count += 1;
68 ctx.transform(Some(&tx)).geometry(&geo);
69 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(1.0, -1.0);
70
71 ctx.transform(Some(&tx)).typography(&name, 0.0, 60.0, &typo);
72 }
73 count = 0;
74 for (name, geo) in self
75 .full_set
76 .clone()
77 .iter()
78 .filter(|(x, _y)| x.starts_with("^"))
79 {
80 println!("Plotting inverse scale/2 {}", name);
81 let yofs: f64 =
82 -256.0f64 - 16.0f64 + 128.0f64 * <f64 as From<i32>>::from((count / 6) as i32);
83 let xofs: f64 = -512.0f64
84 + (96.0f64 * 6.0f64)
85 + 96.0f64 * <f64 as From<i32>>::from((count % 6) as i32);
86 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(32.0, 32.0);
87 count += 1;
88 ctx.transform(Some(&tx)).geometry(&geo);
89 ctx.transform(Some(&tx)).geometry(&geo);
90 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(1.0, -1.0);
91
92 ctx.transform(Some(&tx)).typography(&name, 0.0, 40.0, &typo);
93 }
94 ctx
95 }
More examples
8fn main() {
9 let pen_width = 0.3;
10 let cols = 23;
11 let rows = 16;
12 let size = (cols * rows) / 2;
13 let days = 365;
14 let cellw = f64::from(size) / f64::from(cols);
15 let cellh = f64::from(size) / f64::from(rows);
16
17 let mut ctx = Context::new();
18
19 // Set the default stroke/hatch/pen.
20 ctx.stroke("black")
21 .hatch(45.0)
22 .pen(pen_width)
23 .pattern(Hatches::line())
24 .fill("black");
25
26 for day in 0..days {
27 let col = f64::from(day / rows);
28 let row = f64::from(day % rows);
29 let x = col * cellw;
30 let y = row * cellh;
31 let w = 2.0f64;
32 let h = 30.0f64;
33
34 let phi = (f64::from(day) / f64::from(days)) * PI;
35 let theta = phi.sin() * 80.0 + 45.0;
36
37 // We scale w and h by the scale here because of implementation differences
38 // between JS canvas context and our context.
39 let scale = phi.cos().abs() * 2.0 + 1.0;
40 let w = scale * w;
41 let h = scale * h;
42
43 ctx.push()
44 .transform(Some(&(Context::translate_matrix(x, y))))
45 .mask_box(cellw * -0.5, cellh * -0.5, cellw * 0.5, cellh * 0.5)
46 .transform(Some(
47 &(Context::translate_matrix(x, y) * Context::rotate_matrix(theta)),
48 ))
49 .hatch(-90.0 + theta)
50 .rect(w * -0.5, h * -0.5, w * 0.5, h * 0.5)
51 .pop()
52 .expect("Somehow lost track of my internal stack");
53 }
54
55 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
56 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
57 // to match the context's bounds, giving us back an Arrangement::Transform with the
58 // affine txform that gives us a nicely centered drawing.
59 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
60 25.4,
61 Context::viewbox(0.0, 0.0, 216.0, 216.0),
62 false,
63 ));
64
65 let document = ctx.to_svg(&arrangement).unwrap();
66
67 // Write it to the images folder, so we can use it as an example!
68 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
69 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
70 svg::save(format!("images/{}.svg", fname), &document).unwrap();
71}
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
Sourcepub fn rotate_matrix(degrees: f64) -> Affine2<f64>
pub fn rotate_matrix(degrees: f64) -> Affine2<f64>
Angle is in degrees because I am a terrible person. Also, compass degrees. For an SVG anyhow. I am a bastard.
Examples found in repository?
8fn main() {
9 let pen_width = 0.3;
10 let cols = 23;
11 let rows = 16;
12 let size = (cols * rows) / 2;
13 let days = 365;
14 let cellw = f64::from(size) / f64::from(cols);
15 let cellh = f64::from(size) / f64::from(rows);
16
17 let mut ctx = Context::new();
18
19 // Set the default stroke/hatch/pen.
20 ctx.stroke("black")
21 .hatch(45.0)
22 .pen(pen_width)
23 .pattern(Hatches::line())
24 .fill("black");
25
26 for day in 0..days {
27 let col = f64::from(day / rows);
28 let row = f64::from(day % rows);
29 let x = col * cellw;
30 let y = row * cellh;
31 let w = 2.0f64;
32 let h = 30.0f64;
33
34 let phi = (f64::from(day) / f64::from(days)) * PI;
35 let theta = phi.sin() * 80.0 + 45.0;
36
37 // We scale w and h by the scale here because of implementation differences
38 // between JS canvas context and our context.
39 let scale = phi.cos().abs() * 2.0 + 1.0;
40 let w = scale * w;
41 let h = scale * h;
42
43 ctx.push()
44 .transform(Some(&(Context::translate_matrix(x, y))))
45 .mask_box(cellw * -0.5, cellh * -0.5, cellw * 0.5, cellh * 0.5)
46 .transform(Some(
47 &(Context::translate_matrix(x, y) * Context::rotate_matrix(theta)),
48 ))
49 .hatch(-90.0 + theta)
50 .rect(w * -0.5, h * -0.5, w * 0.5, h * 0.5)
51 .pop()
52 .expect("Somehow lost track of my internal stack");
53 }
54
55 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
56 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
57 // to match the context's bounds, giving us back an Arrangement::Transform with the
58 // affine txform that gives us a nicely centered drawing.
59 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
60 25.4,
61 Context::viewbox(0.0, 0.0, 216.0, 216.0),
62 false,
63 ));
64
65 let document = ctx.to_svg(&arrangement).unwrap();
66
67 // Write it to the images folder, so we can use it as an example!
68 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
69 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
70 svg::save(format!("images/{}.svg", fname), &document).unwrap();
71}
More examples
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
Sourcepub fn new() -> Context
pub fn new() -> Context
I can haz a new default drawing context?
Examples found in repository?
8fn main() {
9 let mut ctx = Context::new();
10 let mut typ = Typography::new();
11 typ.size(2.0);
12 typ.close(true);
13
14 ctx.stroke("black")
15 .fill("red")
16 .pen(0.5)
17 .pattern(Hatches::none())
18 // .pattern(LineHatch::gen())
19 // .typography(&"i".to_string(), 50.0, 50.0, &typ);
20 .typography(&"Left".to_string(), 50.0, 50.0, &typ);
21 typ.align(TextAlignment::Right);
22 ctx.typography(&"Right".to_string(), 50.0, 90.0, &typ);
23 typ.align(TextAlignment::Center);
24 ctx.typography(&"Center".to_string(), 50.0, 70.0, &typ);
25
26 let svg = ctx
27 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
28 coord! {x:0.0, y:0.0},
29 coord! {x:100.0, y:100.0},
30 )))
31 .unwrap();
32 // Write it to the images folder, so we can use it as an example!
33 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
34 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
35 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
36}
More examples
27 fn generate(&mut self) {
28 let /*mut*/ _ctx = Context::new();
29 let mut fibval = 1;
30 let mut lastfib = 0;
31 let mut angle = 0.0f64;
32
33 for _i in 0..self.settings.fibdepth {
34 let scale = self.settings.scale * (<f64 as From<i32>>::from(fibval));
35 // let translation = Context::translate_matrix(scale, scale) * Context::rotate_matrix(angle);
36 let _origin = coord! {
37 x: scale*(angle*(PI/180.0)).cos(),
38 y: scale*(angle*(PI/180.0)).sin()
39 };
40 // let base_scale = 2.0f64 * (f64::from(fibval)/2.0).floor();
41 let base_scale = 2.0f64.pow(<f64 as From<i32>>::from(fibval).log2().floor());
42 println!(
43 "FIB {} would have a base_scale of {} with a rootval of {} and logval of {}",
44 fibval,
45 base_scale,
46 <f64 as From<i32>>::from(fibval).log2().floor(),
47 f64::from(fibval).log2()
48 );
49
50 let tmp = fibval;
51 fibval = fibval + lastfib;
52 lastfib = tmp;
53 angle += 90.0;
54 }
55 }
45 fn generate(&self) -> AOERCTX {
46 let mut ctx = AOERCTX::new();
47 let mut count = 0;
48
49 ctx.pen(1.5).accuracy(0.3);
50 if self.settings.draft {
51 ctx.pattern(Hatches::none());
52 } else {
53 ctx.pattern(Hatches::line());
54 }
55 let mut typo = Typography::new();
56 typo.size(4.5).align(Center);
57
58 for (name, geo) in CarlsonSmithTruchet::full_set()
59 .iter()
60 .filter(|(x, _y)| !x.starts_with("^"))
61 {
62 println!("Plotting {}", name);
63 let yofs: f64 = -256.0f64 + 128.0f64 * <f64 as From<i32>>::from((count / 6) as i32);
64 let xofs: f64 = -512.0f64 + 96.0f64 * <f64 as From<i32>>::from((count % 6) as i32);
65 // println!("xy is {},{}", xofs, yofs);
66 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(64.0, 64.0);
67 count += 1;
68 ctx.transform(Some(&tx)).geometry(&geo);
69 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(1.0, -1.0);
70
71 ctx.transform(Some(&tx)).typography(&name, 0.0, 60.0, &typo);
72 }
73 count = 0;
74 for (name, geo) in self
75 .full_set
76 .clone()
77 .iter()
78 .filter(|(x, _y)| x.starts_with("^"))
79 {
80 println!("Plotting inverse scale/2 {}", name);
81 let yofs: f64 =
82 -256.0f64 - 16.0f64 + 128.0f64 * <f64 as From<i32>>::from((count / 6) as i32);
83 let xofs: f64 = -512.0f64
84 + (96.0f64 * 6.0f64)
85 + 96.0f64 * <f64 as From<i32>>::from((count % 6) as i32);
86 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(32.0, 32.0);
87 count += 1;
88 ctx.transform(Some(&tx)).geometry(&geo);
89 ctx.transform(Some(&tx)).geometry(&geo);
90 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(1.0, -1.0);
91
92 ctx.transform(Some(&tx)).typography(&name, 0.0, 40.0, &typo);
93 }
94 ctx
95 }
8fn main() {
9 let pen_width = 0.3;
10 let cols = 23;
11 let rows = 16;
12 let size = (cols * rows) / 2;
13 let days = 365;
14 let cellw = f64::from(size) / f64::from(cols);
15 let cellh = f64::from(size) / f64::from(rows);
16
17 let mut ctx = Context::new();
18
19 // Set the default stroke/hatch/pen.
20 ctx.stroke("black")
21 .hatch(45.0)
22 .pen(pen_width)
23 .pattern(Hatches::line())
24 .fill("black");
25
26 for day in 0..days {
27 let col = f64::from(day / rows);
28 let row = f64::from(day % rows);
29 let x = col * cellw;
30 let y = row * cellh;
31 let w = 2.0f64;
32 let h = 30.0f64;
33
34 let phi = (f64::from(day) / f64::from(days)) * PI;
35 let theta = phi.sin() * 80.0 + 45.0;
36
37 // We scale w and h by the scale here because of implementation differences
38 // between JS canvas context and our context.
39 let scale = phi.cos().abs() * 2.0 + 1.0;
40 let w = scale * w;
41 let h = scale * h;
42
43 ctx.push()
44 .transform(Some(&(Context::translate_matrix(x, y))))
45 .mask_box(cellw * -0.5, cellh * -0.5, cellw * 0.5, cellh * 0.5)
46 .transform(Some(
47 &(Context::translate_matrix(x, y) * Context::rotate_matrix(theta)),
48 ))
49 .hatch(-90.0 + theta)
50 .rect(w * -0.5, h * -0.5, w * 0.5, h * 0.5)
51 .pop()
52 .expect("Somehow lost track of my internal stack");
53 }
54
55 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
56 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
57 // to match the context's bounds, giving us back an Arrangement::Transform with the
58 // affine txform that gives us a nicely centered drawing.
59 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
60 25.4,
61 Context::viewbox(0.0, 0.0, 216.0, 216.0),
62 false,
63 ));
64
65 let document = ctx.to_svg(&arrangement).unwrap();
66
67 // Write it to the images folder, so we can use it as an example!
68 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
69 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
70 svg::save(format!("images/{}.svg", fname), &document).unwrap();
71}
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
56fn main() {
57 let pen_width = 0.5f64;
58 let size: i32 = 224;
59 let square_count = 8;
60 let white = "#F2F5F1";
61 let colors = vec!["#D40920", "#1356A2", "#F7D842"];
62 let square_weight = 2.0f64; // How thick the dividing lines are
63
64 // We're using a static random generator here so that our SVG files
65 // don't get regenerated every time we run the examples.
66 let mut rng = SmallRng::seed_from_u64(1234567);
67 let mut ctx = Context::new();
68
69 let mut squares: Vec<Rect<f64>> = vec![Rect::new(
70 coord! {x:0.0, y:0.0},
71 coord! {x: f64::from(size), y: f64::from(size)},
72 )];
73
74 // split_squares_at(&mut squares, coord!{x: f64::from(size)/2.0, y: -1.0});
75 // split_squares_at(&mut squares, coord!{x:-1.0, y: f64::from(size)/2.0});
76 for i in (0..(size)).step_by((size / square_count) as usize) {
77 split_squares_at(&mut squares, coord! {x: f64::from(i), y: -1.0}, &mut rng);
78 split_squares_at(&mut squares, coord! {x:-1.0, y: f64::from(i)}, &mut rng);
79 }
80
81 // Create an array of the same length as the squares array, and fill it with "white"
82 let mut square_colors: Vec<&str> = squares.iter().map(|_s| white.clone()).collect();
83
84 for color in colors.clone() {
85 // Note, this might overlap an existing colored square. More often than you'd think actually.
86 square_colors[rng.gen_range(0..squares.len())] = color;
87 }
88
89 // Set the default stroke/hatch/pen.
90 ctx.stroke("black").hatch(45.0).pen(pen_width);
91
92 // for square in squares {
93 for i in 0..squares.len() {
94 let square = squares[i].clone();
95 let color = square_colors[i].clone();
96
97 // Don't bother hatching if it's white.
98 if color != white {
99 ctx.pattern(Hatches::line());
100 } else {
101 ctx.pattern(Hatches::none());
102 }
103
104 // And set the fill color.
105 ctx.fill(color).rect(
106 square.min().x + square_weight,
107 square.min().y + square_weight,
108 square.max().x - square_weight,
109 square.max().y - square_weight,
110 );
111
112 // Now we just draw the rest of the outlines, inside to outside, no fill.
113 ctx.pattern(Hatches::none());
114 let mut remaining_width = square_weight - (pen_width / 2.0);
115 let s = squares[i].clone();
116 while remaining_width >= 0.0 {
117 ctx.geometry(&Geometry::Rect(Rect::new(
118 coord! {x: &s.min().x+remaining_width, y: &s.min().y+remaining_width},
119 coord! {x: &s.max().x-remaining_width, y: &s.max().y-remaining_width},
120 )));
121 remaining_width -= pen_width;
122 }
123 }
124
125 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
126 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
127 // to match the context's bounds, giving us back an Arrangement::Transform with the
128 // affine txform that gives us a nicely centered drawing.
129 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
130 25.4,
131 Context::viewbox(0.0, 0.0, 216.0, 216.0),
132 false,
133 ));
134
135 let document = ctx.to_svg(&arrangement).unwrap();
136
137 // Write it to the images folder, so we can use it as an example!
138 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
139 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
140 svg::save(format!("images/{}.svg", fname), &document).unwrap();
141}
Sourcepub fn bounds(&self) -> Result<Rect<f64>, Box<dyn Error>>
pub fn bounds(&self) -> Result<Rect<f64>, Box<dyn Error>>
Bounds returns a Rect defining the bounds of all operations drawn on the context. Note: Since this has to iterate over ALL geometry in the drawing, it’s kind of expensive. I’ll probably cache this per operation at some point, but for now it’s pricy.
Sourcepub fn mask_poly(
&mut self,
exterior: Vec<(f64, f64)>,
interiors: Vec<Vec<(f64, f64)>>,
) -> &mut Self
pub fn mask_poly( &mut self, exterior: Vec<(f64, f64)>, interiors: Vec<Vec<(f64, f64)>>, ) -> &mut Self
Masks any further operations with a clipping polygon. Only items inside the clipping poly will be used.
Sourcepub fn mask_box(&mut self, x0: f64, y0: f64, x1: f64, y1: f64) -> &mut Self
pub fn mask_box(&mut self, x0: f64, y0: f64, x1: f64, y1: f64) -> &mut Self
Examples found in repository?
8fn main() {
9 let pen_width = 0.3;
10 let cols = 23;
11 let rows = 16;
12 let size = (cols * rows) / 2;
13 let days = 365;
14 let cellw = f64::from(size) / f64::from(cols);
15 let cellh = f64::from(size) / f64::from(rows);
16
17 let mut ctx = Context::new();
18
19 // Set the default stroke/hatch/pen.
20 ctx.stroke("black")
21 .hatch(45.0)
22 .pen(pen_width)
23 .pattern(Hatches::line())
24 .fill("black");
25
26 for day in 0..days {
27 let col = f64::from(day / rows);
28 let row = f64::from(day % rows);
29 let x = col * cellw;
30 let y = row * cellh;
31 let w = 2.0f64;
32 let h = 30.0f64;
33
34 let phi = (f64::from(day) / f64::from(days)) * PI;
35 let theta = phi.sin() * 80.0 + 45.0;
36
37 // We scale w and h by the scale here because of implementation differences
38 // between JS canvas context and our context.
39 let scale = phi.cos().abs() * 2.0 + 1.0;
40 let w = scale * w;
41 let h = scale * h;
42
43 ctx.push()
44 .transform(Some(&(Context::translate_matrix(x, y))))
45 .mask_box(cellw * -0.5, cellh * -0.5, cellw * 0.5, cellh * 0.5)
46 .transform(Some(
47 &(Context::translate_matrix(x, y) * Context::rotate_matrix(theta)),
48 ))
49 .hatch(-90.0 + theta)
50 .rect(w * -0.5, h * -0.5, w * 0.5, h * 0.5)
51 .pop()
52 .expect("Somehow lost track of my internal stack");
53 }
54
55 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
56 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
57 // to match the context's bounds, giving us back an Arrangement::Transform with the
58 // affine txform that gives us a nicely centered drawing.
59 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
60 25.4,
61 Context::viewbox(0.0, 0.0, 216.0, 216.0),
62 false,
63 ));
64
65 let document = ctx.to_svg(&arrangement).unwrap();
66
67 // Write it to the images folder, so we can use it as an example!
68 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
69 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
70 svg::save(format!("images/{}.svg", fname), &document).unwrap();
71}
Sourcepub fn set_mask(&mut self, mask: &Option<Geometry<f64>>) -> &mut Self
pub fn set_mask(&mut self, mask: &Option<Geometry<f64>>) -> &mut Self
Sets the mask to Geometry, or None.
Sourcepub fn push(&mut self) -> &mut Self
pub fn push(&mut self) -> &mut Self
Pushes the current context onto the stack.
Examples found in repository?
8fn main() {
9 let pen_width = 0.3;
10 let cols = 23;
11 let rows = 16;
12 let size = (cols * rows) / 2;
13 let days = 365;
14 let cellw = f64::from(size) / f64::from(cols);
15 let cellh = f64::from(size) / f64::from(rows);
16
17 let mut ctx = Context::new();
18
19 // Set the default stroke/hatch/pen.
20 ctx.stroke("black")
21 .hatch(45.0)
22 .pen(pen_width)
23 .pattern(Hatches::line())
24 .fill("black");
25
26 for day in 0..days {
27 let col = f64::from(day / rows);
28 let row = f64::from(day % rows);
29 let x = col * cellw;
30 let y = row * cellh;
31 let w = 2.0f64;
32 let h = 30.0f64;
33
34 let phi = (f64::from(day) / f64::from(days)) * PI;
35 let theta = phi.sin() * 80.0 + 45.0;
36
37 // We scale w and h by the scale here because of implementation differences
38 // between JS canvas context and our context.
39 let scale = phi.cos().abs() * 2.0 + 1.0;
40 let w = scale * w;
41 let h = scale * h;
42
43 ctx.push()
44 .transform(Some(&(Context::translate_matrix(x, y))))
45 .mask_box(cellw * -0.5, cellh * -0.5, cellw * 0.5, cellh * 0.5)
46 .transform(Some(
47 &(Context::translate_matrix(x, y) * Context::rotate_matrix(theta)),
48 ))
49 .hatch(-90.0 + theta)
50 .rect(w * -0.5, h * -0.5, w * 0.5, h * 0.5)
51 .pop()
52 .expect("Somehow lost track of my internal stack");
53 }
54
55 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
56 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
57 // to match the context's bounds, giving us back an Arrangement::Transform with the
58 // affine txform that gives us a nicely centered drawing.
59 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
60 25.4,
61 Context::viewbox(0.0, 0.0, 216.0, 216.0),
62 false,
63 ));
64
65 let document = ctx.to_svg(&arrangement).unwrap();
66
67 // Write it to the images folder, so we can use it as an example!
68 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
69 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
70 svg::save(format!("images/{}.svg", fname), &document).unwrap();
71}
More examples
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
Sourcepub fn pop(&mut self) -> Result<&mut Self, ContextError>
pub fn pop(&mut self) -> Result<&mut Self, ContextError>
Pops the previous context off the stack
Examples found in repository?
8fn main() {
9 let pen_width = 0.3;
10 let cols = 23;
11 let rows = 16;
12 let size = (cols * rows) / 2;
13 let days = 365;
14 let cellw = f64::from(size) / f64::from(cols);
15 let cellh = f64::from(size) / f64::from(rows);
16
17 let mut ctx = Context::new();
18
19 // Set the default stroke/hatch/pen.
20 ctx.stroke("black")
21 .hatch(45.0)
22 .pen(pen_width)
23 .pattern(Hatches::line())
24 .fill("black");
25
26 for day in 0..days {
27 let col = f64::from(day / rows);
28 let row = f64::from(day % rows);
29 let x = col * cellw;
30 let y = row * cellh;
31 let w = 2.0f64;
32 let h = 30.0f64;
33
34 let phi = (f64::from(day) / f64::from(days)) * PI;
35 let theta = phi.sin() * 80.0 + 45.0;
36
37 // We scale w and h by the scale here because of implementation differences
38 // between JS canvas context and our context.
39 let scale = phi.cos().abs() * 2.0 + 1.0;
40 let w = scale * w;
41 let h = scale * h;
42
43 ctx.push()
44 .transform(Some(&(Context::translate_matrix(x, y))))
45 .mask_box(cellw * -0.5, cellh * -0.5, cellw * 0.5, cellh * 0.5)
46 .transform(Some(
47 &(Context::translate_matrix(x, y) * Context::rotate_matrix(theta)),
48 ))
49 .hatch(-90.0 + theta)
50 .rect(w * -0.5, h * -0.5, w * 0.5, h * 0.5)
51 .pop()
52 .expect("Somehow lost track of my internal stack");
53 }
54
55 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
56 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
57 // to match the context's bounds, giving us back an Arrangement::Transform with the
58 // affine txform that gives us a nicely centered drawing.
59 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
60 25.4,
61 Context::viewbox(0.0, 0.0, 216.0, 216.0),
62 false,
63 ));
64
65 let document = ctx.to_svg(&arrangement).unwrap();
66
67 // Write it to the images folder, so we can use it as an example!
68 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
69 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
70 svg::save(format!("images/{}.svg", fname), &document).unwrap();
71}
More examples
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
Sourcepub fn transform(&mut self, transformation: Option<&Affine2<f64>>) -> &mut Self
pub fn transform(&mut self, transformation: Option<&Affine2<f64>>) -> &mut Self
Set the transformation matrix for subsequent ops. Take a look at the transformation
helpers (crate::context::Context::scale_matrix
,
crate::context::Context::translate_matrix
, and
crate::context::Context::rotate_matrix
, which are great
if you don’t want to generate your own unsafe Affine2 transformations. Also, usefully,
these transformations can be COMPOSED via multiplication. Note that the order of the
compositions is right-to-left, so the last in the chain of multiplications is the
first one to be performed. See the example in context_basic.rs for more info.
Examples found in repository?
45 fn generate(&self) -> AOERCTX {
46 let mut ctx = AOERCTX::new();
47 let mut count = 0;
48
49 ctx.pen(1.5).accuracy(0.3);
50 if self.settings.draft {
51 ctx.pattern(Hatches::none());
52 } else {
53 ctx.pattern(Hatches::line());
54 }
55 let mut typo = Typography::new();
56 typo.size(4.5).align(Center);
57
58 for (name, geo) in CarlsonSmithTruchet::full_set()
59 .iter()
60 .filter(|(x, _y)| !x.starts_with("^"))
61 {
62 println!("Plotting {}", name);
63 let yofs: f64 = -256.0f64 + 128.0f64 * <f64 as From<i32>>::from((count / 6) as i32);
64 let xofs: f64 = -512.0f64 + 96.0f64 * <f64 as From<i32>>::from((count % 6) as i32);
65 // println!("xy is {},{}", xofs, yofs);
66 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(64.0, 64.0);
67 count += 1;
68 ctx.transform(Some(&tx)).geometry(&geo);
69 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(1.0, -1.0);
70
71 ctx.transform(Some(&tx)).typography(&name, 0.0, 60.0, &typo);
72 }
73 count = 0;
74 for (name, geo) in self
75 .full_set
76 .clone()
77 .iter()
78 .filter(|(x, _y)| x.starts_with("^"))
79 {
80 println!("Plotting inverse scale/2 {}", name);
81 let yofs: f64 =
82 -256.0f64 - 16.0f64 + 128.0f64 * <f64 as From<i32>>::from((count / 6) as i32);
83 let xofs: f64 = -512.0f64
84 + (96.0f64 * 6.0f64)
85 + 96.0f64 * <f64 as From<i32>>::from((count % 6) as i32);
86 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(32.0, 32.0);
87 count += 1;
88 ctx.transform(Some(&tx)).geometry(&geo);
89 ctx.transform(Some(&tx)).geometry(&geo);
90 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(1.0, -1.0);
91
92 ctx.transform(Some(&tx)).typography(&name, 0.0, 40.0, &typo);
93 }
94 ctx
95 }
More examples
8fn main() {
9 let pen_width = 0.3;
10 let cols = 23;
11 let rows = 16;
12 let size = (cols * rows) / 2;
13 let days = 365;
14 let cellw = f64::from(size) / f64::from(cols);
15 let cellh = f64::from(size) / f64::from(rows);
16
17 let mut ctx = Context::new();
18
19 // Set the default stroke/hatch/pen.
20 ctx.stroke("black")
21 .hatch(45.0)
22 .pen(pen_width)
23 .pattern(Hatches::line())
24 .fill("black");
25
26 for day in 0..days {
27 let col = f64::from(day / rows);
28 let row = f64::from(day % rows);
29 let x = col * cellw;
30 let y = row * cellh;
31 let w = 2.0f64;
32 let h = 30.0f64;
33
34 let phi = (f64::from(day) / f64::from(days)) * PI;
35 let theta = phi.sin() * 80.0 + 45.0;
36
37 // We scale w and h by the scale here because of implementation differences
38 // between JS canvas context and our context.
39 let scale = phi.cos().abs() * 2.0 + 1.0;
40 let w = scale * w;
41 let h = scale * h;
42
43 ctx.push()
44 .transform(Some(&(Context::translate_matrix(x, y))))
45 .mask_box(cellw * -0.5, cellh * -0.5, cellw * 0.5, cellh * 0.5)
46 .transform(Some(
47 &(Context::translate_matrix(x, y) * Context::rotate_matrix(theta)),
48 ))
49 .hatch(-90.0 + theta)
50 .rect(w * -0.5, h * -0.5, w * 0.5, h * 0.5)
51 .pop()
52 .expect("Somehow lost track of my internal stack");
53 }
54
55 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
56 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
57 // to match the context's bounds, giving us back an Arrangement::Transform with the
58 // affine txform that gives us a nicely centered drawing.
59 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
60 25.4,
61 Context::viewbox(0.0, 0.0, 216.0, 216.0),
62 false,
63 ));
64
65 let document = ctx.to_svg(&arrangement).unwrap();
66
67 // Write it to the images folder, so we can use it as an example!
68 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
69 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
70 svg::save(format!("images/{}.svg", fname), &document).unwrap();
71}
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
Sourcepub fn mul_transform(&mut self, transformation: &Affine2<f64>) -> &mut Self
pub fn mul_transform(&mut self, transformation: &Affine2<f64>) -> &mut Self
Similar to transform, but multiplies the CURRENT transformation matrix by the new one. If the current matrix is None, then multiplies by the UNIT matrix. This is really useful for stepping through relative positions, or rotations. Couples well with push/pop to make an addition relative to current matrix, then resetting to origin.
Sourcepub fn geometry(&mut self, geometry: &Geometry<f64>) -> &mut Self
pub fn geometry(&mut self, geometry: &Geometry<f64>) -> &mut Self
Adds a geometry to the operations list. Has some checking to make it safe for general users.
Examples found in repository?
45 fn generate(&self) -> AOERCTX {
46 let mut ctx = AOERCTX::new();
47 let mut count = 0;
48
49 ctx.pen(1.5).accuracy(0.3);
50 if self.settings.draft {
51 ctx.pattern(Hatches::none());
52 } else {
53 ctx.pattern(Hatches::line());
54 }
55 let mut typo = Typography::new();
56 typo.size(4.5).align(Center);
57
58 for (name, geo) in CarlsonSmithTruchet::full_set()
59 .iter()
60 .filter(|(x, _y)| !x.starts_with("^"))
61 {
62 println!("Plotting {}", name);
63 let yofs: f64 = -256.0f64 + 128.0f64 * <f64 as From<i32>>::from((count / 6) as i32);
64 let xofs: f64 = -512.0f64 + 96.0f64 * <f64 as From<i32>>::from((count % 6) as i32);
65 // println!("xy is {},{}", xofs, yofs);
66 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(64.0, 64.0);
67 count += 1;
68 ctx.transform(Some(&tx)).geometry(&geo);
69 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(1.0, -1.0);
70
71 ctx.transform(Some(&tx)).typography(&name, 0.0, 60.0, &typo);
72 }
73 count = 0;
74 for (name, geo) in self
75 .full_set
76 .clone()
77 .iter()
78 .filter(|(x, _y)| x.starts_with("^"))
79 {
80 println!("Plotting inverse scale/2 {}", name);
81 let yofs: f64 =
82 -256.0f64 - 16.0f64 + 128.0f64 * <f64 as From<i32>>::from((count / 6) as i32);
83 let xofs: f64 = -512.0f64
84 + (96.0f64 * 6.0f64)
85 + 96.0f64 * <f64 as From<i32>>::from((count % 6) as i32);
86 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(32.0, 32.0);
87 count += 1;
88 ctx.transform(Some(&tx)).geometry(&geo);
89 ctx.transform(Some(&tx)).geometry(&geo);
90 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(1.0, -1.0);
91
92 ctx.transform(Some(&tx)).typography(&name, 0.0, 40.0, &typo);
93 }
94 ctx
95 }
More examples
56fn main() {
57 let pen_width = 0.5f64;
58 let size: i32 = 224;
59 let square_count = 8;
60 let white = "#F2F5F1";
61 let colors = vec!["#D40920", "#1356A2", "#F7D842"];
62 let square_weight = 2.0f64; // How thick the dividing lines are
63
64 // We're using a static random generator here so that our SVG files
65 // don't get regenerated every time we run the examples.
66 let mut rng = SmallRng::seed_from_u64(1234567);
67 let mut ctx = Context::new();
68
69 let mut squares: Vec<Rect<f64>> = vec![Rect::new(
70 coord! {x:0.0, y:0.0},
71 coord! {x: f64::from(size), y: f64::from(size)},
72 )];
73
74 // split_squares_at(&mut squares, coord!{x: f64::from(size)/2.0, y: -1.0});
75 // split_squares_at(&mut squares, coord!{x:-1.0, y: f64::from(size)/2.0});
76 for i in (0..(size)).step_by((size / square_count) as usize) {
77 split_squares_at(&mut squares, coord! {x: f64::from(i), y: -1.0}, &mut rng);
78 split_squares_at(&mut squares, coord! {x:-1.0, y: f64::from(i)}, &mut rng);
79 }
80
81 // Create an array of the same length as the squares array, and fill it with "white"
82 let mut square_colors: Vec<&str> = squares.iter().map(|_s| white.clone()).collect();
83
84 for color in colors.clone() {
85 // Note, this might overlap an existing colored square. More often than you'd think actually.
86 square_colors[rng.gen_range(0..squares.len())] = color;
87 }
88
89 // Set the default stroke/hatch/pen.
90 ctx.stroke("black").hatch(45.0).pen(pen_width);
91
92 // for square in squares {
93 for i in 0..squares.len() {
94 let square = squares[i].clone();
95 let color = square_colors[i].clone();
96
97 // Don't bother hatching if it's white.
98 if color != white {
99 ctx.pattern(Hatches::line());
100 } else {
101 ctx.pattern(Hatches::none());
102 }
103
104 // And set the fill color.
105 ctx.fill(color).rect(
106 square.min().x + square_weight,
107 square.min().y + square_weight,
108 square.max().x - square_weight,
109 square.max().y - square_weight,
110 );
111
112 // Now we just draw the rest of the outlines, inside to outside, no fill.
113 ctx.pattern(Hatches::none());
114 let mut remaining_width = square_weight - (pen_width / 2.0);
115 let s = squares[i].clone();
116 while remaining_width >= 0.0 {
117 ctx.geometry(&Geometry::Rect(Rect::new(
118 coord! {x: &s.min().x+remaining_width, y: &s.min().y+remaining_width},
119 coord! {x: &s.max().x-remaining_width, y: &s.max().y-remaining_width},
120 )));
121 remaining_width -= pen_width;
122 }
123 }
124
125 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
126 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
127 // to match the context's bounds, giving us back an Arrangement::Transform with the
128 // affine txform that gives us a nicely centered drawing.
129 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
130 25.4,
131 Context::viewbox(0.0, 0.0, 216.0, 216.0),
132 false,
133 ));
134
135 let document = ctx.to_svg(&arrangement).unwrap();
136
137 // Write it to the images folder, so we can use it as an example!
138 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
139 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
140 svg::save(format!("images/{}.svg", fname), &document).unwrap();
141}
Sourcepub fn line(&mut self, x0: f64, y0: f64, x1: f64, y1: f64) -> &mut Self
pub fn line(&mut self, x0: f64, y0: f64, x1: f64, y1: f64) -> &mut Self
Draws a simple line from x0,y0 to x1,y1
Examples found in repository?
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
Sourcepub fn typography(
&mut self,
text: &String,
x0: f64,
y0: f64,
typography: &Typography,
) -> &mut Self
pub fn typography( &mut self, text: &String, x0: f64, y0: f64, typography: &Typography, ) -> &mut Self
Draws a line of text
Examples found in repository?
8fn main() {
9 let mut ctx = Context::new();
10 let mut typ = Typography::new();
11 typ.size(2.0);
12 typ.close(true);
13
14 ctx.stroke("black")
15 .fill("red")
16 .pen(0.5)
17 .pattern(Hatches::none())
18 // .pattern(LineHatch::gen())
19 // .typography(&"i".to_string(), 50.0, 50.0, &typ);
20 .typography(&"Left".to_string(), 50.0, 50.0, &typ);
21 typ.align(TextAlignment::Right);
22 ctx.typography(&"Right".to_string(), 50.0, 90.0, &typ);
23 typ.align(TextAlignment::Center);
24 ctx.typography(&"Center".to_string(), 50.0, 70.0, &typ);
25
26 let svg = ctx
27 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
28 coord! {x:0.0, y:0.0},
29 coord! {x:100.0, y:100.0},
30 )))
31 .unwrap();
32 // Write it to the images folder, so we can use it as an example!
33 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
34 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
35 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
36}
More examples
45 fn generate(&self) -> AOERCTX {
46 let mut ctx = AOERCTX::new();
47 let mut count = 0;
48
49 ctx.pen(1.5).accuracy(0.3);
50 if self.settings.draft {
51 ctx.pattern(Hatches::none());
52 } else {
53 ctx.pattern(Hatches::line());
54 }
55 let mut typo = Typography::new();
56 typo.size(4.5).align(Center);
57
58 for (name, geo) in CarlsonSmithTruchet::full_set()
59 .iter()
60 .filter(|(x, _y)| !x.starts_with("^"))
61 {
62 println!("Plotting {}", name);
63 let yofs: f64 = -256.0f64 + 128.0f64 * <f64 as From<i32>>::from((count / 6) as i32);
64 let xofs: f64 = -512.0f64 + 96.0f64 * <f64 as From<i32>>::from((count % 6) as i32);
65 // println!("xy is {},{}", xofs, yofs);
66 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(64.0, 64.0);
67 count += 1;
68 ctx.transform(Some(&tx)).geometry(&geo);
69 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(1.0, -1.0);
70
71 ctx.transform(Some(&tx)).typography(&name, 0.0, 60.0, &typo);
72 }
73 count = 0;
74 for (name, geo) in self
75 .full_set
76 .clone()
77 .iter()
78 .filter(|(x, _y)| x.starts_with("^"))
79 {
80 println!("Plotting inverse scale/2 {}", name);
81 let yofs: f64 =
82 -256.0f64 - 16.0f64 + 128.0f64 * <f64 as From<i32>>::from((count / 6) as i32);
83 let xofs: f64 = -512.0f64
84 + (96.0f64 * 6.0f64)
85 + 96.0f64 * <f64 as From<i32>>::from((count % 6) as i32);
86 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(32.0, 32.0);
87 count += 1;
88 ctx.transform(Some(&tx)).geometry(&geo);
89 ctx.transform(Some(&tx)).geometry(&geo);
90 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(1.0, -1.0);
91
92 ctx.transform(Some(&tx)).typography(&name, 0.0, 40.0, &typo);
93 }
94 ctx
95 }
Sourcepub fn glyph(&mut self, glyph: char, close: bool) -> &mut Self
pub fn glyph(&mut self, glyph: char, close: bool) -> &mut Self
Glyph Draws a single glyph on the Context, at 0,0
Examples found in repository?
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
Sourcepub fn path(&mut self, bezier: &BezPath) -> &mut Self
pub fn path(&mut self, bezier: &BezPath) -> &mut Self
Way more useful path interface. Uses Kurbo’s BezierPath module. After creation, uses GEOS polygonize_full to generate polygons and line segments from the drawing, ensuring that we can have filled geometry as an output.
Sourcepub fn spline(
&mut self,
points: &Vec<(f64, f64)>,
num_interpolated_segments: u32,
tension: f64,
) -> &mut Self
pub fn spline( &mut self, points: &Vec<(f64, f64)>, num_interpolated_segments: u32, tension: f64, ) -> &mut Self
Generates a spline from a set of points and renders as a multi line string. Doesn’t do errors very well, just silently fails to draw. First and last point in points are NOT drawn, and set the ‘tension’ points which the line pulls from.
Examples found in repository?
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
Sourcepub fn arc_center(
&mut self,
x0: f64,
y0: f64,
radius: f64,
deg0: f64,
deg1: f64,
) -> &mut Self
pub fn arc_center( &mut self, x0: f64, y0: f64, radius: f64, deg0: f64, deg1: f64, ) -> &mut Self
centerpoint arc Draw an arc around x0,y0 with the given radius, from deg0 to deg1. Arcs will always be coords oriented clockwise from “north” on an SVG. ie: 45 to 135 will be NE to SE.
Sourcepub fn rect(&mut self, x0: f64, y0: f64, x1: f64, y1: f64) -> &mut Self
pub fn rect(&mut self, x0: f64, y0: f64, x1: f64, y1: f64) -> &mut Self
What it says on the box. Draws a simple rectangle on the context.
Examples found in repository?
8fn main() {
9 let pen_width = 0.3;
10 let cols = 23;
11 let rows = 16;
12 let size = (cols * rows) / 2;
13 let days = 365;
14 let cellw = f64::from(size) / f64::from(cols);
15 let cellh = f64::from(size) / f64::from(rows);
16
17 let mut ctx = Context::new();
18
19 // Set the default stroke/hatch/pen.
20 ctx.stroke("black")
21 .hatch(45.0)
22 .pen(pen_width)
23 .pattern(Hatches::line())
24 .fill("black");
25
26 for day in 0..days {
27 let col = f64::from(day / rows);
28 let row = f64::from(day % rows);
29 let x = col * cellw;
30 let y = row * cellh;
31 let w = 2.0f64;
32 let h = 30.0f64;
33
34 let phi = (f64::from(day) / f64::from(days)) * PI;
35 let theta = phi.sin() * 80.0 + 45.0;
36
37 // We scale w and h by the scale here because of implementation differences
38 // between JS canvas context and our context.
39 let scale = phi.cos().abs() * 2.0 + 1.0;
40 let w = scale * w;
41 let h = scale * h;
42
43 ctx.push()
44 .transform(Some(&(Context::translate_matrix(x, y))))
45 .mask_box(cellw * -0.5, cellh * -0.5, cellw * 0.5, cellh * 0.5)
46 .transform(Some(
47 &(Context::translate_matrix(x, y) * Context::rotate_matrix(theta)),
48 ))
49 .hatch(-90.0 + theta)
50 .rect(w * -0.5, h * -0.5, w * 0.5, h * 0.5)
51 .pop()
52 .expect("Somehow lost track of my internal stack");
53 }
54
55 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
56 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
57 // to match the context's bounds, giving us back an Arrangement::Transform with the
58 // affine txform that gives us a nicely centered drawing.
59 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
60 25.4,
61 Context::viewbox(0.0, 0.0, 216.0, 216.0),
62 false,
63 ));
64
65 let document = ctx.to_svg(&arrangement).unwrap();
66
67 // Write it to the images folder, so we can use it as an example!
68 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
69 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
70 svg::save(format!("images/{}.svg", fname), &document).unwrap();
71}
More examples
56fn main() {
57 let pen_width = 0.5f64;
58 let size: i32 = 224;
59 let square_count = 8;
60 let white = "#F2F5F1";
61 let colors = vec!["#D40920", "#1356A2", "#F7D842"];
62 let square_weight = 2.0f64; // How thick the dividing lines are
63
64 // We're using a static random generator here so that our SVG files
65 // don't get regenerated every time we run the examples.
66 let mut rng = SmallRng::seed_from_u64(1234567);
67 let mut ctx = Context::new();
68
69 let mut squares: Vec<Rect<f64>> = vec![Rect::new(
70 coord! {x:0.0, y:0.0},
71 coord! {x: f64::from(size), y: f64::from(size)},
72 )];
73
74 // split_squares_at(&mut squares, coord!{x: f64::from(size)/2.0, y: -1.0});
75 // split_squares_at(&mut squares, coord!{x:-1.0, y: f64::from(size)/2.0});
76 for i in (0..(size)).step_by((size / square_count) as usize) {
77 split_squares_at(&mut squares, coord! {x: f64::from(i), y: -1.0}, &mut rng);
78 split_squares_at(&mut squares, coord! {x:-1.0, y: f64::from(i)}, &mut rng);
79 }
80
81 // Create an array of the same length as the squares array, and fill it with "white"
82 let mut square_colors: Vec<&str> = squares.iter().map(|_s| white.clone()).collect();
83
84 for color in colors.clone() {
85 // Note, this might overlap an existing colored square. More often than you'd think actually.
86 square_colors[rng.gen_range(0..squares.len())] = color;
87 }
88
89 // Set the default stroke/hatch/pen.
90 ctx.stroke("black").hatch(45.0).pen(pen_width);
91
92 // for square in squares {
93 for i in 0..squares.len() {
94 let square = squares[i].clone();
95 let color = square_colors[i].clone();
96
97 // Don't bother hatching if it's white.
98 if color != white {
99 ctx.pattern(Hatches::line());
100 } else {
101 ctx.pattern(Hatches::none());
102 }
103
104 // And set the fill color.
105 ctx.fill(color).rect(
106 square.min().x + square_weight,
107 square.min().y + square_weight,
108 square.max().x - square_weight,
109 square.max().y - square_weight,
110 );
111
112 // Now we just draw the rest of the outlines, inside to outside, no fill.
113 ctx.pattern(Hatches::none());
114 let mut remaining_width = square_weight - (pen_width / 2.0);
115 let s = squares[i].clone();
116 while remaining_width >= 0.0 {
117 ctx.geometry(&Geometry::Rect(Rect::new(
118 coord! {x: &s.min().x+remaining_width, y: &s.min().y+remaining_width},
119 coord! {x: &s.max().x-remaining_width, y: &s.max().y-remaining_width},
120 )));
121 remaining_width -= pen_width;
122 }
123 }
124
125 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
126 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
127 // to match the context's bounds, giving us back an Arrangement::Transform with the
128 // affine txform that gives us a nicely centered drawing.
129 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
130 25.4,
131 Context::viewbox(0.0, 0.0, 216.0, 216.0),
132 false,
133 ));
134
135 let document = ctx.to_svg(&arrangement).unwrap();
136
137 // Write it to the images folder, so we can use it as an example!
138 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
139 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
140 svg::save(format!("images/{}.svg", fname), &document).unwrap();
141}
Sourcepub fn poly(
&mut self,
exterior: Vec<(f64, f64)>,
interiors: Vec<Vec<(f64, f64)>>,
) -> &mut Self
pub fn poly( &mut self, exterior: Vec<(f64, f64)>, interiors: Vec<Vec<(f64, f64)>>, ) -> &mut Self
Draws a polygon
Examples found in repository?
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
Sourcepub fn circle(&mut self, x0: f64, y0: f64, radius: f64) -> &mut Self
pub fn circle(&mut self, x0: f64, y0: f64, radius: f64) -> &mut Self
Draws a circle. Actually just buffers a point, and returns a polygon which it draws on the context.
Examples found in repository?
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
Sourcepub fn regular_poly(
&mut self,
sides: usize,
x: f64,
y: f64,
radius: f64,
rotation: f64,
) -> &mut Self
pub fn regular_poly( &mut self, sides: usize, x: f64, y: f64, radius: f64, rotation: f64, ) -> &mut Self
Circumscribed regular polygon. The vertices of the polygon will be situated on a circle defined by the given radius. Polygon will be centered at x,y.
Examples found in repository?
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
Sourcepub fn star_poly(
&mut self,
sides: usize,
x: f64,
y: f64,
inner_radius: f64,
outer_radius: f64,
rotation: f64,
) -> &mut Self
pub fn star_poly( &mut self, sides: usize, x: f64, y: f64, inner_radius: f64, outer_radius: f64, rotation: f64, ) -> &mut Self
Regular star polygon. This is effectively a star shape with the number of points indicated, and with inner and outer radiuses which correspond to the valleys and tips of the star respectively. Note: this is not a star polygon in the strict mathematical sense. This is just a polygon that is in the shape of a star. I may or may not get to regular star polygons (in the canonical mathematical sense) at some point.
Examples found in repository?
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
Sourcepub fn clip(&mut self, clip: bool) -> &mut Self
pub fn clip(&mut self, clip: bool) -> &mut Self
Sets the clipping state. Any subsequent objects will clip their predecessors. Note that this is an EXPENSIVE operation, so you might want to leave it off if you’re sure you won’t have intersections.
Examples found in repository?
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
Sourcepub fn stroke(&mut self, color: &str) -> &mut Self
pub fn stroke(&mut self, color: &str) -> &mut Self
Sets the stroke color
Examples found in repository?
8fn main() {
9 let mut ctx = Context::new();
10 let mut typ = Typography::new();
11 typ.size(2.0);
12 typ.close(true);
13
14 ctx.stroke("black")
15 .fill("red")
16 .pen(0.5)
17 .pattern(Hatches::none())
18 // .pattern(LineHatch::gen())
19 // .typography(&"i".to_string(), 50.0, 50.0, &typ);
20 .typography(&"Left".to_string(), 50.0, 50.0, &typ);
21 typ.align(TextAlignment::Right);
22 ctx.typography(&"Right".to_string(), 50.0, 90.0, &typ);
23 typ.align(TextAlignment::Center);
24 ctx.typography(&"Center".to_string(), 50.0, 70.0, &typ);
25
26 let svg = ctx
27 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
28 coord! {x:0.0, y:0.0},
29 coord! {x:100.0, y:100.0},
30 )))
31 .unwrap();
32 // Write it to the images folder, so we can use it as an example!
33 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
34 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
35 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
36}
More examples
8fn main() {
9 let pen_width = 0.3;
10 let cols = 23;
11 let rows = 16;
12 let size = (cols * rows) / 2;
13 let days = 365;
14 let cellw = f64::from(size) / f64::from(cols);
15 let cellh = f64::from(size) / f64::from(rows);
16
17 let mut ctx = Context::new();
18
19 // Set the default stroke/hatch/pen.
20 ctx.stroke("black")
21 .hatch(45.0)
22 .pen(pen_width)
23 .pattern(Hatches::line())
24 .fill("black");
25
26 for day in 0..days {
27 let col = f64::from(day / rows);
28 let row = f64::from(day % rows);
29 let x = col * cellw;
30 let y = row * cellh;
31 let w = 2.0f64;
32 let h = 30.0f64;
33
34 let phi = (f64::from(day) / f64::from(days)) * PI;
35 let theta = phi.sin() * 80.0 + 45.0;
36
37 // We scale w and h by the scale here because of implementation differences
38 // between JS canvas context and our context.
39 let scale = phi.cos().abs() * 2.0 + 1.0;
40 let w = scale * w;
41 let h = scale * h;
42
43 ctx.push()
44 .transform(Some(&(Context::translate_matrix(x, y))))
45 .mask_box(cellw * -0.5, cellh * -0.5, cellw * 0.5, cellh * 0.5)
46 .transform(Some(
47 &(Context::translate_matrix(x, y) * Context::rotate_matrix(theta)),
48 ))
49 .hatch(-90.0 + theta)
50 .rect(w * -0.5, h * -0.5, w * 0.5, h * 0.5)
51 .pop()
52 .expect("Somehow lost track of my internal stack");
53 }
54
55 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
56 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
57 // to match the context's bounds, giving us back an Arrangement::Transform with the
58 // affine txform that gives us a nicely centered drawing.
59 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
60 25.4,
61 Context::viewbox(0.0, 0.0, 216.0, 216.0),
62 false,
63 ));
64
65 let document = ctx.to_svg(&arrangement).unwrap();
66
67 // Write it to the images folder, so we can use it as an example!
68 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
69 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
70 svg::save(format!("images/{}.svg", fname), &document).unwrap();
71}
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
56fn main() {
57 let pen_width = 0.5f64;
58 let size: i32 = 224;
59 let square_count = 8;
60 let white = "#F2F5F1";
61 let colors = vec!["#D40920", "#1356A2", "#F7D842"];
62 let square_weight = 2.0f64; // How thick the dividing lines are
63
64 // We're using a static random generator here so that our SVG files
65 // don't get regenerated every time we run the examples.
66 let mut rng = SmallRng::seed_from_u64(1234567);
67 let mut ctx = Context::new();
68
69 let mut squares: Vec<Rect<f64>> = vec![Rect::new(
70 coord! {x:0.0, y:0.0},
71 coord! {x: f64::from(size), y: f64::from(size)},
72 )];
73
74 // split_squares_at(&mut squares, coord!{x: f64::from(size)/2.0, y: -1.0});
75 // split_squares_at(&mut squares, coord!{x:-1.0, y: f64::from(size)/2.0});
76 for i in (0..(size)).step_by((size / square_count) as usize) {
77 split_squares_at(&mut squares, coord! {x: f64::from(i), y: -1.0}, &mut rng);
78 split_squares_at(&mut squares, coord! {x:-1.0, y: f64::from(i)}, &mut rng);
79 }
80
81 // Create an array of the same length as the squares array, and fill it with "white"
82 let mut square_colors: Vec<&str> = squares.iter().map(|_s| white.clone()).collect();
83
84 for color in colors.clone() {
85 // Note, this might overlap an existing colored square. More often than you'd think actually.
86 square_colors[rng.gen_range(0..squares.len())] = color;
87 }
88
89 // Set the default stroke/hatch/pen.
90 ctx.stroke("black").hatch(45.0).pen(pen_width);
91
92 // for square in squares {
93 for i in 0..squares.len() {
94 let square = squares[i].clone();
95 let color = square_colors[i].clone();
96
97 // Don't bother hatching if it's white.
98 if color != white {
99 ctx.pattern(Hatches::line());
100 } else {
101 ctx.pattern(Hatches::none());
102 }
103
104 // And set the fill color.
105 ctx.fill(color).rect(
106 square.min().x + square_weight,
107 square.min().y + square_weight,
108 square.max().x - square_weight,
109 square.max().y - square_weight,
110 );
111
112 // Now we just draw the rest of the outlines, inside to outside, no fill.
113 ctx.pattern(Hatches::none());
114 let mut remaining_width = square_weight - (pen_width / 2.0);
115 let s = squares[i].clone();
116 while remaining_width >= 0.0 {
117 ctx.geometry(&Geometry::Rect(Rect::new(
118 coord! {x: &s.min().x+remaining_width, y: &s.min().y+remaining_width},
119 coord! {x: &s.max().x-remaining_width, y: &s.max().y-remaining_width},
120 )));
121 remaining_width -= pen_width;
122 }
123 }
124
125 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
126 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
127 // to match the context's bounds, giving us back an Arrangement::Transform with the
128 // affine txform that gives us a nicely centered drawing.
129 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
130 25.4,
131 Context::viewbox(0.0, 0.0, 216.0, 216.0),
132 false,
133 ));
134
135 let document = ctx.to_svg(&arrangement).unwrap();
136
137 // Write it to the images folder, so we can use it as an example!
138 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
139 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
140 svg::save(format!("images/{}.svg", fname), &document).unwrap();
141}
Sourcepub fn fill(&mut self, color: &str) -> &mut Self
pub fn fill(&mut self, color: &str) -> &mut Self
Sets the fill color
Examples found in repository?
8fn main() {
9 let mut ctx = Context::new();
10 let mut typ = Typography::new();
11 typ.size(2.0);
12 typ.close(true);
13
14 ctx.stroke("black")
15 .fill("red")
16 .pen(0.5)
17 .pattern(Hatches::none())
18 // .pattern(LineHatch::gen())
19 // .typography(&"i".to_string(), 50.0, 50.0, &typ);
20 .typography(&"Left".to_string(), 50.0, 50.0, &typ);
21 typ.align(TextAlignment::Right);
22 ctx.typography(&"Right".to_string(), 50.0, 90.0, &typ);
23 typ.align(TextAlignment::Center);
24 ctx.typography(&"Center".to_string(), 50.0, 70.0, &typ);
25
26 let svg = ctx
27 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
28 coord! {x:0.0, y:0.0},
29 coord! {x:100.0, y:100.0},
30 )))
31 .unwrap();
32 // Write it to the images folder, so we can use it as an example!
33 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
34 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
35 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
36}
More examples
8fn main() {
9 let pen_width = 0.3;
10 let cols = 23;
11 let rows = 16;
12 let size = (cols * rows) / 2;
13 let days = 365;
14 let cellw = f64::from(size) / f64::from(cols);
15 let cellh = f64::from(size) / f64::from(rows);
16
17 let mut ctx = Context::new();
18
19 // Set the default stroke/hatch/pen.
20 ctx.stroke("black")
21 .hatch(45.0)
22 .pen(pen_width)
23 .pattern(Hatches::line())
24 .fill("black");
25
26 for day in 0..days {
27 let col = f64::from(day / rows);
28 let row = f64::from(day % rows);
29 let x = col * cellw;
30 let y = row * cellh;
31 let w = 2.0f64;
32 let h = 30.0f64;
33
34 let phi = (f64::from(day) / f64::from(days)) * PI;
35 let theta = phi.sin() * 80.0 + 45.0;
36
37 // We scale w and h by the scale here because of implementation differences
38 // between JS canvas context and our context.
39 let scale = phi.cos().abs() * 2.0 + 1.0;
40 let w = scale * w;
41 let h = scale * h;
42
43 ctx.push()
44 .transform(Some(&(Context::translate_matrix(x, y))))
45 .mask_box(cellw * -0.5, cellh * -0.5, cellw * 0.5, cellh * 0.5)
46 .transform(Some(
47 &(Context::translate_matrix(x, y) * Context::rotate_matrix(theta)),
48 ))
49 .hatch(-90.0 + theta)
50 .rect(w * -0.5, h * -0.5, w * 0.5, h * 0.5)
51 .pop()
52 .expect("Somehow lost track of my internal stack");
53 }
54
55 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
56 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
57 // to match the context's bounds, giving us back an Arrangement::Transform with the
58 // affine txform that gives us a nicely centered drawing.
59 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
60 25.4,
61 Context::viewbox(0.0, 0.0, 216.0, 216.0),
62 false,
63 ));
64
65 let document = ctx.to_svg(&arrangement).unwrap();
66
67 // Write it to the images folder, so we can use it as an example!
68 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
69 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
70 svg::save(format!("images/{}.svg", fname), &document).unwrap();
71}
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
56fn main() {
57 let pen_width = 0.5f64;
58 let size: i32 = 224;
59 let square_count = 8;
60 let white = "#F2F5F1";
61 let colors = vec!["#D40920", "#1356A2", "#F7D842"];
62 let square_weight = 2.0f64; // How thick the dividing lines are
63
64 // We're using a static random generator here so that our SVG files
65 // don't get regenerated every time we run the examples.
66 let mut rng = SmallRng::seed_from_u64(1234567);
67 let mut ctx = Context::new();
68
69 let mut squares: Vec<Rect<f64>> = vec![Rect::new(
70 coord! {x:0.0, y:0.0},
71 coord! {x: f64::from(size), y: f64::from(size)},
72 )];
73
74 // split_squares_at(&mut squares, coord!{x: f64::from(size)/2.0, y: -1.0});
75 // split_squares_at(&mut squares, coord!{x:-1.0, y: f64::from(size)/2.0});
76 for i in (0..(size)).step_by((size / square_count) as usize) {
77 split_squares_at(&mut squares, coord! {x: f64::from(i), y: -1.0}, &mut rng);
78 split_squares_at(&mut squares, coord! {x:-1.0, y: f64::from(i)}, &mut rng);
79 }
80
81 // Create an array of the same length as the squares array, and fill it with "white"
82 let mut square_colors: Vec<&str> = squares.iter().map(|_s| white.clone()).collect();
83
84 for color in colors.clone() {
85 // Note, this might overlap an existing colored square. More often than you'd think actually.
86 square_colors[rng.gen_range(0..squares.len())] = color;
87 }
88
89 // Set the default stroke/hatch/pen.
90 ctx.stroke("black").hatch(45.0).pen(pen_width);
91
92 // for square in squares {
93 for i in 0..squares.len() {
94 let square = squares[i].clone();
95 let color = square_colors[i].clone();
96
97 // Don't bother hatching if it's white.
98 if color != white {
99 ctx.pattern(Hatches::line());
100 } else {
101 ctx.pattern(Hatches::none());
102 }
103
104 // And set the fill color.
105 ctx.fill(color).rect(
106 square.min().x + square_weight,
107 square.min().y + square_weight,
108 square.max().x - square_weight,
109 square.max().y - square_weight,
110 );
111
112 // Now we just draw the rest of the outlines, inside to outside, no fill.
113 ctx.pattern(Hatches::none());
114 let mut remaining_width = square_weight - (pen_width / 2.0);
115 let s = squares[i].clone();
116 while remaining_width >= 0.0 {
117 ctx.geometry(&Geometry::Rect(Rect::new(
118 coord! {x: &s.min().x+remaining_width, y: &s.min().y+remaining_width},
119 coord! {x: &s.max().x-remaining_width, y: &s.max().y-remaining_width},
120 )));
121 remaining_width -= pen_width;
122 }
123 }
124
125 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
126 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
127 // to match the context's bounds, giving us back an Arrangement::Transform with the
128 // affine txform that gives us a nicely centered drawing.
129 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
130 25.4,
131 Context::viewbox(0.0, 0.0, 216.0, 216.0),
132 false,
133 ));
134
135 let document = ctx.to_svg(&arrangement).unwrap();
136
137 // Write it to the images folder, so we can use it as an example!
138 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
139 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
140 svg::save(format!("images/{}.svg", fname), &document).unwrap();
141}
Sourcepub fn hatch(&mut self, angle: f64) -> &mut Self
pub fn hatch(&mut self, angle: f64) -> &mut Self
Sets the hatch state, either None for no hatching or Some(angle) to set a hatching angle. Will use the current pen width as the spacing between hatch lines.
Examples found in repository?
8fn main() {
9 let pen_width = 0.3;
10 let cols = 23;
11 let rows = 16;
12 let size = (cols * rows) / 2;
13 let days = 365;
14 let cellw = f64::from(size) / f64::from(cols);
15 let cellh = f64::from(size) / f64::from(rows);
16
17 let mut ctx = Context::new();
18
19 // Set the default stroke/hatch/pen.
20 ctx.stroke("black")
21 .hatch(45.0)
22 .pen(pen_width)
23 .pattern(Hatches::line())
24 .fill("black");
25
26 for day in 0..days {
27 let col = f64::from(day / rows);
28 let row = f64::from(day % rows);
29 let x = col * cellw;
30 let y = row * cellh;
31 let w = 2.0f64;
32 let h = 30.0f64;
33
34 let phi = (f64::from(day) / f64::from(days)) * PI;
35 let theta = phi.sin() * 80.0 + 45.0;
36
37 // We scale w and h by the scale here because of implementation differences
38 // between JS canvas context and our context.
39 let scale = phi.cos().abs() * 2.0 + 1.0;
40 let w = scale * w;
41 let h = scale * h;
42
43 ctx.push()
44 .transform(Some(&(Context::translate_matrix(x, y))))
45 .mask_box(cellw * -0.5, cellh * -0.5, cellw * 0.5, cellh * 0.5)
46 .transform(Some(
47 &(Context::translate_matrix(x, y) * Context::rotate_matrix(theta)),
48 ))
49 .hatch(-90.0 + theta)
50 .rect(w * -0.5, h * -0.5, w * 0.5, h * 0.5)
51 .pop()
52 .expect("Somehow lost track of my internal stack");
53 }
54
55 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
56 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
57 // to match the context's bounds, giving us back an Arrangement::Transform with the
58 // affine txform that gives us a nicely centered drawing.
59 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
60 25.4,
61 Context::viewbox(0.0, 0.0, 216.0, 216.0),
62 false,
63 ));
64
65 let document = ctx.to_svg(&arrangement).unwrap();
66
67 // Write it to the images folder, so we can use it as an example!
68 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
69 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
70 svg::save(format!("images/{}.svg", fname), &document).unwrap();
71}
More examples
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
56fn main() {
57 let pen_width = 0.5f64;
58 let size: i32 = 224;
59 let square_count = 8;
60 let white = "#F2F5F1";
61 let colors = vec!["#D40920", "#1356A2", "#F7D842"];
62 let square_weight = 2.0f64; // How thick the dividing lines are
63
64 // We're using a static random generator here so that our SVG files
65 // don't get regenerated every time we run the examples.
66 let mut rng = SmallRng::seed_from_u64(1234567);
67 let mut ctx = Context::new();
68
69 let mut squares: Vec<Rect<f64>> = vec![Rect::new(
70 coord! {x:0.0, y:0.0},
71 coord! {x: f64::from(size), y: f64::from(size)},
72 )];
73
74 // split_squares_at(&mut squares, coord!{x: f64::from(size)/2.0, y: -1.0});
75 // split_squares_at(&mut squares, coord!{x:-1.0, y: f64::from(size)/2.0});
76 for i in (0..(size)).step_by((size / square_count) as usize) {
77 split_squares_at(&mut squares, coord! {x: f64::from(i), y: -1.0}, &mut rng);
78 split_squares_at(&mut squares, coord! {x:-1.0, y: f64::from(i)}, &mut rng);
79 }
80
81 // Create an array of the same length as the squares array, and fill it with "white"
82 let mut square_colors: Vec<&str> = squares.iter().map(|_s| white.clone()).collect();
83
84 for color in colors.clone() {
85 // Note, this might overlap an existing colored square. More often than you'd think actually.
86 square_colors[rng.gen_range(0..squares.len())] = color;
87 }
88
89 // Set the default stroke/hatch/pen.
90 ctx.stroke("black").hatch(45.0).pen(pen_width);
91
92 // for square in squares {
93 for i in 0..squares.len() {
94 let square = squares[i].clone();
95 let color = square_colors[i].clone();
96
97 // Don't bother hatching if it's white.
98 if color != white {
99 ctx.pattern(Hatches::line());
100 } else {
101 ctx.pattern(Hatches::none());
102 }
103
104 // And set the fill color.
105 ctx.fill(color).rect(
106 square.min().x + square_weight,
107 square.min().y + square_weight,
108 square.max().x - square_weight,
109 square.max().y - square_weight,
110 );
111
112 // Now we just draw the rest of the outlines, inside to outside, no fill.
113 ctx.pattern(Hatches::none());
114 let mut remaining_width = square_weight - (pen_width / 2.0);
115 let s = squares[i].clone();
116 while remaining_width >= 0.0 {
117 ctx.geometry(&Geometry::Rect(Rect::new(
118 coord! {x: &s.min().x+remaining_width, y: &s.min().y+remaining_width},
119 coord! {x: &s.max().x-remaining_width, y: &s.max().y-remaining_width},
120 )));
121 remaining_width -= pen_width;
122 }
123 }
124
125 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
126 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
127 // to match the context's bounds, giving us back an Arrangement::Transform with the
128 // affine txform that gives us a nicely centered drawing.
129 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
130 25.4,
131 Context::viewbox(0.0, 0.0, 216.0, 216.0),
132 false,
133 ));
134
135 let document = ctx.to_svg(&arrangement).unwrap();
136
137 // Write it to the images folder, so we can use it as an example!
138 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
139 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
140 svg::save(format!("images/{}.svg", fname), &document).unwrap();
141}
Sourcepub fn pen(&mut self, width: f64) -> &mut Self
pub fn pen(&mut self, width: f64) -> &mut Self
Sets the pen width
Examples found in repository?
8fn main() {
9 let mut ctx = Context::new();
10 let mut typ = Typography::new();
11 typ.size(2.0);
12 typ.close(true);
13
14 ctx.stroke("black")
15 .fill("red")
16 .pen(0.5)
17 .pattern(Hatches::none())
18 // .pattern(LineHatch::gen())
19 // .typography(&"i".to_string(), 50.0, 50.0, &typ);
20 .typography(&"Left".to_string(), 50.0, 50.0, &typ);
21 typ.align(TextAlignment::Right);
22 ctx.typography(&"Right".to_string(), 50.0, 90.0, &typ);
23 typ.align(TextAlignment::Center);
24 ctx.typography(&"Center".to_string(), 50.0, 70.0, &typ);
25
26 let svg = ctx
27 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
28 coord! {x:0.0, y:0.0},
29 coord! {x:100.0, y:100.0},
30 )))
31 .unwrap();
32 // Write it to the images folder, so we can use it as an example!
33 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
34 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
35 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
36}
More examples
45 fn generate(&self) -> AOERCTX {
46 let mut ctx = AOERCTX::new();
47 let mut count = 0;
48
49 ctx.pen(1.5).accuracy(0.3);
50 if self.settings.draft {
51 ctx.pattern(Hatches::none());
52 } else {
53 ctx.pattern(Hatches::line());
54 }
55 let mut typo = Typography::new();
56 typo.size(4.5).align(Center);
57
58 for (name, geo) in CarlsonSmithTruchet::full_set()
59 .iter()
60 .filter(|(x, _y)| !x.starts_with("^"))
61 {
62 println!("Plotting {}", name);
63 let yofs: f64 = -256.0f64 + 128.0f64 * <f64 as From<i32>>::from((count / 6) as i32);
64 let xofs: f64 = -512.0f64 + 96.0f64 * <f64 as From<i32>>::from((count % 6) as i32);
65 // println!("xy is {},{}", xofs, yofs);
66 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(64.0, 64.0);
67 count += 1;
68 ctx.transform(Some(&tx)).geometry(&geo);
69 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(1.0, -1.0);
70
71 ctx.transform(Some(&tx)).typography(&name, 0.0, 60.0, &typo);
72 }
73 count = 0;
74 for (name, geo) in self
75 .full_set
76 .clone()
77 .iter()
78 .filter(|(x, _y)| x.starts_with("^"))
79 {
80 println!("Plotting inverse scale/2 {}", name);
81 let yofs: f64 =
82 -256.0f64 - 16.0f64 + 128.0f64 * <f64 as From<i32>>::from((count / 6) as i32);
83 let xofs: f64 = -512.0f64
84 + (96.0f64 * 6.0f64)
85 + 96.0f64 * <f64 as From<i32>>::from((count % 6) as i32);
86 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(32.0, 32.0);
87 count += 1;
88 ctx.transform(Some(&tx)).geometry(&geo);
89 ctx.transform(Some(&tx)).geometry(&geo);
90 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(1.0, -1.0);
91
92 ctx.transform(Some(&tx)).typography(&name, 0.0, 40.0, &typo);
93 }
94 ctx
95 }
8fn main() {
9 let pen_width = 0.3;
10 let cols = 23;
11 let rows = 16;
12 let size = (cols * rows) / 2;
13 let days = 365;
14 let cellw = f64::from(size) / f64::from(cols);
15 let cellh = f64::from(size) / f64::from(rows);
16
17 let mut ctx = Context::new();
18
19 // Set the default stroke/hatch/pen.
20 ctx.stroke("black")
21 .hatch(45.0)
22 .pen(pen_width)
23 .pattern(Hatches::line())
24 .fill("black");
25
26 for day in 0..days {
27 let col = f64::from(day / rows);
28 let row = f64::from(day % rows);
29 let x = col * cellw;
30 let y = row * cellh;
31 let w = 2.0f64;
32 let h = 30.0f64;
33
34 let phi = (f64::from(day) / f64::from(days)) * PI;
35 let theta = phi.sin() * 80.0 + 45.0;
36
37 // We scale w and h by the scale here because of implementation differences
38 // between JS canvas context and our context.
39 let scale = phi.cos().abs() * 2.0 + 1.0;
40 let w = scale * w;
41 let h = scale * h;
42
43 ctx.push()
44 .transform(Some(&(Context::translate_matrix(x, y))))
45 .mask_box(cellw * -0.5, cellh * -0.5, cellw * 0.5, cellh * 0.5)
46 .transform(Some(
47 &(Context::translate_matrix(x, y) * Context::rotate_matrix(theta)),
48 ))
49 .hatch(-90.0 + theta)
50 .rect(w * -0.5, h * -0.5, w * 0.5, h * 0.5)
51 .pop()
52 .expect("Somehow lost track of my internal stack");
53 }
54
55 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
56 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
57 // to match the context's bounds, giving us back an Arrangement::Transform with the
58 // affine txform that gives us a nicely centered drawing.
59 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
60 25.4,
61 Context::viewbox(0.0, 0.0, 216.0, 216.0),
62 false,
63 ));
64
65 let document = ctx.to_svg(&arrangement).unwrap();
66
67 // Write it to the images folder, so we can use it as an example!
68 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
69 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
70 svg::save(format!("images/{}.svg", fname), &document).unwrap();
71}
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
56fn main() {
57 let pen_width = 0.5f64;
58 let size: i32 = 224;
59 let square_count = 8;
60 let white = "#F2F5F1";
61 let colors = vec!["#D40920", "#1356A2", "#F7D842"];
62 let square_weight = 2.0f64; // How thick the dividing lines are
63
64 // We're using a static random generator here so that our SVG files
65 // don't get regenerated every time we run the examples.
66 let mut rng = SmallRng::seed_from_u64(1234567);
67 let mut ctx = Context::new();
68
69 let mut squares: Vec<Rect<f64>> = vec![Rect::new(
70 coord! {x:0.0, y:0.0},
71 coord! {x: f64::from(size), y: f64::from(size)},
72 )];
73
74 // split_squares_at(&mut squares, coord!{x: f64::from(size)/2.0, y: -1.0});
75 // split_squares_at(&mut squares, coord!{x:-1.0, y: f64::from(size)/2.0});
76 for i in (0..(size)).step_by((size / square_count) as usize) {
77 split_squares_at(&mut squares, coord! {x: f64::from(i), y: -1.0}, &mut rng);
78 split_squares_at(&mut squares, coord! {x:-1.0, y: f64::from(i)}, &mut rng);
79 }
80
81 // Create an array of the same length as the squares array, and fill it with "white"
82 let mut square_colors: Vec<&str> = squares.iter().map(|_s| white.clone()).collect();
83
84 for color in colors.clone() {
85 // Note, this might overlap an existing colored square. More often than you'd think actually.
86 square_colors[rng.gen_range(0..squares.len())] = color;
87 }
88
89 // Set the default stroke/hatch/pen.
90 ctx.stroke("black").hatch(45.0).pen(pen_width);
91
92 // for square in squares {
93 for i in 0..squares.len() {
94 let square = squares[i].clone();
95 let color = square_colors[i].clone();
96
97 // Don't bother hatching if it's white.
98 if color != white {
99 ctx.pattern(Hatches::line());
100 } else {
101 ctx.pattern(Hatches::none());
102 }
103
104 // And set the fill color.
105 ctx.fill(color).rect(
106 square.min().x + square_weight,
107 square.min().y + square_weight,
108 square.max().x - square_weight,
109 square.max().y - square_weight,
110 );
111
112 // Now we just draw the rest of the outlines, inside to outside, no fill.
113 ctx.pattern(Hatches::none());
114 let mut remaining_width = square_weight - (pen_width / 2.0);
115 let s = squares[i].clone();
116 while remaining_width >= 0.0 {
117 ctx.geometry(&Geometry::Rect(Rect::new(
118 coord! {x: &s.min().x+remaining_width, y: &s.min().y+remaining_width},
119 coord! {x: &s.max().x-remaining_width, y: &s.max().y-remaining_width},
120 )));
121 remaining_width -= pen_width;
122 }
123 }
124
125 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
126 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
127 // to match the context's bounds, giving us back an Arrangement::Transform with the
128 // affine txform that gives us a nicely centered drawing.
129 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
130 25.4,
131 Context::viewbox(0.0, 0.0, 216.0, 216.0),
132 false,
133 ));
134
135 let document = ctx.to_svg(&arrangement).unwrap();
136
137 // Write it to the images folder, so we can use it as an example!
138 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
139 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
140 svg::save(format!("images/{}.svg", fname), &document).unwrap();
141}
Sourcepub fn pattern(&mut self, pattern: Hatches) -> &mut Self
pub fn pattern(&mut self, pattern: Hatches) -> &mut Self
Set the hatch pattern
Examples found in repository?
8fn main() {
9 let mut ctx = Context::new();
10 let mut typ = Typography::new();
11 typ.size(2.0);
12 typ.close(true);
13
14 ctx.stroke("black")
15 .fill("red")
16 .pen(0.5)
17 .pattern(Hatches::none())
18 // .pattern(LineHatch::gen())
19 // .typography(&"i".to_string(), 50.0, 50.0, &typ);
20 .typography(&"Left".to_string(), 50.0, 50.0, &typ);
21 typ.align(TextAlignment::Right);
22 ctx.typography(&"Right".to_string(), 50.0, 90.0, &typ);
23 typ.align(TextAlignment::Center);
24 ctx.typography(&"Center".to_string(), 50.0, 70.0, &typ);
25
26 let svg = ctx
27 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
28 coord! {x:0.0, y:0.0},
29 coord! {x:100.0, y:100.0},
30 )))
31 .unwrap();
32 // Write it to the images folder, so we can use it as an example!
33 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
34 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
35 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
36}
More examples
45 fn generate(&self) -> AOERCTX {
46 let mut ctx = AOERCTX::new();
47 let mut count = 0;
48
49 ctx.pen(1.5).accuracy(0.3);
50 if self.settings.draft {
51 ctx.pattern(Hatches::none());
52 } else {
53 ctx.pattern(Hatches::line());
54 }
55 let mut typo = Typography::new();
56 typo.size(4.5).align(Center);
57
58 for (name, geo) in CarlsonSmithTruchet::full_set()
59 .iter()
60 .filter(|(x, _y)| !x.starts_with("^"))
61 {
62 println!("Plotting {}", name);
63 let yofs: f64 = -256.0f64 + 128.0f64 * <f64 as From<i32>>::from((count / 6) as i32);
64 let xofs: f64 = -512.0f64 + 96.0f64 * <f64 as From<i32>>::from((count % 6) as i32);
65 // println!("xy is {},{}", xofs, yofs);
66 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(64.0, 64.0);
67 count += 1;
68 ctx.transform(Some(&tx)).geometry(&geo);
69 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(1.0, -1.0);
70
71 ctx.transform(Some(&tx)).typography(&name, 0.0, 60.0, &typo);
72 }
73 count = 0;
74 for (name, geo) in self
75 .full_set
76 .clone()
77 .iter()
78 .filter(|(x, _y)| x.starts_with("^"))
79 {
80 println!("Plotting inverse scale/2 {}", name);
81 let yofs: f64 =
82 -256.0f64 - 16.0f64 + 128.0f64 * <f64 as From<i32>>::from((count / 6) as i32);
83 let xofs: f64 = -512.0f64
84 + (96.0f64 * 6.0f64)
85 + 96.0f64 * <f64 as From<i32>>::from((count % 6) as i32);
86 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(32.0, 32.0);
87 count += 1;
88 ctx.transform(Some(&tx)).geometry(&geo);
89 ctx.transform(Some(&tx)).geometry(&geo);
90 let tx = AOERCTX::translate_matrix(xofs, yofs) * AOERCTX::scale_matrix(1.0, -1.0);
91
92 ctx.transform(Some(&tx)).typography(&name, 0.0, 40.0, &typo);
93 }
94 ctx
95 }
8fn main() {
9 let pen_width = 0.3;
10 let cols = 23;
11 let rows = 16;
12 let size = (cols * rows) / 2;
13 let days = 365;
14 let cellw = f64::from(size) / f64::from(cols);
15 let cellh = f64::from(size) / f64::from(rows);
16
17 let mut ctx = Context::new();
18
19 // Set the default stroke/hatch/pen.
20 ctx.stroke("black")
21 .hatch(45.0)
22 .pen(pen_width)
23 .pattern(Hatches::line())
24 .fill("black");
25
26 for day in 0..days {
27 let col = f64::from(day / rows);
28 let row = f64::from(day % rows);
29 let x = col * cellw;
30 let y = row * cellh;
31 let w = 2.0f64;
32 let h = 30.0f64;
33
34 let phi = (f64::from(day) / f64::from(days)) * PI;
35 let theta = phi.sin() * 80.0 + 45.0;
36
37 // We scale w and h by the scale here because of implementation differences
38 // between JS canvas context and our context.
39 let scale = phi.cos().abs() * 2.0 + 1.0;
40 let w = scale * w;
41 let h = scale * h;
42
43 ctx.push()
44 .transform(Some(&(Context::translate_matrix(x, y))))
45 .mask_box(cellw * -0.5, cellh * -0.5, cellw * 0.5, cellh * 0.5)
46 .transform(Some(
47 &(Context::translate_matrix(x, y) * Context::rotate_matrix(theta)),
48 ))
49 .hatch(-90.0 + theta)
50 .rect(w * -0.5, h * -0.5, w * 0.5, h * 0.5)
51 .pop()
52 .expect("Somehow lost track of my internal stack");
53 }
54
55 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
56 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
57 // to match the context's bounds, giving us back an Arrangement::Transform with the
58 // affine txform that gives us a nicely centered drawing.
59 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
60 25.4,
61 Context::viewbox(0.0, 0.0, 216.0, 216.0),
62 false,
63 ));
64
65 let document = ctx.to_svg(&arrangement).unwrap();
66
67 // Write it to the images folder, so we can use it as an example!
68 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
69 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
70 svg::save(format!("images/{}.svg", fname), &document).unwrap();
71}
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
56fn main() {
57 let pen_width = 0.5f64;
58 let size: i32 = 224;
59 let square_count = 8;
60 let white = "#F2F5F1";
61 let colors = vec!["#D40920", "#1356A2", "#F7D842"];
62 let square_weight = 2.0f64; // How thick the dividing lines are
63
64 // We're using a static random generator here so that our SVG files
65 // don't get regenerated every time we run the examples.
66 let mut rng = SmallRng::seed_from_u64(1234567);
67 let mut ctx = Context::new();
68
69 let mut squares: Vec<Rect<f64>> = vec![Rect::new(
70 coord! {x:0.0, y:0.0},
71 coord! {x: f64::from(size), y: f64::from(size)},
72 )];
73
74 // split_squares_at(&mut squares, coord!{x: f64::from(size)/2.0, y: -1.0});
75 // split_squares_at(&mut squares, coord!{x:-1.0, y: f64::from(size)/2.0});
76 for i in (0..(size)).step_by((size / square_count) as usize) {
77 split_squares_at(&mut squares, coord! {x: f64::from(i), y: -1.0}, &mut rng);
78 split_squares_at(&mut squares, coord! {x:-1.0, y: f64::from(i)}, &mut rng);
79 }
80
81 // Create an array of the same length as the squares array, and fill it with "white"
82 let mut square_colors: Vec<&str> = squares.iter().map(|_s| white.clone()).collect();
83
84 for color in colors.clone() {
85 // Note, this might overlap an existing colored square. More often than you'd think actually.
86 square_colors[rng.gen_range(0..squares.len())] = color;
87 }
88
89 // Set the default stroke/hatch/pen.
90 ctx.stroke("black").hatch(45.0).pen(pen_width);
91
92 // for square in squares {
93 for i in 0..squares.len() {
94 let square = squares[i].clone();
95 let color = square_colors[i].clone();
96
97 // Don't bother hatching if it's white.
98 if color != white {
99 ctx.pattern(Hatches::line());
100 } else {
101 ctx.pattern(Hatches::none());
102 }
103
104 // And set the fill color.
105 ctx.fill(color).rect(
106 square.min().x + square_weight,
107 square.min().y + square_weight,
108 square.max().x - square_weight,
109 square.max().y - square_weight,
110 );
111
112 // Now we just draw the rest of the outlines, inside to outside, no fill.
113 ctx.pattern(Hatches::none());
114 let mut remaining_width = square_weight - (pen_width / 2.0);
115 let s = squares[i].clone();
116 while remaining_width >= 0.0 {
117 ctx.geometry(&Geometry::Rect(Rect::new(
118 coord! {x: &s.min().x+remaining_width, y: &s.min().y+remaining_width},
119 coord! {x: &s.max().x-remaining_width, y: &s.max().y-remaining_width},
120 )));
121 remaining_width -= pen_width;
122 }
123 }
124
125 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
126 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
127 // to match the context's bounds, giving us back an Arrangement::Transform with the
128 // affine txform that gives us a nicely centered drawing.
129 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
130 25.4,
131 Context::viewbox(0.0, 0.0, 216.0, 216.0),
132 false,
133 ));
134
135 let document = ctx.to_svg(&arrangement).unwrap();
136
137 // Write it to the images folder, so we can use it as an example!
138 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
139 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
140 svg::save(format!("images/{}.svg", fname), &document).unwrap();
141}
Sourcepub fn outline(&mut self, stroke: Option<f64>) -> &mut Self
pub fn outline(&mut self, stroke: Option<f64>) -> &mut Self
Neat option. Instead of drawing a complex poly, why not just set outline, and have the lines/polys/whatever you subsequently draw get buffered and hatched to imitate a really thick pen? I knew you’d like this one :D
Examples found in repository?
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
Sourcepub fn flatten(&self) -> Self
pub fn flatten(&self) -> Self
Flatten will take a context and “flatten” together all polygons of a given color and “depth”. What that means is that we watch for changes to fill/color/etc, and set those as boundaries. Then every geometry within a set of boundaries is flattened as “unions” into a single geometry. This is nice because overlapping polygons get turned into a single unified polygon, and their fills are no longer disjoint (and they don’t have unexpected overlapping boundary lines). See the 10_hello example for more details. Unlike the other methods, this one generates an entirely new context including a NEW HISTORY, so you can’t use push/pop to go back, and the individual operations are (obviously) lost.
Examples found in repository?
97 fn on_change(&self) -> Layers {
98 let ctx = self.generate();
99 println!("Flattening...");
100 let layers = if self.settings.draft {
101 ctx.flatten().to_layers()
102 } else {
103 ctx.to_layers()
104 };
105 println!("Done flattening");
106
107 let mut out = Layers::new();
108 for layer in &layers {
109 let (strokes, fills) = layer.to_lines();
110 if self.settings.draft {
111 if out.contains_key(&layer.stroke()) {
112 let (mut orig_stroke, _orig_fill) =
113 out.get_mut(&layer.stroke()).unwrap().clone();
114 orig_stroke.0.append(&mut strokes.0.clone());
115 out.insert(
116 layer.stroke().clone(),
117 (orig_stroke.clone(), MultiLineString::new(vec![])),
118 );
119 } else {
120 out.insert(
121 layer.stroke().clone(),
122 (strokes.clone(), MultiLineString::new(vec![])),
123 );
124 }
125 } else {
126 if out.contains_key(&layer.stroke()) {
127 let (mut orig_stroke, mut orig_fill) =
128 out.get_mut(&layer.stroke()).unwrap().clone();
129 orig_stroke.0.append(&mut strokes.0.clone());
130 orig_fill.0.append(&mut fills.0.clone());
131 out.insert(layer.stroke(), (orig_stroke.clone(), orig_fill.clone()));
132 } else {
133 out.insert(layer.stroke(), (strokes.clone(), fills.clone()));
134 }
135 }
136 }
137 out
138 }
pub fn to_geo(&self) -> Result<Geometry<f64>, Box<dyn Error>>
Sourcepub fn to_layers(&self) -> Vec<OPLayer>
pub fn to_layers(&self) -> Vec<OPLayer>
Generate layers of perimeters and fills
Examples found in repository?
97 fn on_change(&self) -> Layers {
98 let ctx = self.generate();
99 println!("Flattening...");
100 let layers = if self.settings.draft {
101 ctx.flatten().to_layers()
102 } else {
103 ctx.to_layers()
104 };
105 println!("Done flattening");
106
107 let mut out = Layers::new();
108 for layer in &layers {
109 let (strokes, fills) = layer.to_lines();
110 if self.settings.draft {
111 if out.contains_key(&layer.stroke()) {
112 let (mut orig_stroke, _orig_fill) =
113 out.get_mut(&layer.stroke()).unwrap().clone();
114 orig_stroke.0.append(&mut strokes.0.clone());
115 out.insert(
116 layer.stroke().clone(),
117 (orig_stroke.clone(), MultiLineString::new(vec![])),
118 );
119 } else {
120 out.insert(
121 layer.stroke().clone(),
122 (strokes.clone(), MultiLineString::new(vec![])),
123 );
124 }
125 } else {
126 if out.contains_key(&layer.stroke()) {
127 let (mut orig_stroke, mut orig_fill) =
128 out.get_mut(&layer.stroke()).unwrap().clone();
129 orig_stroke.0.append(&mut strokes.0.clone());
130 orig_fill.0.append(&mut fills.0.clone());
131 out.insert(layer.stroke(), (orig_stroke.clone(), orig_fill.clone()));
132 } else {
133 out.insert(layer.stroke(), (strokes.clone(), fills.clone()));
134 }
135 }
136 }
137 out
138 }
Sourcepub fn to_svg(
&self,
arrangement: &Arrangement<f64>,
) -> Result<Document, ContextError>
pub fn to_svg( &self, arrangement: &Arrangement<f64>, ) -> Result<Document, ContextError>
Take this giant complex thing and generate and SVG Document, or an error. Whatever.
Examples found in repository?
8fn main() {
9 let mut ctx = Context::new();
10 let mut typ = Typography::new();
11 typ.size(2.0);
12 typ.close(true);
13
14 ctx.stroke("black")
15 .fill("red")
16 .pen(0.5)
17 .pattern(Hatches::none())
18 // .pattern(LineHatch::gen())
19 // .typography(&"i".to_string(), 50.0, 50.0, &typ);
20 .typography(&"Left".to_string(), 50.0, 50.0, &typ);
21 typ.align(TextAlignment::Right);
22 ctx.typography(&"Right".to_string(), 50.0, 90.0, &typ);
23 typ.align(TextAlignment::Center);
24 ctx.typography(&"Center".to_string(), 50.0, 70.0, &typ);
25
26 let svg = ctx
27 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
28 coord! {x:0.0, y:0.0},
29 coord! {x:100.0, y:100.0},
30 )))
31 .unwrap();
32 // Write it to the images folder, so we can use it as an example!
33 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
34 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
35 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
36}
More examples
8fn main() {
9 let pen_width = 0.3;
10 let cols = 23;
11 let rows = 16;
12 let size = (cols * rows) / 2;
13 let days = 365;
14 let cellw = f64::from(size) / f64::from(cols);
15 let cellh = f64::from(size) / f64::from(rows);
16
17 let mut ctx = Context::new();
18
19 // Set the default stroke/hatch/pen.
20 ctx.stroke("black")
21 .hatch(45.0)
22 .pen(pen_width)
23 .pattern(Hatches::line())
24 .fill("black");
25
26 for day in 0..days {
27 let col = f64::from(day / rows);
28 let row = f64::from(day % rows);
29 let x = col * cellw;
30 let y = row * cellh;
31 let w = 2.0f64;
32 let h = 30.0f64;
33
34 let phi = (f64::from(day) / f64::from(days)) * PI;
35 let theta = phi.sin() * 80.0 + 45.0;
36
37 // We scale w and h by the scale here because of implementation differences
38 // between JS canvas context and our context.
39 let scale = phi.cos().abs() * 2.0 + 1.0;
40 let w = scale * w;
41 let h = scale * h;
42
43 ctx.push()
44 .transform(Some(&(Context::translate_matrix(x, y))))
45 .mask_box(cellw * -0.5, cellh * -0.5, cellw * 0.5, cellh * 0.5)
46 .transform(Some(
47 &(Context::translate_matrix(x, y) * Context::rotate_matrix(theta)),
48 ))
49 .hatch(-90.0 + theta)
50 .rect(w * -0.5, h * -0.5, w * 0.5, h * 0.5)
51 .pop()
52 .expect("Somehow lost track of my internal stack");
53 }
54
55 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
56 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
57 // to match the context's bounds, giving us back an Arrangement::Transform with the
58 // affine txform that gives us a nicely centered drawing.
59 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
60 25.4,
61 Context::viewbox(0.0, 0.0, 216.0, 216.0),
62 false,
63 ));
64
65 let document = ctx.to_svg(&arrangement).unwrap();
66
67 // Write it to the images folder, so we can use it as an example!
68 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
69 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
70 svg::save(format!("images/{}.svg", fname), &document).unwrap();
71}
7fn main() {
8 let mut ctx = Context::new();
9 ctx.stroke("black")
10 .fill("red")
11 .pen(0.5)
12 .outline(Some(5.0))
13 .hatch(45.0)
14 .poly(
15 vec![(0.0, 0.0), (25.0, 0.0), (25.0, 25.0), (0.0, 25.0)],
16 vec![],
17 )
18 .outline(None)
19 .pattern(Hatches::line())
20 .hatch(135.0)
21 .stroke("blue")
22 .fill("yellow")
23 .circle(12.5, 12.5, 5.0)
24 .push()
25 .hatch(180.0)
26 .stroke("red")
27 .fill("green")
28 .circle(17.5, 12.5, 2.5)
29 .pop()
30 .unwrap()
31 .hatch(0.0)
32 .pattern(Hatches::none())
33 .clip(true)
34 .circle(7.5, 12.5, 2.5)
35 .clip(false)
36 .stroke("brown")
37 .pen(1.0)
38 .line(0.0, 0.0, 3.0, 3.0)
39 .pen(0.1)
40 .outline(Some(1.0))
41 .stroke("pink")
42 .line(3.0, 0.0, 0.0, 3.0)
43 .stroke("purple")
44 .spline(
45 &vec![
46 (0.0, 25.0),
47 (0.0, 25.0),
48 (10.0, 20.0),
49 (20.0, 25.0),
50 (25.0, 25.0),
51 ],
52 8,
53 0.5,
54 )
55 .push() // Prepare for this transformation stuff...
56 .transform(Some(
57 &(Context::translate_matrix(25.0, 25.0)
58 * Context::rotate_matrix(45.0)
59 * Context::scale_matrix(1.0, 0.5)),
60 )) // Holy crap we can multiply these?! ;)
61 .stroke("cyan")
62 .circle(0.0, 0.0, 8.0)
63 .pop()
64 .unwrap() // We're back to purple and regular coords
65 .outline(None)
66 .stroke("green")
67 .regular_poly(8, 80.0, 80.0, 20.0, 0.0)
68 .star_poly(5, 30.0, 80.0, 10.0, 20.0, 0.0)
69 .transform(Some(
70 &(Context::translate_matrix(50.0, 50.0) * Context::scale_matrix(0.02, -0.02)),
71 ))
72 .pattern(Hatches::none())
73 .pattern(Hatches::line())
74 .glyph('Q', false);
75
76 let svg = ctx
77 .to_svg(&Arrangement::<f64>::unit(&Rect::<f64>::new(
78 coord! {x:0.0, y:0.0},
79 coord! {x:100.0, y:100.0},
80 )))
81 .unwrap();
82 // Write it to the images folder, so we can use it as an example!
83 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
84 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
85 svg::save(format!("images/{}.svg", fname), &svg).unwrap();
86}
56fn main() {
57 let pen_width = 0.5f64;
58 let size: i32 = 224;
59 let square_count = 8;
60 let white = "#F2F5F1";
61 let colors = vec!["#D40920", "#1356A2", "#F7D842"];
62 let square_weight = 2.0f64; // How thick the dividing lines are
63
64 // We're using a static random generator here so that our SVG files
65 // don't get regenerated every time we run the examples.
66 let mut rng = SmallRng::seed_from_u64(1234567);
67 let mut ctx = Context::new();
68
69 let mut squares: Vec<Rect<f64>> = vec![Rect::new(
70 coord! {x:0.0, y:0.0},
71 coord! {x: f64::from(size), y: f64::from(size)},
72 )];
73
74 // split_squares_at(&mut squares, coord!{x: f64::from(size)/2.0, y: -1.0});
75 // split_squares_at(&mut squares, coord!{x:-1.0, y: f64::from(size)/2.0});
76 for i in (0..(size)).step_by((size / square_count) as usize) {
77 split_squares_at(&mut squares, coord! {x: f64::from(i), y: -1.0}, &mut rng);
78 split_squares_at(&mut squares, coord! {x:-1.0, y: f64::from(i)}, &mut rng);
79 }
80
81 // Create an array of the same length as the squares array, and fill it with "white"
82 let mut square_colors: Vec<&str> = squares.iter().map(|_s| white.clone()).collect();
83
84 for color in colors.clone() {
85 // Note, this might overlap an existing colored square. More often than you'd think actually.
86 square_colors[rng.gen_range(0..squares.len())] = color;
87 }
88
89 // Set the default stroke/hatch/pen.
90 ctx.stroke("black").hatch(45.0).pen(pen_width);
91
92 // for square in squares {
93 for i in 0..squares.len() {
94 let square = squares[i].clone();
95 let color = square_colors[i].clone();
96
97 // Don't bother hatching if it's white.
98 if color != white {
99 ctx.pattern(Hatches::line());
100 } else {
101 ctx.pattern(Hatches::none());
102 }
103
104 // And set the fill color.
105 ctx.fill(color).rect(
106 square.min().x + square_weight,
107 square.min().y + square_weight,
108 square.max().x - square_weight,
109 square.max().y - square_weight,
110 );
111
112 // Now we just draw the rest of the outlines, inside to outside, no fill.
113 ctx.pattern(Hatches::none());
114 let mut remaining_width = square_weight - (pen_width / 2.0);
115 let s = squares[i].clone();
116 while remaining_width >= 0.0 {
117 ctx.geometry(&Geometry::Rect(Rect::new(
118 coord! {x: &s.min().x+remaining_width, y: &s.min().y+remaining_width},
119 coord! {x: &s.max().x-remaining_width, y: &s.max().y-remaining_width},
120 )));
121 remaining_width -= pen_width;
122 }
123 }
124
125 // We're using a new feature here: Create a FitCenterMargin Arrangement that matches
126 // the paper size we're using (8.5" square). Then, finalize it's transformation matrix
127 // to match the context's bounds, giving us back an Arrangement::Transform with the
128 // affine txform that gives us a nicely centered drawing.
129 let arrangement = ctx.finalize_arrangement(&Arrangement::FitCenterMargin(
130 25.4,
131 Context::viewbox(0.0, 0.0, 216.0, 216.0),
132 false,
133 ));
134
135 let document = ctx.to_svg(&arrangement).unwrap();
136
137 // Write it to the images folder, so we can use it as an example!
138 // Write it out to /images/$THIS_EXAMPLE_FILE.svg
139 let fname = Path::new(file!()).file_stem().unwrap().to_str().unwrap();
140 svg::save(format!("images/{}.svg", fname), &document).unwrap();
141}
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Context
impl RefUnwindSafe for Context
impl !Send for Context
impl !Sync for Context
impl Unpin for Context
impl UnwindSafe for Context
Blanket Implementations§
Source§impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for S
impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for S
Source§fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<Swp, Dwp, T>,
fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<Swp, Dwp, T>,
Source§fn adapt_into(self) -> D
fn adapt_into(self) -> D
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T, U> ConvertInto<U> for Twhere
U: ConvertFrom<T>,
impl<T, U> ConvertInto<U> for Twhere
U: ConvertFrom<T>,
Source§fn convert_into(self) -> U
fn convert_into(self) -> U
Source§fn convert_unclamped_into(self) -> U
fn convert_unclamped_into(self) -> U
Source§fn try_convert_into(self) -> Result<U, OutOfBounds<U>>
fn try_convert_into(self) -> Result<U, OutOfBounds<U>>
OutOfBounds
error is returned which contains the unclamped color. Read moreSource§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self
from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self
is actually part of its subset T
(and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset
but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self
to the equivalent element of its superset.