[Commit] cairo/src cairo_path_stroke.c,1.5,1.6 cairo_pen.c,1.5,1.6

Keith Packard commit at keithp.com
Fri Sep 5 14:25:49 PDT 2003


Committed by: keithp

Update of /local/src/CVS/cairo/src
In directory home.keithp.com:/tmp/cvs-serv32385/src

Modified Files:
	cairo_path_stroke.c cairo_pen.c 
Log Message:
	* src/cairo_path_stroke.c: comment face computations, check for
	reflecting transformation to select correct face orientations
	
	* src/cairo_pen.c: check for reflecting transform when computing
	pen to ensure consistent pen orientation


Index: cairo_path_stroke.c
===================================================================
RCS file: /local/src/CVS/cairo/src/cairo_path_stroke.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- cairo_path_stroke.c	4 Sep 2003 18:54:09 -0000	1.5
+++ cairo_path_stroke.c	5 Sep 2003 20:25:47 -0000	1.6
@@ -171,26 +171,22 @@
     case CAIRO_LINE_JOIN_ROUND: {
 	int i;
 	int start, step, stop;
-	cairo_point_t tri[3], initial, final;
+	cairo_point_t tri[3];
 	cairo_pen_t *pen = &gstate->pen_regular;
 
 	tri[0] = in->pt;
 	if (clockwise) {
-	    initial = in->ccw;
 	    _cairo_pen_find_active_ccw_vertex_index (pen, &in->dev_vector, &start);
 	    step = -1;
 	    _cairo_pen_find_active_ccw_vertex_index (pen, &out->dev_vector, &stop);
-	    final = out->ccw;
 	} else {
-	    initial = in->cw;
 	    _cairo_pen_find_active_cw_vertex_index (pen, &in->dev_vector, &start);
 	    step = +1;
 	    _cairo_pen_find_active_cw_vertex_index (pen, &out->dev_vector, &stop);
-	    final = out->cw;
 	}
 
 	i = start;
-	tri[1] = initial;
+	tri[1] = *inpt;
 	while (i != stop) {
 	    tri[2] = in->pt;
 	    _translate_point (&tri[2], &pen->vertex[i].pt);
@@ -203,7 +199,7 @@
 		i = 0;
 	}
 
-	tri[2] = final;
+	tri[2] = *outpt;
 
 	return _cairo_traps_tessellate_triangle (stroker->traps, tri);
     }
@@ -388,36 +384,55 @@
 static void
 _compute_face (cairo_point_t *pt, cairo_slope_t *slope, cairo_gstate_t *gstate, cairo_stroke_face_t *face)
 {
-    double mag, tmp;
-    double dx, dy;
+    double mag, det;
+    double line_dx, line_dy;
+    double face_dx, face_dy;
     XPointDouble usr_vector;
     cairo_point_t offset_ccw, offset_cw;
 
-    dx = cairo_fixed_to_double (slope->dx);
-    dy = cairo_fixed_to_double (slope->dy);
+    line_dx = cairo_fixed_to_double (slope->dx);
+    line_dy = cairo_fixed_to_double (slope->dy);
 
-    cairo_matrix_transform_distance (&gstate->ctm_inverse, &dx, &dy);
+    /* faces are normal in user space, not device space */
+    cairo_matrix_transform_distance (&gstate->ctm_inverse, &line_dx, &line_dy);
 
-    mag = sqrt (dx * dx + dy * dy);
+    mag = sqrt (line_dx * line_dx + line_dy * line_dy);
     if (mag == 0) {
 	/* XXX: Can't compute other face points. Do we want a tag in the face for this case? */
 	return;
     }
 
-    dx /= mag;
-    dy /= mag;
+    /* normalize to unit length */
+    line_dx /= mag;
+    line_dy /= mag;
 
-    usr_vector.x = dx;
-    usr_vector.y = dy;
+    usr_vector.x = line_dx;
+    usr_vector.y = line_dy;
 
-    tmp = dx;
-    dx = - dy * (gstate->line_width / 2.0);
-    dy = tmp * (gstate->line_width / 2.0);
+    /* 
+     * rotate to get a line_width/2 vector along the face, note that
+     * the vector must be rotated the right direction in device space,
+     * but by 90° in user space. So, the rotation depends on
+     * whether the ctm reflects or not, and that can be determined
+     * by looking at the determinant of the matrix.
+     */
+    _cairo_matrix_compute_determinant (&gstate->ctm, &det);
+    if (det >= 0)
+    {
+	face_dx = - line_dy * (gstate->line_width / 2.0);
+	face_dy = line_dx * (gstate->line_width / 2.0);
+    }
+    else
+    {
+	face_dx = line_dy * (gstate->line_width / 2.0);
+	face_dy = - line_dx * (gstate->line_width / 2.0);
+    }
 
-    cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
+    /* back to device space */
+    cairo_matrix_transform_distance (&gstate->ctm, &face_dx, &face_dy);
 
-    offset_ccw.x = cairo_double_to_fixed (dx);
-    offset_ccw.y = cairo_double_to_fixed (dy);
+    offset_ccw.x = cairo_double_to_fixed (face_dx);
+    offset_ccw.y = cairo_double_to_fixed (face_dy);
     offset_cw.x = -offset_ccw.x;
     offset_cw.y = -offset_ccw.y;
 

Index: cairo_pen.c
===================================================================
RCS file: /local/src/CVS/cairo/src/cairo_pen.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- cairo_pen.c	26 Aug 2003 14:40:17 -0000	1.5
+++ cairo_pen.c	5 Sep 2003 20:25:47 -0000	1.6
@@ -28,7 +28,7 @@
 #include "cairoint.h"
 
 static int
-_cairo_pen_vertices_needed (double radius, double tolerance, cairo_matrix_t *matrix);
+_cairo_pen_vertices_needed (double radius, double tolerance, double expansion);
 
 static void
 _cairo_pen_compute_slopes (cairo_pen_t *pen);
@@ -54,6 +54,8 @@
 _cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate)
 {
     int i;
+    int reflect;
+    double det, expansion;
 
     if (pen->num_vertices) {
 	/* XXX: It would be nice to notice that the pen is already properly constructed.
@@ -68,7 +70,20 @@
     pen->radius = radius;
     pen->tolerance = gstate->tolerance;
 
-    pen->num_vertices = _cairo_pen_vertices_needed (radius, gstate->tolerance, &gstate->ctm);
+    /* The determinant represents the area expansion factor of the
+       transform. In the worst case, this is entirely in one
+       dimension, which is what we assume here. */
+
+    _cairo_matrix_compute_determinant (&gstate->ctm, &det);
+    if (det >= 0) {
+	reflect = 0;
+	expansion = det;
+    } else {
+	reflect = 1;
+	expansion = -det;
+    }
+    
+    pen->num_vertices = _cairo_pen_vertices_needed (radius, gstate->tolerance, expansion);
     /* number of vertices must be even */
     if (pen->num_vertices % 2)
 	pen->num_vertices++;
@@ -78,14 +93,20 @@
 	return CAIRO_STATUS_NO_MEMORY;
     }
 
+    /*
+     * Compute pen coordinates.  To generate the right ellipse, compute points around
+     * a circle in user space and transform them to device space.  To get a consistent
+     * orientation in device space, flip the pen if the transformation matrix
+     * is reflecting
+     */
     for (i=0; i < pen->num_vertices; i++) {
 	double theta = 2 * M_PI * i / (double) pen->num_vertices;
-	double dx = radius * cos (theta);
-	double dy = radius * sin (theta);
+	double dx = radius * cos (reflect ? -theta : theta);
+	double dy = radius * sin (reflect ? -theta : theta);
 	cairo_pen_vertex_t *v = &pen->vertex[i];
 	cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
-	v->pt.x = XDoubleToFixed (dx);
-	v->pt.y = XDoubleToFixed (dy);
+	v->pt.x = cairo_double_to_fixed (dx);
+	v->pt.y = cairo_double_to_fixed (dy);
     }
 
     _cairo_pen_compute_slopes (pen);
@@ -157,15 +178,9 @@
 }
 
 static int
-_cairo_pen_vertices_needed (double radius, double tolerance, cairo_matrix_t *matrix)
+_cairo_pen_vertices_needed (double radius, double tolerance, double expansion)
 {
-    double expansion, theta;
-
-    /* The determinant represents the area expansion factor of the
-       transform. In the worst case, this is entirely in one
-       dimension, which is what we assume here. */
-
-    _cairo_matrix_compute_determinant (matrix, &expansion);
+    double theta;
 
     if (tolerance > expansion*radius) {
 	return 4;




More information about the Commit mailing list