cairo_stroke_extents() gives a wrong result (!) for arcs in some specific cases.
cairo_arc(cr, 250.0, 250.0, 157.0, 5.147, 3.432);
cairo_stroke_extents(cr, &x1,&y1, &x2,&y2);
cairo_stroke_extents gives (!) x1=-229.47 (!), y1==37.75, x2=484.00, y2=483.90,
but stroked arc looks good, however.
This behaviour can be reproduced only for some specific cases - small changes of
the arc radius/angle1/angle2 or the line width hide this beast
(cairo_set_line_width(cr, 153.99) fixes the example above).
Created attachment 5928 [details]
small test case, requires GTK
The small test case, GTK2 required, compile:
cc -Wall `pkg-config --cflags --libs gtk+-2.0` cairo-test.c -o cairo-test
It shows the window with the arc, red half-toned rectangle shows the area
reported by cairo_stroke_extents().
Created attachment 11758 [details] [review]
Correct the mitre limit derivation
I believe the bug is in the derivation of the mitre limit conditional
(In reply to comment #2)
> I believe the bug is in the derivation of the mitre limit conditional
[chorus] Oh no it isn't!
The final equation is correct, it is just a misleading comment about the condition being secant(phi/2) <= ml (instead of 1 <= ml sin(phi/2) or cosecant(phi/2) <= ml). So the bug appears related to incorrect intersection vectors of the curves.
I've worked around this problem by relaxing the check that the in and out faces are exactly coincident, and instead just checking that if the two faces are within stoker->tolerance of each other, then we need not do any work to join the two faces and return SUCCESS.
@@ -205,17 +210,28 @@ _cairo_stroker_face_clockwise (cairo_stroke_face_t *in, ca
return _cairo_slope_clockwise (&in_slope, &out_slope);
+_PointDistanceSquaredToPoint (const cairo_point_t *a, const cairo_point_t *b)
+ double dx = _cairo_fixed_to_double (b->x - a->x);
+ double dy = _cairo_fixed_to_double (b->y - a->y);
+ return dx*dx + dy*dy;
_cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_s
int clockwise = _cairo_stroker_face_clockwise (out,
cairo_point_t *inpt, *outpt;
+ double tolerance_sqr = stroker->tolerance * stroker->tolerance;
- if (in->cw.x == out->cw.x
+ if ((in->cw.x == out->cw.x
&& in->cw.y == out->cw.y
&& in->ccw.x == out->ccw.x
&& in->ccw.y == out->ccw.y)
+ || (_PointDistanceSquaredToPoint (&in->cw, &out->cw) < tolerance_sqr &&
+ _PointDistanceSquaredToPoint (&in->ccw, &out->ccw) < tolerance_sqr))
I'm a little hesitant to apply this as I'm uncertain as to whether this is just papering over a deeper bug.
I've fixed this bug now here:
The fix will appear in the imminent 1.5.2 snapshot of cairo.