Struct Context

Source
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)
;

context_basic

Implementations§

Source§

impl Context

Source

pub fn accuracy(&mut self, accuracy: f64) -> &mut Self

Set accuracy (allowed tolerance) in mm

Examples found in repository?
examples/carlson_smith_gallery_nannou.rs (line 49)
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    }
Source

pub fn default_font() -> Font

Default font

Source

pub fn finalize_arrangement( &self, arrangement: &Arrangement<f64>, ) -> Arrangement<f64>

Finalize Arrangement

Examples found in repository?
examples/ga_09_hours_of_dark.rs (lines 59-63)
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
Hide additional examples
examples/ga_08_piet_mondrian.rs (lines 129-133)
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}
Source

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?
examples/ga_09_hours_of_dark.rs (line 61)
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
Hide additional examples
examples/ga_08_piet_mondrian.rs (line 131)
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}
Source

pub fn scale_matrix(sx: f64, sy: f64) -> Affine2<f64>

Helper to create a scaling matrix

Examples found in repository?
examples/carlson_smith_gallery_nannou.rs (line 66)
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
Hide additional examples
examples/context_basic.rs (line 59)
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}
Source

pub fn unit_matrix() -> Affine2<f64>

Unit matrix. Basically a no-op

Source

pub fn translate_matrix(tx: f64, ty: f64) -> Affine2<f64>

Helper to create a translation matrix

Examples found in repository?
examples/carlson_smith_gallery_nannou.rs (line 66)
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
Hide additional examples
examples/ga_09_hours_of_dark.rs (line 44)
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}
examples/context_basic.rs (line 57)
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}
Source

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?
examples/ga_09_hours_of_dark.rs (line 47)
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
Hide additional examples
examples/context_basic.rs (line 58)
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}
Source

pub fn new() -> Context

I can haz a new default drawing context?

Examples found in repository?
examples/typography.rs (line 9)
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
Hide additional examples
examples/carlson_smith_fibo_nannou.rs (line 28)
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    }
examples/carlson_smith_gallery_nannou.rs (line 46)
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    }
examples/ga_09_hours_of_dark.rs (line 17)
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}
examples/context_basic.rs (line 8)
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}
examples/ga_08_piet_mondrian.rs (line 67)
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}
Source

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.

Source

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.

Source

pub fn mask_box(&mut self, x0: f64, y0: f64, x1: f64, y1: f64) -> &mut Self

Examples found in repository?
examples/ga_09_hours_of_dark.rs (line 45)
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}
Source

pub fn set_mask(&mut self, mask: &Option<Geometry<f64>>) -> &mut Self

Sets the mask to Geometry, or None.

Source

pub fn push(&mut self) -> &mut Self

Pushes the current context onto the stack.

Examples found in repository?
examples/ga_09_hours_of_dark.rs (line 43)
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
Hide additional examples
examples/context_basic.rs (line 24)
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}
Source

pub fn pop(&mut self) -> Result<&mut Self, ContextError>

Pops the previous context off the stack

Examples found in repository?
examples/ga_09_hours_of_dark.rs (line 51)
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
Hide additional examples
examples/context_basic.rs (line 29)
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}
Source

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?
examples/carlson_smith_gallery_nannou.rs (line 68)
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
Hide additional examples
examples/ga_09_hours_of_dark.rs (line 44)
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}
examples/context_basic.rs (lines 56-60)
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}
Source

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.

Source

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?
examples/carlson_smith_gallery_nannou.rs (line 68)
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
Hide additional examples
examples/ga_08_piet_mondrian.rs (lines 117-120)
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}
Source

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?
examples/context_basic.rs (line 38)
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}
Source

pub fn typography( &mut self, text: &String, x0: f64, y0: f64, typography: &Typography, ) -> &mut Self

Draws a line of text

Examples found in repository?
examples/typography.rs (line 20)
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
Hide additional examples
examples/carlson_smith_gallery_nannou.rs (line 71)
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    }
Source

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?
examples/context_basic.rs (line 74)
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}
Source

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.

Source

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?
examples/context_basic.rs (lines 44-54)
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}
Source

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.

Source

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?
examples/ga_09_hours_of_dark.rs (line 50)
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
Hide additional examples
examples/ga_08_piet_mondrian.rs (lines 105-110)
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}
Source

pub fn poly( &mut self, exterior: Vec<(f64, f64)>, interiors: Vec<Vec<(f64, f64)>>, ) -> &mut Self

Draws a polygon

Examples found in repository?
examples/context_basic.rs (lines 14-17)
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}
Source

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?
examples/context_basic.rs (line 23)
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}
Source

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?
examples/context_basic.rs (line 67)
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}
Source

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?
examples/context_basic.rs (line 68)
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}
Source

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?
examples/context_basic.rs (line 33)
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}
Source

pub fn stroke(&mut self, color: &str) -> &mut Self

Sets the stroke color

Examples found in repository?
examples/typography.rs (line 14)
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
Hide additional examples
examples/ga_09_hours_of_dark.rs (line 20)
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}
examples/context_basic.rs (line 9)
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}
examples/ga_08_piet_mondrian.rs (line 90)
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}
Source

pub fn fill(&mut self, color: &str) -> &mut Self

Sets the fill color

Examples found in repository?
examples/typography.rs (line 15)
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
Hide additional examples
examples/ga_09_hours_of_dark.rs (line 24)
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}
examples/context_basic.rs (line 10)
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}
examples/ga_08_piet_mondrian.rs (line 105)
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}
Source

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?
examples/ga_09_hours_of_dark.rs (line 21)
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
Hide additional examples
examples/context_basic.rs (line 13)
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}
examples/ga_08_piet_mondrian.rs (line 90)
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}
Source

pub fn pen(&mut self, width: f64) -> &mut Self

Sets the pen width

Examples found in repository?
examples/typography.rs (line 16)
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
Hide additional examples
examples/carlson_smith_gallery_nannou.rs (line 49)
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    }
examples/ga_09_hours_of_dark.rs (line 22)
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}
examples/context_basic.rs (line 11)
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}
examples/ga_08_piet_mondrian.rs (line 90)
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}
Source

pub fn pattern(&mut self, pattern: Hatches) -> &mut Self

Set the hatch pattern

Examples found in repository?
examples/typography.rs (line 17)
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
Hide additional examples
examples/carlson_smith_gallery_nannou.rs (line 51)
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    }
examples/ga_09_hours_of_dark.rs (line 23)
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}
examples/context_basic.rs (line 19)
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}
examples/ga_08_piet_mondrian.rs (line 99)
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}
Source

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?
examples/context_basic.rs (line 12)
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}
Source

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?
examples/carlson_smith_gallery_nannou.rs (line 101)
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    }
Source

pub fn to_geo(&self) -> Result<Geometry<f64>, Box<dyn Error>>

Source

pub fn to_layers(&self) -> Vec<OPLayer>

Generate layers of perimeters and fills

Examples found in repository?
examples/carlson_smith_gallery_nannou.rs (line 101)
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    }
Source

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?
examples/typography.rs (lines 27-30)
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
Hide additional examples
examples/ga_09_hours_of_dark.rs (line 65)
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}
examples/context_basic.rs (lines 77-80)
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}
examples/ga_08_piet_mondrian.rs (line 135)
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§

Source§

impl Clone for Context

Source§

fn clone(&self) -> Context

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for S
where T: Component + Float, Swp: WhitePoint, Dwp: WhitePoint, D: AdaptFrom<S, Swp, Dwp, T>,

Source§

fn adapt_into_using<M>(self, method: M) -> D
where M: TransformMatrix<Swp, Dwp, T>,

Convert the source color to the destination color using the specified method
Source§

fn adapt_into(self) -> D

Convert the source color to the destination color using the bradford method by default
Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T, U> ConvertInto<U> for T
where U: ConvertFrom<T>,

Source§

fn convert_into(self) -> U

Convert into T with values clamped to the color defined bounds Read more
Source§

fn convert_unclamped_into(self) -> U

Convert into T. The resulting color might be invalid in its color space Read more
Source§

fn try_convert_into(self) -> Result<U, OutOfBounds<U>>

Convert into T, returning ok if the color is inside of its defined range, otherwise an OutOfBounds error is returned which contains the unclamped color. Read more
Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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 more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

Source§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
Source§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
Source§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
Source§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>

Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> ErasedDestructor for T
where T: 'static,