On 10-10-2012 9:52, Tavmjong Bah wrote:
On Tue, 2012-10-09 at 23:37 +0200, Johan Engelen wrote:
On 9-10-2012 1:04, Johan Engelen wrote:
On 8-10-2012 10:35, Jasper van de Gronde wrote:
On 07-10-12 21:05, Johan Engelen wrote:
On 7-10-2012 7:49, Tavmjong Bah wrote:
On Sat, 2012-10-06 at 22:26 +0200, Johan Engelen wrote: > Hi all, > I've lost track of all the problems with powerstroke. > Please send me again the bugs you have found (with a test file!) or the > UI ideas we definitely need for release. > > I have been working on "extrapolate by arcs matching path curvature", > but I think it will take me too long to make that work reliably before > release. There are still too many bumps along that road... I've > committed the code, but it is disabled. What is your problem with "extrapolate by arcs matching path curvature"? I've got a hacked version of Cairo that does the extrapolated line-join... but not properly (it only works at 100% zoom at the moment).
Determining the curvature is messy, have not found a good way to do that yet.
In principle, curvature is just the norm of the second derivative w.r.t. arc-length (if you want it signed, you'd probably just have to take the dot product with the unit normal, instead of the norm).
Of course, the trick is in the "arc-length" bit, is that where you're getting stuck? One trick you could try is taking an explicit formula like (x'*y'' - y'*x'')/(x'^2+y'^2)^(3/2) and approximating it with a polynomial (which doesn't require any values near the endpoints, where you'll usually get singularities and other problems), then evaluating the polynomial at the endpoints. I haven't tried it, so I'm not sure how well it would work, but my guess is that it could work pretty well.
I tried the norm of second derivative but I forgot about arc-length reparametrisation, thanks for the hint! Arc-length reparametrisation is already present in 2geom, so that is easy. Yes I need it 'signed', such that the touching circle is on the inside of the curve. I indeed get that from the normal, but the trick is to figure out which direction points inward for the normal! :-) For that I look at the direction of 2nd derivative w.r.t. the tangent.
And just now I find at function named "curvature" in 2geom... (although it has a todo comment that it is claimed incomplete...)
For my Cairo hack, I used the last three points (two handles, end point) of the cubic Bezier curve to determine the curvature. If the last two points are degenerate, I uses the start point, first handle, and end point. This seems to work fine (and as Cairo only uses cubic Bezier and lines at the rendering point I don't have to worry about arcs, quadratic Beziers, etc.). The math for finding the curvature of a cubic Bezier can be found at:
Nice explanation, we should link our release notes to it.
I think my 2geom's math is sound now, but... I could transform to cubic bezier and do the math there, to make sure it is identical to yours/SVG's............
But... I spot a difference with my implementation: I extrapolate with circles that are tangent to the stroke of the path, instead of the concentric circles with reduced radius like you do. Because of varying stroke width, the direction and curvature at the stroke itself may be very different from the direction and curvature of the original path. Intuition tells me that our two approaches are identical for fixed stroke width, but am too lazy to do the math. I guess for you it is an easy change, so hoping you can change that aspect to "my" calculation, so your text is valid for varying stroke width too!
"Extrapolated arc" works much better with the improved curvature calculation (not sure whether it is really the curvature but OK :)). Now what is left is to fix the calculation for zero-length handles. Attached is a modified version of the "Choose your miter" file that I showed at LGM. In many cases, the difference between "Extrapolated" and "Extrapolated arc" is not very big. But there are things that one or the other can't do. For example, with "extrapolate" it is not possible to end up with a curving miter at the end of an almost straight line segment simply because the mirrored piece will be straight too instead of curved. Overall it seems that "Extrapolated arc" is easier to control and leads to nicer results, so I am tempted to pick that one by default.
Please play with it a bit and form an opinion.
I would choose the extrapolated arc. (This also matches what will be in SVG 2.)
There seems to be a bug in your code where the wrong intersection of the two circles is sometimes chosen.
Which rev did you use? Should've been fixed yesterday.
Have to fix the effect for straight paths now.
I noticed in your code that if the two circles don't intersect, you fall back to bevel join. I am thinking in the SVG 2 spec about falling back to miter join.
Ok, I just did the fallback as a temp fix. Let's see if it makes much difference. (because very often the miter will have to fallback to bevel I think)
I really hope someone comes up with better names for "Extrapolated" and "Extrapolated arc"
Yes, a better name would be nice... If someone comes up with one it might just end up in the SVG 2 spec. Maybe just "arc"?
Do people still want the original extrapolate? I'm not too proud of my original idea to not leave it out if people find it to have very little use. I have not made up my mind yet. The mirror-extrapolate allows for some funky looking stuff that you can't get with circle-extrapolate, but perhaps it is too extreme to be useful :P
Cheers, Johan