roughr/filler/
zig_zag_filler.rs

1use std::borrow::BorrowMut;
2use std::marker::PhantomData;
3
4use euclid::default::Point2D;
5use euclid::{point2, Trig};
6use num_traits::{Float, FloatConst, FromPrimitive};
7
8use super::scan_line_hachure::polygon_hachure_lines;
9use super::traits::PatternFiller;
10use crate::core::{OpSet, OpSetType, Options, _c};
11use crate::geometry::Line;
12
13pub struct ZigZagFiller<F> {
14    _phantom: PhantomData<F>,
15}
16
17impl<F, P> PatternFiller<F, P> for ZigZagFiller<F>
18where
19    F: Float + Trig + FromPrimitive,
20    P: BorrowMut<Vec<Vec<Point2D<F>>>>,
21{
22    fn fill_polygons(&self, mut polygon_list: P, o: &mut Options) -> crate::core::OpSet<F> {
23        let mut gap = o.hachure_gap.map(_c::<F>).unwrap_or_else(|| _c::<F>(-1.0));
24        if gap < F::zero() {
25            gap = o.stroke_width.map(_c::<F>).unwrap_or_else(|| _c::<F>(1.0)) * _c::<F>(4.0);
26        }
27        gap = gap.max(_c::<F>(0.1));
28        let mut o2 = o.clone();
29        o2.set_hachure_gap(Some(gap.to_f32().unwrap()));
30        let lines = polygon_hachure_lines(polygon_list.borrow_mut(), &o2);
31        let zig_zag_angle =
32            (_c::<F>(f32::PI()) / _c::<F>(180.0)) * _c::<F>(o.hachure_angle.unwrap_or(0.0));
33        let mut zig_zag_lines = vec![];
34        let dgx = gap * _c::<F>(0.5) * Trig::cos(zig_zag_angle);
35        let dgy = gap * _c::<F>(0.5) * Trig::sin(zig_zag_angle);
36
37        for line in lines.iter() {
38            if line.length() > _c::<F>(0.0) {
39                zig_zag_lines.push(Line {
40                    start_point: point2(line.start_point.x - dgx, line.start_point.y + dgy),
41                    end_point: line.end_point,
42                });
43                zig_zag_lines.push(Line {
44                    start_point: point2(line.start_point.x + dgx, line.start_point.y - dgy),
45                    end_point: line.end_point,
46                });
47            }
48        }
49
50        let ops = ZigZagFiller::render_lines(zig_zag_lines, o);
51        return OpSet {
52            ops,
53            op_set_type: OpSetType::FillSketch,
54            size: None,
55            path: None,
56        };
57    }
58}
59
60impl<F: Float + Trig + FromPrimitive> ZigZagFiller<F> {
61    pub fn new() -> Self {
62        ZigZagFiller { _phantom: PhantomData }
63    }
64
65    fn render_lines(lines: Vec<Line<F>>, o: &mut Options) -> Vec<crate::core::Op<F>> {
66        let mut ops: Vec<crate::core::Op<F>> = vec![];
67        lines.iter().for_each(|l| {
68            ops.extend(crate::renderer::_double_line(
69                l.start_point.x,
70                l.start_point.y,
71                l.end_point.x,
72                l.end_point.y,
73                o,
74                true,
75            ))
76        });
77
78        ops
79    }
80}