# Re: stroke-linejoin="arcs"

• From: Diego Nehab <diego.nehab@gmail.com>
• Date: Sat, 16 Jan 2016 23:24:22 -0200
• To: Tavmjong Bah <tav.w3c@gmail.com>
• Message-ID: <CAH2ULtHjZT_TS=2t6x_WjevgFqsrHcus4-Xu0RDkCp1kR0CdVg@mail.gmail.com>
```Dear Tav,

Sorry it has taken me so long to reply...

No problem!

> Take the tangent direction at a point P(t) while moving along the
> > segment. Call it T(t). Rotate it CCW by 90 degrees and normalize to
> > produce N(t). Now compute signed curvature κ(t) as usual. The center
> > of the osculating circle is at P(t) + N(t)/k(t). As long as the
> > tangent direction and curvature have been computed consistently
> > (i.e., traversing the curve in consistent directions), the formula
> > should work, no? Where is the ambiguity? The formulas do not change
> > regardless of whether the join is to the right or left of the path.
>
> Yes, for calculating the center of the circle. But not for calculating
> the offset radii. Try reversing the path.
>

It still works. The radius of the circular offset to be drawn in the
direction of the normal is always abs(1/k + w/2). If k is positive, the
center is on the same side as the normal and the curve is turning towards
the normal. So the radius of the offset circle is 1/k - w/2. If k is
negative, the center is on the opposite side of the normal and the curve is
turning away from the normal. So the radius of the offset circle is -1/k +
w/2. You will notice that, regardless of whether k is positive or negative,
the radius is always abs(1/k-w/2) = abs(w/2-1/k), which is the formula I
suggested using. It doesn't matter if you reverse the path. The normal will
flip and so will the sign of k. Nothing changes. This is in fact how I
implement it. Move along the path offsetting one side then move along the
reversed path offsetting the other side, always using the same formulas.

> > I think we have a few cases here, depending on signed curvatures of
> > the two connecting segments. In order of precedence:
> >
> > 1) If either curvature is -∞, we revert to the round join.
>
> This means the radius is zero. That can't happen for Bezier curves. I
> suppose it could happen if an elliptical curve was flat. In any case, I
> don't think this needs to be special cased since the offset path will
> have a radius of w/2.
>
>
Isn't this exactly what happens when there is a cusp in a cubic Bézier? Try
repeating the first two control points. What is the curvature at t=0? But
it doesn't matter. What matters is that when the radius of curvature is too
small, the best approximation for the join is round, not miter. Right?

> > 2) If both curvatures are in (-∞, 0], then the offset osculating
> > "circles" intersect and we are golden. Quotes are because these
> > circles could degenerate to lines, but this is no trouble.
>
> Yes, this should always work, offset radii greater than w/2.
>
> > 3) If one curvature is in (-∞, 0] and the other is in (0, 2/w),
> > where w is the stroke width, the offset osculating circles may or may
> > not intersect. This case is problematic because, according to the
> > proposal, we don't have a continuous behavior here. Reverting back to
> > miter when no intersection is found will basically create a pop.
> > Perhaps we should instead take the positive curvature and reduce it
> > until the circles are tangent? At least this would create a
> > continuous behavior more in the line of what SVG does in other
> > cases...
>
> This is an interesting idea but as far as I can tell it requires
> solving a quartic equation. I tried just increasing the smaller circle
> until there is an intersection. See the animation in the web page
> below.
>
>
I saw the animation. It is pretty cool. :) I do prefer this method. The
length of the join wouldn't increase like crazy because of the miter limit,
right? I haven't done the math to see if it requires solving a quartic or
not. But even if it does, it shouldn't be a problem. We know the bounds for
the roots we care about, right? There is a very simple method numerical
method (I am saying 10-15 lines of code) that is guaranteed to find the
roots of polynomials inside a bracket. Quite efficient for low-order
polynomials.

I'm not 100% sure of what you are saying here but of course inner
> boundaries are not relevant here.
>
> > For some reason, I can't load the SVG files you linked to.
> > (Subscripts in a link?)
>
> Subscripts? Are you perhaps a tex user?
>
>
I am. But I swear that my e-mail reader (Gmail!) was rendering the file
names as subscripts! :)

> > As for your blog, can I get the SVG files for these cool examples you
> > show?
>
> Most if the images are SVG files. Inkscape trunk has a "Join" LPE which
> implements the arcs line-join. It's a bit buggy but it gives quite
> useful feedback. By setting the stroke color different than the fill
> color one can see the generated offset path.
>
> I've prepared a web page with some studies of line joins. I look at
> several options for fallbacks for the 'arcs' line join and at the
> bottom there is an exhaustive diagram of all the different possible
> combinations of curvatures relative to stroke widths. See:
>
>         http://tavmjong.free.fr/SVG/LINEJOIN_STUDY/
>

Do you know what algorithm Inkscape uses for offseting? When the stroke
width is large, things start breaking apart. It's not something particular
to Inkscape. Many renderers break down, and break down in a somewhat
similar way. I was wondering if they all try to implement the same idea.
NVPR has a directory with a bunch of these nasty examples. I think they
converted examples they got from GhostScript.

Kind regards,
Diego
```

Received on Sunday, 17 January 2016 01:28:07 UTC