diff --git a/crates/effects/src/generate3/paths.rs b/crates/effects/src/generate3/paths.rs index 03f041673..9158a274e 100644 --- a/crates/effects/src/generate3/paths.rs +++ b/crates/effects/src/generate3/paths.rs @@ -388,10 +388,12 @@ pub(super) fn vegas(ctx: &EffectCtx, mut b: Buf) -> Buf { } /// Sub-samples per Vegas segment: at least 12 (opacity ramp), more for long segments so each straight piece stays -/// short compared with the stroke width and the segment follows rounded corners smoothly. +/// short compared with the stroke width and the segment follows rounded corners smoothly. Always even. pub(super) fn vegas_substeps(each: f64, width: f64) -> usize { let step = width.max(2.0); - ((each / step).ceil().max(12.0) as usize).min(512) + let n = ((each / step).ceil().max(12.0) as usize).min(512); + // Even, so the segment's midpoint (0.5) is always one of the samples. + n + (n & 1) } fn vegas_plan(ctx: &EffectCtx, b: &Buf) -> PaintPlan { diff --git a/crates/effects/src/generate3/tests.rs b/crates/effects/src/generate3/tests.rs index cf05842f5..8c2bbff82 100644 --- a/crates/effects/src/generate3/tests.rs +++ b/crates/effects/src/generate3/tests.rs @@ -401,7 +401,8 @@ fn vegas_long_segments_are_sampled_finely() { // A short segment keeps the 12 samples; a long one gets more so it bends smoothly round rounded corners. assert_eq!(super::paths::vegas_substeps(10.0, 4.0), 12); let n = super::paths::vegas_substeps(400.0, 4.0); - assert!(n > 12, "{n}"); + assert!(n > 12 && n % 2 == 0, "{n}"); + assert_eq!(super::paths::vegas_substeps(13.0 * 4.0, 4.0) % 2, 0); assert!(400.0 / n as f64 <= 4.0 + 1e-9); assert_eq!(super::paths::vegas_substeps(1.0e9, 4.0), 512); }