animate/canvas/rough/fillers/
dot.rs1use 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
14impl<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 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 }
56 }
57
58 OpSet {
59 kind: OpSetType::FillSketch,
60 ops,
61 size: None,
62 path: None,
63 }
64 }
65}