Guard against over-refinement of offset curves near cusps#259
Draft
gpeairs wants to merge 3 commits into
Draft
Conversation
gpeairs
marked this pull request as draft
July 14, 2026 16:08
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The curvature of an offset curve can diverge when the offset crosses through the curvature radius of the base curve (that is, near a cusp of the offset curve). This leads to extreme refinement near cusps even when unnecessary for tolerance, now that offset curves are discretized based on their own curvature rather than that of the base curve (following #236).
This PR clamps the effective ratio between curvature radius of base and offset curves used by the marching kernel to discretize the offset curve to
R_kernel / R_base = 0.1. While this looks like a relative guard, you can derive a bound on absolute error if you linearize the base curvature radiusRnear a cusp at arclengths_c(whereR = d). The value that we're clamping to a minimum ofε=0.1is|1 − d·κ(s)| ≈ (|R′|/d)·|s − s_c|, withR′ = dR_base/dsdimensionless and O(1) for a smooth spline. Then the clamp leaves the marching step nearby atΔs = √(8·tol·d·ε), and if this step straddles the cusp, the offset curve's max excursion from the resulting chord ise = |R′|·Δs²/(8d) ≈ ε · |dR/ds| · tol. So 0.1 is pretty conservative and won't hurt well-behaved curves without cusps.Note that this doesn't repair curves with cusps (e.g. by clipping out any closed region created by self-intersection), so users can still create pathological geometry at their own risk (but now at least they get warnings during rendering). This change just prevents the curve from being sampled excessively near cusps.
Addresses the issue described at the end of the #243 thread as far as over-refinement is concerned, but because the sampled curve may still self-intersect, it does not necessarily survive clipping, in which case curve recovery will still fail. However, even if it succeeded by partial matching of clipped runs, you'd be left with a self-intersecting polygon / negative-area loop.
Edit: Draft while a fix to the cusp warning is in progress.