[Commit] cairo/src cairo.c, 1.14, 1.15 cairo.h, 1.15,
1.16 cairo_font.c, 1.6, 1.7 cairo_gstate.c, 1.14,
1.15 cairoint.h, 1.21, 1.22
Carl Worth
commit at keithp.com
Mon Sep 29 09:36:32 PDT 2003
- Previous message: [Commit] cairo ChangeLog, 1.65, 1.66 TODO, 1.6, 1.7 configure.in,
1.18, 1.19
- Next message: [Commit] cairo ChangeLog,1.66,1.67 TODO,1.7,1.8
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Committed by: cworth
Update of /local/src/CVS/cairo/src
In directory home.keithp.com:/tmp/cvs-serv7386/src
Modified Files:
cairo.c cairo.h cairo_font.c cairo_gstate.c cairoint.h
Log Message:
Added cairo_arc and cairo_arc_negative.
Index: cairo.c
===================================================================
RCS file: /local/src/CVS/cairo/src/cairo.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- cairo.c 25 Sep 2003 22:01:28 -0000 1.14
+++ cairo.c 29 Sep 2003 15:36:30 -0000 1.15
@@ -478,6 +478,53 @@
}
void
+cairo_arc (cairo_t *cr,
+ double xc, double yc,
+ double radius,
+ double angle1, double angle2)
+{
+ if (cr->status)
+ return;
+
+ cr->status = _cairo_gstate_arc (cr->gstate,
+ xc, yc,
+ radius,
+ angle1, angle2);
+}
+
+void
+cairo_arc_negative (cairo_t *cr,
+ double xc, double yc,
+ double radius,
+ double angle1, double angle2)
+{
+ if (cr->status)
+ return;
+
+ cr->status = _cairo_gstate_arc_negative (cr->gstate,
+ xc, yc,
+ radius,
+ angle1, angle2);
+}
+
+/* XXX: NYI
+void
+cairo_arc_to (cairo_t *cr,
+ double x1, double y1,
+ double x2, double y2,
+ double radius)
+{
+ if (cr->status)
+ return;
+
+ cr->status = _cairo_gstate_arc_to (cr->gstate,
+ x1, y1,
+ x2, y2,
+ radius);
+}
+*/
+
+void
cairo_rel_move_to (cairo_t *cr, double dx, double dy)
{
if (cr->status)
Index: cairo.h
===================================================================
RCS file: /local/src/CVS/cairo/src/cairo.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- cairo.h 25 Sep 2003 22:01:28 -0000 1.15
+++ cairo.h 29 Sep 2003 15:36:30 -0000 1.16
@@ -261,6 +261,26 @@
double x3, double y3);
extern void __external_linkage
+cairo_arc (cairo_t *cr,
+ double xc, double yc,
+ double radius,
+ double angle1, double angle2);
+
+extern void __external_linkage
+cairo_arc_negative (cairo_t *cr,
+ double xc, double yc,
+ double radius,
+ double angle1, double angle2);
+
+/* XXX: NYI
+extern void __external_linkage
+cairo_arc_to (cairo_t *cr,
+ double x1, double y1,
+ double x2, double y2,
+ double radius);
+*/
+
+extern void __external_linkage
cairo_rel_move_to (cairo_t *cr, double dx, double dy);
extern void __external_linkage
Index: cairo_font.c
===================================================================
RCS file: /local/src/CVS/cairo/src/cairo_font.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- cairo_font.c 5 Sep 2003 22:29:49 -0000 1.6
+++ cairo_font.c 29 Sep 2003 15:36:30 -0000 1.7
@@ -142,7 +142,16 @@
/* XXX: The determinant gives an area expansion factor, so the
math below should be correct for the (common) case of uniform
X/Y scaling. Is there anything different we would want to do
- for non-uniform X/Y scaling? */
+ for non-uniform X/Y scaling?
+
+ XXX: Actually, the reasoning above is bogus. A transformation
+ such as scale (N, 1/N) will give an expansion_factor of 1. So,
+ with the code below we'll end up with font_size == 1 instead of
+ N, (so the hinting will be all wrong). I think we want to use
+ the maximum eigen value rather than the square root of the
+ determinant.
+
+ */
_cairo_matrix_compute_determinant (&matrix, &expansion);
font_size = sqrt (fabs (expansion));
Index: cairo_gstate.c
===================================================================
RCS file: /local/src/CVS/cairo/src/cairo_gstate.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- cairo_gstate.c 25 Sep 2003 22:01:28 -0000 1.14
+++ cairo_gstate.c 29 Sep 2003 15:36:30 -0000 1.15
@@ -707,6 +707,272 @@
return status;
}
+/* Spline deviation from the circle in radius would be given by:
+
+ error = sqrt (x**2 + y**2) - 1
+
+ A simpler error function to work with is:
+
+ e = x**2 + y**2 - 1
+
+ From "Good approximation of circles by curvature-continuous Bezier
+ curves", Tor Dokken and Morten Daehlen, Computer Aided Geometric
+ Design 8 (1990) 22-41, we learn:
+
+ abs (max(e)) = 4/27 * sin**6(angle/4) / cos**2(angle/4)
+
+ and
+ abs (error) =~ 1/2 * e
+
+ Of course, this error value applies only for the particular spline
+ approximation that is used in _cairo_gstate_arc_segment.
+*/
+static double
+_arc_error_normalized (double angle)
+{
+ return 2.0/27.0 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2);
+}
+
+static double
+_arc_max_angle_for_tolerance_normalized (double tolerance)
+{
+ double angle, error;
+ int i;
+
+ /* Use table lookup to reduce search time in most cases. */
+ struct {
+ double angle;
+ double error;
+ } table[] = {
+ { M_PI / 1.0, 0.0185185185185185036127 },
+ { M_PI / 2.0, 0.000272567143730179811158 },
+ { M_PI / 3.0, 2.38647043651461047433e-05 },
+ { M_PI / 4.0, 4.2455377443222443279e-06 },
+ { M_PI / 5.0, 1.11281001494389081528e-06 },
+ { M_PI / 6.0, 3.72662000942734705475e-07 },
+ { M_PI / 7.0, 1.47783685574284411325e-07 },
+ { M_PI / 8.0, 6.63240432022601149057e-08 },
+ { M_PI / 9.0, 3.2715520137536980553e-08 },
+ { M_PI / 10.0, 1.73863223499021216974e-08 },
+ { M_PI / 11.0, 9.81410988043554039085e-09 },
+ };
+ int table_size = (sizeof (table) / sizeof (table[0]));
+
+ for (i = 0; i < table_size; i++)
+ if (table[i].error < tolerance)
+ return table[i].angle;
+
+ ++i;
+ do {
+ angle = M_PI / i++;
+ error = _arc_error_normalized (angle);
+ } while (error > tolerance);
+
+ return angle;
+}
+
+static int
+_cairo_gstate_arc_segments_needed (cairo_gstate_t *gstate,
+ double angle,
+ double radius)
+{
+ double l1, l2, lmax;
+ double max_angle;
+
+ _cairo_matrix_compute_eigen_values (&gstate->ctm, &l1, &l2);
+
+ l1 = fabs (l1);
+ l2 = fabs (l2);
+ if (l1 > l2)
+ lmax = l1;
+ else
+ lmax = l2;
+
+ max_angle = _arc_max_angle_for_tolerance_normalized (gstate->tolerance / (radius * lmax));
+
+ return (int) ceil (angle / max_angle);
+}
+
+/* We want to draw a single spline approximating a circular arc radius
+ R from angle A to angle B. Since we want a symmetric spline that
+ matches the endpoints of the arc in position and slope, we know
+ that the spline control points must be:
+
+ (R * cos(A), R * sin(A))
+ (R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
+ (R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
+ (R * cos(B), R * sin(B))
+
+ for some value of h.
+
+ "Approximation of circular arcs by cubic poynomials", Michael
+ Goldapp, Computer Aided Geometric Design 8 (1991) 227-238, provides
+ various values of h along with error analysis for each.
+
+ From that paper, a very practical value of h is:
+
+ h = 4/3 * tan(angle/4)
+
+ This value does not give the spline with minimal error, but it does
+ provide a very good approximation, (6th-order convergence), and the
+ error expression is quite simple, (see the comment for
+ _arc_error_normalized).
+*/
+static cairo_status_t
+_cairo_gstate_arc_segment (cairo_gstate_t *gstate,
+ double xc, double yc,
+ double radius,
+ double angle_A, double angle_B)
+{
+ cairo_status_t status;
+ double r_sin_A, r_cos_A;
+ double r_sin_B, r_cos_B;
+ double h;
+
+ r_sin_A = radius * sin (angle_A);
+ r_cos_A = radius * cos (angle_A);
+ r_sin_B = radius * sin (angle_B);
+ r_cos_B = radius * cos (angle_B);
+
+ h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
+
+ status = _cairo_gstate_curve_to (gstate,
+ xc + r_cos_A - h * r_sin_A, yc + r_sin_A + h * r_cos_A,
+ xc + r_cos_B + h * r_sin_B, yc + r_sin_B - h * r_cos_B,
+ xc + r_cos_B, yc + r_sin_B);
+ if (status)
+ return status;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gstate_arc_dir (cairo_gstate_t *gstate,
+ double xc, double yc,
+ double radius,
+ double angle_min,
+ double angle_max,
+ cairo_direction_t dir)
+{
+ cairo_status_t status;
+
+ while (angle_max - angle_min > 4 * M_PI)
+ angle_max -= 2 * M_PI;
+
+ /* Recurse if drawing arc larger than pi */
+ if (angle_max - angle_min > M_PI) {
+ /* XXX: Something tells me this block could be condensed. */
+ if (dir == CAIRO_DIRECTION_FORWARD) {
+ status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
+ angle_min, angle_min + M_PI, dir);
+ if (status)
+ return status;
+
+ status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
+ angle_min + M_PI, angle_max, dir);
+ if (status)
+ return status;
+ } else {
+ status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
+ angle_min + M_PI, angle_max, dir);
+ if (status)
+ return status;
+
+ status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
+ angle_min, angle_min + M_PI, dir);
+ if (status)
+ return status;
+ }
+ } else {
+ int i, segments;
+ double angle, angle_step;
+
+ segments = _cairo_gstate_arc_segments_needed (gstate,
+ angle_max - angle_min,
+ radius);
+ angle_step = (angle_max - angle_min) / (double) segments;
+
+ if (dir == CAIRO_DIRECTION_FORWARD) {
+ angle = angle_min;
+ } else {
+ angle = angle_max;
+ angle_step = - angle_step;
+ }
+
+ for (i = 0; i < segments; i++, angle += angle_step) {
+ _cairo_gstate_arc_segment (gstate,
+ xc, yc,
+ radius,
+ angle,
+ angle + angle_step);
+ }
+
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_gstate_arc (cairo_gstate_t *gstate,
+ double xc, double yc,
+ double radius,
+ double angle1, double angle2)
+{
+ cairo_status_t status;
+
+ while (angle2 < angle1)
+ angle2 += 2 * M_PI;
+
+ status = _cairo_gstate_line_to (gstate,
+ xc + radius * cos (angle1),
+ yc + radius * sin (angle1));
+ if (status)
+ return status;
+
+ status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
+ angle1, angle2, CAIRO_DIRECTION_FORWARD);
+ if (status)
+ return status;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_gstate_arc_negative (cairo_gstate_t *gstate,
+ double xc, double yc,
+ double radius,
+ double angle1, double angle2)
+{
+ cairo_status_t status;
+
+ while (angle2 > angle1)
+ angle2 -= 2 * M_PI;
+
+ status = _cairo_gstate_line_to (gstate,
+ xc + radius * cos (angle1),
+ yc + radius * sin (angle1));
+ if (status)
+ return status;
+
+ status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
+ angle2, angle1, CAIRO_DIRECTION_REVERSE);
+ if (status)
+ return status;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* XXX: NYI
+cairo_status_t
+_cairo_gstate_arc_to (cairo_gstate_t *gstate,
+ double x1, double y1,
+ double x2, double y2,
+ double radius)
+{
+
+}
+*/
+
cairo_status_t
_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy)
{
@@ -775,7 +1041,7 @@
{
cairo_status_t status;
- _cairo_pen_init (&gstate
+ _cairo_pen_init (&gstate);
return CAIRO_STATUS_SUCCESS;
}
*/
Index: cairoint.h
===================================================================
RCS file: /local/src/CVS/cairo/src/cairoint.h,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- cairoint.h 27 Sep 2003 12:08:38 -0000 1.21
+++ cairoint.h 29 Sep 2003 15:36:30 -0000 1.22
@@ -544,6 +544,18 @@
double x3, double y3);
extern cairo_status_t __internal_linkage
+_cairo_gstate_arc (cairo_gstate_t *gstate,
+ double xc, double yc,
+ double radius,
+ double angle1, double angle2);
+
+extern cairo_status_t __internal_linkage
+_cairo_gstate_arc_negative (cairo_gstate_t *gstate,
+ double xc, double yc,
+ double radius,
+ double angle1, double angle2);
+
+extern cairo_status_t __internal_linkage
_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy);
extern cairo_status_t __internal_linkage
- Previous message: [Commit] cairo ChangeLog, 1.65, 1.66 TODO, 1.6, 1.7 configure.in,
1.18, 1.19
- Next message: [Commit] cairo ChangeLog,1.66,1.67 TODO,1.7,1.8
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the Commit
mailing list