animate/canvas/rough/fillers/
dot.rs

1use super::polygon_hachure_lines;
2use crate::{
3    canvas::rough::{
4        geometry::line_length, Line, Op, OpSet, OpSetType, PatternFiller, RenderHelper,
5        RoughOptions,
6    },
7    Point,
8};
9
10pub struct DotFiller<H: RenderHelper> {
11    helper: H,
12}
13
14// implements PatternFiller
15impl<H: RenderHelper> DotFiller<H> {
16    pub fn new(helper: H) -> Self {
17        Self { helper }
18    }
19
20    fn fill_polygon(&self, points: Vec<Point<f64>>, options: &RoughOptions) -> OpSet {
21        // o = Object.assign({}, o, { curveStepCount: 4, hachureAngle: 0, roughness: 1 });
22        let lines = polygon_hachure_lines(&points, options);
23        self.dots_on_lines(lines, options)
24    }
25
26    fn dots_on_lines(&self, lines: Vec<Line<f64>>, options: &RoughOptions) -> OpSet {
27        let ops: Vec<Op> = Vec::new();
28
29        let gap = if options.hachure_gap < 0.0 {
30            (options.stroke_width * 4.0).max(0.1)
31        } else {
32            options.hachure_gap.max(0.1)
33        };
34
35        let mut fweight = options.fill_weight;
36        if fweight < 0.0 {
37            fweight = options.stroke_width / 2.0;
38        }
39        let ro = gap / 4.0;
40
41        for line in lines.iter() {
42            let length = line_length(line);
43            let dl = length / gap;
44            let count = (dl.ceil() - 1.0) as usize;
45            let offset = length - (count as f64 * gap);
46            let x = ((line.start.x + line.end.x) / 2.0) - (gap / 4.0);
47            let min_y = line.start.y.min(line.end.y);
48
49            for i in 0..count {
50                let y = min_y + offset + (i as f64 * gap);
51                let cx = self.helper.rand_offset_with_range(x - ro, x + ro, options);
52                let cy = self.helper.rand_offset_with_range(y - ro, y + ro, options);
53                let el = self.helper.ellipse(cx, cy, fweight, fweight, options);
54                //     ops.push(...el.ops);
55            }
56        }
57
58        OpSet {
59            kind: OpSetType::FillSketch,
60            ops,
61            size: None,
62            path: None,
63        }
64    }
65}