use std::borrow::BorrowMut;
use std::marker::PhantomData;
use euclid::default::Point2D;
use euclid::{point2, Trig};
use num_traits::{Float, FromPrimitive};
use super::scan_line_hachure::polygon_hachure_lines;
use super::traits::PatternFiller;
use crate::core::{OpSet, Options, _c};
use crate::geometry::Line;
use crate::renderer::_double_line;
pub struct DashedFiller<F> {
_phantom: PhantomData<F>,
}
impl<F, P> PatternFiller<F, P> for DashedFiller<F>
where
F: Float + Trig + FromPrimitive,
P: BorrowMut<Vec<Vec<Point2D<F>>>>,
{
fn fill_polygons(&self, mut polygon_list: P, o: &mut Options) -> crate::core::OpSet<F> {
let lines = polygon_hachure_lines(polygon_list.borrow_mut(), o);
let ops = DashedFiller::dashed_line(lines, o);
OpSet {
op_set_type: crate::core::OpSetType::FillSketch,
ops,
size: None,
path: None,
}
}
}
impl<'a, F: Float + Trig + FromPrimitive> DashedFiller<F> {
pub fn new() -> Self {
DashedFiller { _phantom: PhantomData }
}
fn dashed_line(lines: Vec<Line<F>>, o: &mut Options) -> Vec<crate::core::Op<F>> {
let dash_offset: F = o.dash_offset.map(_c).unwrap_or_else(|| _c(-1.0));
let offset = if dash_offset < _c(0.0) {
let hachure_gap: F = o.hachure_gap.map(_c).unwrap_or_else(|| _c(-1.0));
if hachure_gap < _c(0.0) {
o.stroke_width.map(_c::<F>).unwrap_or_else(|| _c(1.0)) * _c(4.0)
} else {
hachure_gap
}
} else {
dash_offset
};
let dash_gap = o.dash_gap.map(_c).unwrap_or_else(|| _c(-1.0));
let gap: F = if dash_gap < _c(0.0) {
let hachure_gap = o.hachure_gap.map(_c).unwrap_or_else(|| _c(-1.0));
if hachure_gap < _c(0.0) {
o.stroke_width.map(_c::<F>).unwrap_or_else(|| _c(1.0)) * _c(4.0)
} else {
hachure_gap
}
} else {
dash_gap
};
let mut ops = vec![];
for line in lines.iter() {
let length = line.length();
let count = (length / (offset + gap)).floor();
let start_offset = (length + gap - (count * (offset + gap))) / _c(2.0);
let mut p1 = line.start_point;
let mut p2 = line.end_point;
if p1.x > p2.x {
p1 = line.end_point;
p2 = line.start_point;
}
let alpha = ((p2.y - p1.y) / (p2.x - p1.x)).atan();
for i in 0..count.to_u32().unwrap() {
let lstart = F::from(i).unwrap() * (offset + gap);
let lend = lstart + offset;
let start: Point2D<F> = point2(
p1.x + (lstart * num_traits::Float::cos(alpha))
+ (start_offset * num_traits::Float::cos(alpha)),
p1.y + lstart * num_traits::Float::sin(alpha)
+ (start_offset * num_traits::Float::sin(alpha)),
);
let end: Point2D<F> = point2(
p1.x + (lend * num_traits::Float::cos(alpha))
+ (start_offset * num_traits::Float::cos(alpha)),
p1.y + (lend * num_traits::Float::sin(alpha))
+ (start_offset * num_traits::Float::sin(alpha)),
);
let line_ops = _double_line(start.x, start.y, end.x, end.y, o, false);
ops.extend(line_ops);
}
}
ops
}
}