w3c / svgwg

SVG Working Group specifications
Other
711 stars 133 forks source link

Alternative arcs join fallback heuristics (SVG 2 sec 13.5.7,9) #771

Open skef opened 4 years ago

skef commented 4 years ago

This is in reference to sections 13.5.7 and 13.5.9 of the current SVG 2 draft.

(Note that this issue was substantially rewritten June 28 2020.)

The "round" fallback

In the sub-section of 13.5.7 that starts with "The line join shape for a given segment of a subpath ...", Item number 10 reads:

If stroke-linejoin is arcs, then find the circles that are tangent to the stroke edges at P1 and P2 with the same curvature as the edges at those points (see below). If both curvatures are zero fall through to miter-clip. If either curvature is greater than 2/(stroke width), fallback to round. Extend the stroke edges using these circles (or a line, in the case of zero curvature). If the two circles (or circle and line) do not intersect, adjust the radii of the two circles by an equal amount (or just the circle in case of a circle and line) until they do intersect (see below).

After implementing arcs joins a few times I've come to think of the round fallback rule as somewhat arbitrary. It seems as though there are two problems it is meant to address:

  1. Avoiding the extension of "inverted" curvatures due to (being on "the other side" of) offset cusps.
  2. Eliminating some of the more extreme discontinuous curvature due to non-intersecting osculating circles at the offsets (the 13.5.9 stuff).

I agree that problem 1 needs to be addressed but it could be directly targeted by the rule: "If the sign of either offset curvature differs from that of the path-end curvature, fallback to 'round'.", which is not any harder to implement than the current guideline.

As for problem 2 the current heuristic is very non-specific. Consider these two slightly differing join geometries:

join_arcs join_round

The difference is a slightly smaller radius of curvature on the "e" side. The first join looks fine to my eyes and in both cases the "original" osculating circles intersect. Why fall back to round in the second case?

On the other hand you have joins like the following:

join_big_adjust

In this case the "s" side adjustment results in a very visible discontinuity of curvature which the current fallback rule doesn't prevent.

I therefore think it would be preferable to address problem 2 in one of these two ways:

  1. Have a rule limiting the ratio of original and adjusted radii to something between 2:1 and 5:1, with a fallback to round.
  2. Do nothing.

I currently weakly favor a version of alternative 1 with a higher cutoff -- maybe around 4:1 -- but other people are in a better position to make subjective design judgments than I am.

The "parallel" case

This is more of a nit/spec optimization.

A later part of section 13.5.9 describes how to construct a rectangle when the tangent offsets are parallel. This is a waste of descriptive energy as you'll get the same result from falling back to a miter-clip join. So I would change the second sentence of "item 10" quoted above to:

"If both curvatures are zero or the tangents of the offset paths are parallel fall through to miter-clip".

And eliminate the rest of the language.

skef commented 4 years ago

(Heads up @Tavmjong ...)

skef commented 4 years ago

On second thought about the second problem: the fallback only applies when the circles don't overlap, so the language would need to be clarified with that condition.