roughr/filler/
zig_zag_filler.rs1use 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}