Re: stroke-miterlimit: Why not use partial miters when a stroke linejoin exceeds the limit?

Hi Amelia,

I've had time to think about this issue a little more.

The reason for the current behavior is that it is what the underlying
graphics libraries support. And the graphic libraries support these
options because that is the way it's always been done (PostScript, RTF,
etc.). And PostScript did it this way because CPU power in its early
days didn't allow for complicated clipping as you have proposed
(according to one website I found).

Your proposal will require changes to the underlying graphical
libraries. I can anticipate some resistance to making changes of this
type to the SVG spec for this reason (as well as for backwards
compatibility). The 'arc' line-join will face the same problem. But if
the 'arc' line-join is added to graphical libraries then there is a
chance a new 'miter-clipped' type could be added too.

(Note: Firefox may be using different libraries on different platforms
which could account for the difference in behaviors.)

On Sun, 2014-10-19 at 14:22 -0600, Amelia Bellamy-Royds wrote:
> Thanks Tav,
> 
> 
> One detail I thought of after I sent out the previous message: what to
> do when the two lines are completely coincident (e.g., theta = 0).
> The draft SVG2 implementation notes currently say to crop flush with
> the point (no additional line join area).  In contrast, the
> Firefox/Windows implementation maintains the trimmed miter as an
> extension to the lines.  I've updated the codepen to include this
> scenario.

I believe that this statement in the spec is not clear enough. I think
it applies only to a join where the join is smooth, i.e. the line out
exits in the same direction as the line in (otherwise, you would not get
the expected round cap if the line join is type is 'round'.

> To maintain smooth transitions while removing extension for 0-degree
> vertices -- and to more accurately reflect the definition of
> stroke-miterlimit as being proportional to the complete stroke width,
> not just the outside half -- the miter cut-off point could be a fixed
> distance from the inside corner, not from the actual path vertex.

For explaining this to the working group it would be very useful to have
some graphics.

> In other words, the final implementation instructions for basic miter
> would be:
> 
> 
> 14. Let P5 be the intersection of the two stroke edges on the inside
> of the corner (opposite side of P versus P3). Construct a clipping
> rectangle, *limit*, centered on the line between P5 and P3, that
> extends (d = ‘stroke-miterlimit’ * ‘stroke-width’) on either side
> perpendicular to that line, and and the same distance along that
> line from P5.  In other words, if P5 is (x,y) and P3 is (x1,y1), then
> the four vertexes of the clipping polygon would be defined as (x,y) ±
> d*(y1-1, x-x1) and  (x,y) + d(x1-x, y1-y) ± d*(y1-1, x-x1) .
> 
> 
> 15. Return the the union of *bevel* with (*extension* clipped to
> *limit*).  
> 
> 
> 
> 
> 
> 
> I also agree that the arc join needs to be finessed.  A simple
> rectangular clip, on second consideration, wouldn't do: it could
> result in disconnected pieces, with the tip of the talon curving back
> into the rectangle when the main arc has been clipped.    I would
> really have to play around with a working implementation of the arc
> joins to get the possibilities clear in my mind.

Inkscape 'trunk' has a "PowerStroke" path effect which can simulate the
arcs line join. It might be useful to play around with it to see the
kinds of shapes one can get. I do have a trial versions of Cairo and
Inkscape that supports the 'arc' linejoin. It's a bit bit-rotted and
will take some effort to bring up-to-date.

Tav


> ABR
> 
> 
> 
> On 19 October 2014 13:12, Tavmjong Bah <tav.w3c@gmail.com> wrote:
>         
>         Hi,
>         
>         The behavior you've described seems reasonable. I've added the
>         topic of
>         miter limit to the agenda requests for the TPAC meeting this
>         month. The
>         limit as applied to the arc join needs to be studied further;
>         it's on my
>         list of things to do.
>         
>         Tav
>         
>         On Sat, 2014-10-18 at 16:18 -0600, Amelia Bellamy-Royds wrote:
>         > [ General comment: If it would preferable to submit these
>         feature
>         > request / implementation discussions through an issue
>         tracker, please
>         > let me know.  I'm not quite clear on the relationship
>         between the two
>         > issue trackers, one at
>         http://www.w3.org/Graphics/SVG/WG/track/ and
>         > one as part of the W3 Bugzilla.
>         >
>         >
>         > Sorry for dumping a lot of ideas all at once, but as I
>         mentioned
>         > previously I'm starting to figure out what's new in SVG2,
>         and I know
>         > that the working group has got a big meeting coming up at
>         the end of
>         > the month, so might as well mention sooner rather than
>         later. ]
>         >
>         >
>         > ______________________
>         >
>         >
>         > Background:
>         > ------------------
>         > The stroke-miterlimit prevents mitered strokes on acute
>         linejoins from
>         > extending far beyond the dimensions of the shape.
>         >
>         >
>         > However, the behaviour was not clearly defined in SVG1.1
>         [1].  The
>         > general description seems to imply that `stroke-miterlimit`
>         is a
>         > *limit* that the miter reaches but does not surpass.
>         However, the
>         > specific rule is "When the limit is exceeded, the join is
>         converted
>         > from a miter to a bevel", which has been interpretted by
>         most browsers
>         > as meaning to convert the linejoin to
>         `stroke-linejoin:bevel`, which
>         > is a much tighter crop.
>         >
>         >
>         > The detailed implementation notes in the current SVG2 draft
>         would lock
>         > in that interpretation. [2]
>         >
>         >
>         >
>         > The Problem:
>         > ------------------
>         > In my mind, this is contrary to the spirit of a "limit"
>         attribute.
>         > Furthermore, it results in unpleasant effects in animation.
>         See
>         > http://codepen.io/AmeliaBR/pen/JACBu?editors=110
>         >
>         >
>         > Current behaviour in all browsers tested except Firefox is
>         as
>         > described above.  The switch to the the extreme bevel when
>         the miter
>         > exceeds the limit results in sudden jumps during animation,
>         and ends
>         > up bevelling acute angles much more closely than the miter
>         on more
>         > oblique angles.
>         >
>         >
>         > (Batik 1.7 seems to be cutting the difference, removing the
>         bevelled
>         > area but keeping the point!  Oops!)
>         >
>         >
>         >
>         > In contrast, in Firefox (v32/33 on Win7), the animation is
>         smooth.  If
>         > you had a shape with multiple mitered corners of similar
>         angles on
>         > either side of the limit, they would be rendered
>         consistently.
>         >
>         >
>         > The discrepancy has been noted on this list before in May of
>         this
>         > year [3], where it was determined that the Firefox behaviour
>         was
>         > operating-system dependant.  That thread ended with a link
>         to the
>         > corresponding Mozilla bug page about standardizing the
>         rendering [5].
>         >
>         >
>         > Standardizing is good, but why not standardize in the other
>         direction,
>         > to the more aesthetically pleasing result that allows for
>         smooth
>         > animations?  Yes, this would somewhat sacrifice
>         > backwards-compatibility, but only for a feature that is
>         currently
>         > implemented in incompatible ways by different agents.
>         >
>         >
>         >
>         >
>         > Request:
>         > ------------
>         > That SVG 2 define the behaviour of stroke-miterlimit so that
>         it never
>         > crops mitered corners shorter than the limit.
>         >
>         >
>         > A similar rule could also be applied to the proposed
>         arc/talon
>         > linejoin, taking the shape defined in the talon and clipping
>         it to the
>         > miter limit.
>         >
>         >
>         > In order to make this the defined behaviour, the final
>         points in the
>         > line join shape implementation notes (after calculating the
>         basic
>         > intersection points) would be amended as follows:
>         >
>         >
>         > 8. Let *bevel* be the triangle formed from the three points
>         P, P1 and
>         > P2.
>         >
>         >
>         > 9. If ‘stroke-linejoin’ is bevel, return *bevel*.
>         >
>         >
>         > 10. If ‘stroke-linejoin’ is round, then return the union of
>         *bevel*
>         > and a circular sector of radius ‘stroke-width’, centered on
>         P, and
>         > which has P1 and P2 as the two endpoints of the arc.
>         >
>         >
>         > 10. 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 "Computing the circles for
>         the arcs
>         > 'stroke-linejoin'"). If both curvatures are zero fall
>         through to
>         > miter. Extend the stroke edges using these circles (or a
>         line, in the
>         > case of zero curvature). If the two circles (or circle and
>         line)
>         > intersect, let *extension* be the area inside the region
>         defined by
>         > the lines that connect P with P1 and P2 and the arcs defined
>         by the
>         > circles (or arc and line) between the closest intersection
>         point to P,
>         > and P1 and P2. If the two circles (or circle and line) do
>         not
>         > intersect, fall through to miter. Note that the curvatures
>         are
>         > calculated in user-space before any transforms are applied.
>         >
>         >
>         > 12. If ‘stroke-linejoin’ is miter, or if *extension* could
>         not be
>         > defined using the arcs method, let *extension* be the
>         triangle formed
>         > from the three points P1, P2 and P3.
>         >
>         >
>         > 13. Let θ be the angle between A and B.  If 1 / sin(θ / 2) ≤
>         > ‘stroke-miterlimit’, then return the union of *extension*
>         and
>         > *bevel*.
>         >
>         >
>         > 14. Construct a clipping rectangle, *limit*, centered on P
>         that
>         > extends (‘stroke-miterlimit’ * ‘stroke-width’) from P in the
>         > directions perpendicular to the line between P and P3, and
>         half that
>         > distance in the directions parallel to that line.  In other
>         words, if
>         > P is (x,y), P3 is (x1,y1), and the computed distance is d,
>         then the
>         > four vertexes of the clipping polygon would be defined as
>         (x,y) ±
>         > d/2*(x1-x, y1-y) ± d*(y1-1, x-x1).
>         >
>         >
>         > 15. Return the the union of *bevel* with *extension*,
>         clipped to
>         > *limit*.
>         >
>         >
>         > Depending on implementations, user agents might skip 13 and
>         just apply
>         > the clipping region; it depends which is faster, a
>         null-effect
>         > clipping operation or trigonometry.
>         >
>         >
>         > I'm fairly certain this reflects the current Firefox/Windows
>         > implementation for miters, and I think it would result in
>         acceptable
>         > appearance of "clipped talons" when applied to the arc line
>         joins,
>         > although I haven't explored it carefully.  The use of a
>         clipping
>         > rectangle centered on P is intended to encompass any degree
>         of
>         > curvature of the talons, including curving back towards the
>         other side
>         > of the join.  However, I'm not sure whether the use of 1 /
>         sin(θ / 2)
>         > will cover all cases of long talons; it might be better to
>         directly
>         > calculate the distance to the intersection point of the two
>         arcs.
>         >
>         >
>         >
>         >
>         > [1]:
>         http://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty
>         > [2]:
>         >
>         http://www.w3.org/TR/2014/WD-SVG2-20140211/painting.html#TermLineJoinShape
>         > [3]:
>         http://lists.w3.org/Archives/Public/www-svg/2013May/0020.html
>         > [4]: https://bugzilla.mozilla.org/show_bug.cgi?id=854296
>         
>         
>         
> 
> 

Received on Monday, 20 October 2014 12:53:52 UTC