mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-31 21:27:00 -06:00
PDF import: a mesh-painted stroke's outline keeps dash and tolerance in reason
This commit is contained in:
@@ -245,6 +245,8 @@ pub(super) fn stroke_layer(paint: Paint, opacity: f32, p: &StrokeProps, scale: f
|
||||
|
||||
/// The most entries of a dash array kept (an even count keeps it a pattern of dashes and gaps).
|
||||
const MAX_DASH_ENTRIES: usize = 64;
|
||||
/// Most dash periods [`stroke_outline`] cuts a stroke into.
|
||||
const MAX_OUTLINE_DASHES: f64 = 1e5;
|
||||
|
||||
/// The area stroke `p` paints along `path` (in its own space, before `transform`), in the document:
|
||||
/// where a shading painting the stroke shows. Width, caps, joins and dashes as [`stroke_layer`]
|
||||
@@ -258,11 +260,14 @@ pub(super) fn stroke_outline(path: &BezPath, transform: Affine, p: &StrokeProps)
|
||||
kurbo::Stroke::new(line_width(p, scale) / scale).with_join(p.line_join).with_caps(p.line_cap).with_miter_limit(p.miter_limit as f64);
|
||||
let dashes: Vec<f64> = p.dash_array.iter().take(MAX_DASH_ENTRIES).map(|v| *v as f64).collect();
|
||||
let dash = Dash { pattern: dashes.clone(), offset: p.dash_offset as f64, align_corners: false };
|
||||
if dash.is_dashed() {
|
||||
// A dash pattern far finer than the path would cut it into countless pieces: it strokes solid.
|
||||
let period: f64 = dashes.iter().sum();
|
||||
if dash.is_dashed() && period > 0.0 && kurbo::Shape::perimeter(path, 1e-3) / period < MAX_OUTLINE_DASHES {
|
||||
style = style.with_dashes(dash.offset, dashes);
|
||||
}
|
||||
// To a hundredth of a point in the document.
|
||||
let mut out = kurbo::stroke(path.iter(), &style, &kurbo::StrokeOpts::default(), 0.01 / scale);
|
||||
// To a hundredth of a point in the document, within reason at extreme scales.
|
||||
let tolerance = (0.01 / scale).clamp(1e-4, 1.0);
|
||||
let mut out = kurbo::stroke(path.iter(), &style, &kurbo::StrokeOpts::default(), tolerance);
|
||||
out.apply_affine(transform);
|
||||
(!out.elements().is_empty()).then_some(out)
|
||||
}
|
||||
@@ -301,3 +306,22 @@ pub(super) fn resize_alpha(a: &LumaData, w: u32, h: u32) -> Vec<u8> {
|
||||
None => vec![255; (w * h) as usize],
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod stroke_outline_tests {
|
||||
use super::*;
|
||||
|
||||
/// A dash pattern far finer than the path strokes it solid instead of cutting it into
|
||||
/// millions of pieces; one in reason dashes it.
|
||||
#[test]
|
||||
fn a_dash_far_finer_than_the_path_strokes_solid() {
|
||||
let mut path = BezPath::new();
|
||||
path.move_to((0.0, 0.0));
|
||||
path.line_to((1000.0, 0.0));
|
||||
let props = |dash: f32| StrokeProps { line_width: 2.0, dash_array: [dash; 4].into(), ..StrokeProps::default() };
|
||||
let solid = stroke_outline(&path, Affine::IDENTITY, &props(1e-6)).unwrap();
|
||||
assert!(solid.elements().len() < 20, "{} elements", solid.elements().len());
|
||||
let dashed = stroke_outline(&path, Affine::IDENTITY, &props(10.0)).unwrap();
|
||||
assert!(dashed.elements().len() > 100, "dashed: {} elements", dashed.elements().len());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user