Discussion:
[cairo] Ellipse stroke
Richard Copley
2017-11-14 20:01:46 UTC
Permalink
I don't think the result of adding an elliptical arc to a path and
stroking the path is right, if the ellipse's minor semiaxis is small
compared to the line width.

I put a little program at https://buster.me.uk/cgit/cairo-bug.git
to illustrate. The output PNGs are there too (use the "plain" links).

The top part of each image is what current Cairo paints when stroking
an elliptical arc, from 0 to pi radians, with a large line width.

In my opinion, image 0 is perfect, images 1 and 2 are incorrect,
and there's a different issue (possibly a Cairo bug?) that affects
images 3 to 11 more and more severely.

I can see the advantages of the current method, that it mostly works
fine and is straightforward to describe and implement.

I have a suggestion for a possible solution too, though the
mathematics of it is beyond me for the moment.

You see, as the minor axis of the ellipse tends to zero, the path
tends to a 'limit path' which is a straight line of length the major
axis, preceded and followed by infinitesimal segments perpedicular to
it.

And, I propose, that limit path should be stroked as if it is simply a
straight line. (As if the infinitesimal sections don't exist at all).

And as the minor radius changes continuously from "OK" (as in image 0)
through "not OK" (as in images 1 and 2) tending towards zero, the
stroked region should change continuously from the "OK" ellipse stroke
in image 0 to the "limit path" straight line.

That's all just explaining what I'd like to accomplish, not how I
would do it.

How I would do it is: find the points where the current Cairo stroker
would make a cusp (as in image 2), if any. Truncate the path being
stroked at the cusp(s). Extend the stroke with a circular segment
centre the cusp, in such a way that the leading edge of the stroked
region exactly reaches the endpoint of the path.

Clear as mud?

It's a fun problem, You'll love it. Linear algebra, calculus /and/
trigonometry. A real treat.
--
cairo mailing list
***@cairographics.org
https://lists.cairographics.org/mailman/lis
c***@aol.com
2017-11-15 04:22:39 UTC
Permalink
Hi Richard,

I don't have a solution for drawing with a cairo arc and a wide line. If you want to draw wide curves though, you can use bezier points. Get some circular or elliptical points and then get the bezier points for them. Then draw the curve. This gives you a lot of flexibility with what you might want to draw. As an example, I have some clocks at

https://github.com/cecashon/OrderedSetVelociRaptor/tree/master/Misc/CircularClocks

Some start as circles but can be deformed into an ellipse. There are some wide lines and a few other circular shapes there also.

Eric
Richard Copley
2017-11-17 08:31:39 UTC
Permalink
Post by c***@aol.com
I don't have a solution for drawing with a cairo arc and a wide line. If you
want to draw wide curves though, you can use bezier points. Get some
circular or elliptical points and then get the bezier points for them. Then
draw the curve. This gives you a lot of flexibility with what you might want
to draw. As an example, I have some clocks at
https://github.com/cecashon/OrderedSetVelociRaptor/tree/master/Misc/CircularClocks
Some start as circles but can be deformed into an ellipse. There are some
wide lines and a few other circular shapes there also.
Very cool, thanks.

To achieve what I want in Cairo, I will have to replace the cairo_arc calls
with lower-level cairo_curve_to calls, after having analysed quite thoroughly
exactly what the final stroke is supposed to look like.

It's more fun in HTML5 Canvas -- it seems happy to draw any ellipse arc
(even if the minor semiaxis is zero, which is ruled out by the Cairo API.)
I confess I'm not sure exactly what shaped path HTML5 Canvas creates
for the strokes in the cases I illustrated.

To match the ease-of-use of HTML5 Canvas, I think a "cairo_ellipse" API
would be needed. (Ignore the naive suggestions in my OP, of course,
as they don't fit Cairo's path representation.)
--
cairo mailing list
***@cairographics.org
https:
Richard Copley
2017-11-17 21:36:54 UTC
Permalink
Post by Richard Copley
I'm not sure exactly what shaped path HTML5 Canvas creates
for the strokes in the cases I illustrated.
Here's an HTML5 Canvas sample of some elliptical arcs:
<https://jsfiddle.net/tbncfoof/10/>

I tried it on desktop Firefox, Chrome and Edge. Cairo's stroke has
undesirable gaps, in my opinion, and it breaks down when the minor
semiaxis is near zero. Webkit's stroke is like Cairo's but without the
problems when the minor semiaxis is near zero. Webkit strokes a simple
straight line when the minor semiaxis is equal to zero. Gecko's stroke
(using Skia) has desirable properties (no gaps!) and is the best, IMO.
Edge's stroke is kind of weird but not completely unusable.

BTW and hypothetically, could Cairo accept a patch it it were derived
from Mozilla's source code?
--
cairo mailing list
***@cairographics.org
https://lists.ca
c***@aol.com
2017-11-18 19:50:45 UTC
Permalink
Very nice demo. I tried firefox, chrome and ie at the library. Firefox and chrome draw the same as the C++ program using cairo and nothing is drawn in ie.

This is a test drawing program that might be of interest but suffers from the same lack of simplicity problem as the clocks.

https://github.com/cecashon/OrderedSetVelociRaptor/blob/master/Misc/cairo_drawings/bezier_points1.c

If you change the global variable "line_width" to 100, you can see what the arc, drawn with circular points and bezier points, looks like in the initial drawing. You can delete points also to see how it changes or drag points and transform them. You could start with eliptical points. Also the drawing can be output to svg and tested in a web browser. Some general drawing ideas I was trying out.

Yes, an elliptical function would be easier and useful but I think that it would need to operate in the same sort of way by connecting points in a path.


Eric
c***@aol.com
2017-11-25 02:35:02 UTC
Permalink
Looking at this a little more I am starting to suspect that the line caps are causing the drawing problems when flattening an ellipse. The round cap looks to work the best. The other two don't do so well. I tried three different methods for drawing an ellipse and they all work about the same with the round cap when the window height is reduced.

https://github.com/cecashon/OrderedSetVelociRaptor/blob/master/Misc/cairo_drawings/ellipse1.c

Eric
Richard Copley
2017-11-29 20:13:43 UTC
Permalink
[Eric, sorry I sent my earlier reply to you off-list by mistake, and
sorry to send this message to you more than once; the first attempt
was rejected because the attachment took it over the list's size
limit.]

Hello.

I'm reporting a bug. I'm not sure if I made that clear.

The documentation says it's OK to report bugs on this list. Is that
wrong?

The API suggests that Cairo is supposed to be able to render
elliptical arcs. Is that wrong?

To see how poor Cairo's rendering is, please see here:
<https://imgur.com/a/i2EZS>

On the top left and bottom left: the bug (arcs stroked from 0 to pi).
Notice that everything goes horribly wrong for a small part of the
animation.

On the top right and bottom right: avoiding the bug by stroking the
arc from t to pi-t, where cos²(t) = (r₀² - ∛(r₀r₀L)²) / (r₀² - r₁²),
where r₀ and r₁ are the ellipse semiaxes and L is the line width.

(That equation gives the locations of the cusps (if any) in the inner
curve of the ellipse stroke (proof omitted).)

The right hand side of the gif is meant to show that there's no
intrinsic mathematical reason that Cairo can't stroke ellipses
properly (except if the CTM while calling cairo_arc() is so near
to singular that it effectively has no inverse).
--
cairo mailing list
***@cairographics.org
ht
Richard Copley
2017-11-29 20:18:43 UTC
Permalink
Post by Richard Copley
On the top right and bottom right: avoiding the bug by stroking the
arc from t to pi-t, where cos²(t) = (r₀² - ∛(r₀r₀L)²) / (r₀² - r₁²),
where r₀ and r₁ are the ellipse semiaxes and L is the line width.
(That equation gives the locations of the cusps (if any) in the inner
curve of the ellipse stroke (proof omitted).)
Typo, sorry. The equation should be:

cos²(t) = (r₀² - ∛(r₀r₁L)²) / (r₀² - r₁²)
--
cairo mailing list
***@cairographics.org
https://lists.ca
Ray Gardener
2017-11-30 01:47:27 UTC
Permalink
Doesn't Cairo internally decompose arc calls into curveto calls?
--
cairo mailing list
***@cairographics.org
ht
Richard Copley
2017-11-30 22:27:26 UTC
Permalink
Post by Ray Gardener
Doesn't Cairo internally decompose arc calls into curveto calls?
Sort of. The path data structure is like you describe, see
<https://www.cairographics.org/manual/cairo-Paths.html#cairo-path-data-t>,
but when stroking it you also have to take account of the joins
between segments. I think.
--
cairo mailing list
***@cairographics.org
https://lists.cairographics.org/mailman/
Ray Gardener
2017-12-01 02:20:23 UTC
Permalink
Hmm. If the path structure is strictly Bezier curve segments and
straight lines,
then the rendering issue is more general in nature, not necessarily because
arcs were appended. i.e., if one explicitly issued the corresponding
curveto calls,
the misrender should still occur, no?

Ray
Post by Richard Copley
Post by Ray Gardener
Doesn't Cairo internally decompose arc calls into curveto calls?
Sort of. The path data structure is like you describe, see
<https://www.cairographics.org/manual/cairo-Paths.html#cairo-path-data-t>,
but when stroking it you also have to take account of the joins
between segments. I think.
--
cairo mailing list
***@cairographics.org
https://lists.cairographics.org/m
c***@aol.com
2017-11-30 18:32:46 UTC
Permalink
Hi Ray,

When an elliptical arc approaches a line under transform, the curve segments drawn overlap enough that the ends of the arc are no longer line capped flush with the default line cap. Half of the ends look like they end up with a round cap.

Eric
c***@aol.com
2017-12-01 03:17:36 UTC
Permalink
Yes, the misrender still occurs. If you generate Steiner points to draw the ellipse and get the corresponding Bezier points to draw the curve segments with, the ends of the elliptical arc look similar to the Cairo transformed arc. If you use unequally spaced points but equal angles to draw the arc then the ends work out OK but the arc has flat spots on the ends when flattened so it doesn't look real good.

For a wide arc or ring I would tend to draw the outline and then fill. A wide line elliptical arc does have some strange ends though when flattened.

Eric
c***@aol.com
2017-12-01 03:41:44 UTC
Permalink
Yes, the misrender still occurs. If you generate Steiner points to draw the ellipse and get the corresponding Bezier points to draw the curve segments with, the ends of the elliptical arc look similar to the Cairo transformed arc. If you use unequally spaced points but equal angles to draw the arc then the ends work out OK but the arc has flat spots on the ends when flattened so it doesn't look real good.

For a wide arc or ring I would tend to draw the outline and then fill. A wide line elliptical arc does have some strange ends though when flattened.

Eric
Richard Copley
2017-12-01 18:50:46 UTC
Permalink
Post by Richard Copley
you also have to take account of the joins
between segments. I think.
... but of course, the same is true for a sequence of curve_to calls.
if one explicitly issued the corresponding curveto calls,
the misrender should still occur, no?
I suppose so, and according to Eric's testing, yes. That suggests two
approaches.
1: Build a different list of curve_to segments, during the cairo_arc call.
2: Stroke bezier curves differently.

Maybe it also suggests that option 2 (if it's possible) would be
better. Is that roughly where you're heading with your line of
questioning?
For a wide arc or ring I would tend to draw the outline and then fill. A
wide line elliptical arc does have some strange ends though when flattened.
I think this is cairo_stroke's job description! Ideally, the user
shouldn't have to do the math(s) for themselves to get the right
result.

The stroke will have strange line endings when drawn correctly (more
or less strange depending on your chosen definitions).

The bug I'm reporting is that Cairo draws the line endings quite
inaccurately for fairly flat ellipses, and draws the whole arc very
badly for very flat ellipses.

Thanks to both of you for looking at this.
--
cairo mailing list
***@cairographics.org
https://lis
Continue reading on narkive:
Loading...