[Commit] cairo/src cairo_path_stroke.c, 1.4, 1.5 cairoint.h, 1.12, 1.13

Keith Packard commit at keithp.com
Thu Sep 4 12:54:11 PDT 2003


Committed by: keithp

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

Modified Files:
	cairo_path_stroke.c cairoint.h 
Log Message:
	* src/cairo_path_stroke.c: added comments describing miter
	join code and miter limit computation.  Replace XFoo with cairo_foo
	for double and fixed

	* src/cairoint.h: add cairo_fixed_to_double and cairo_double_to_fixed
	Carl says he's got similar code, so he'll have to fix things if I
	get this committed quickly enough.



Index: cairo_path_stroke.c
===================================================================
RCS file: /local/src/CVS/cairo/src/cairo_path_stroke.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- cairo_path_stroke.c	26 Aug 2003 14:40:17 -0000	1.4
+++ cairo_path_stroke.c	4 Sep 2003 18:54:09 -0000	1.5
@@ -209,39 +209,87 @@
     }
     case CAIRO_LINE_JOIN_MITER:
     default: {
-	cairo_polygon_t	polygon;
-	XDouble	c = (-in->usr_vector.x * out->usr_vector.x)+(-in->usr_vector.y * out->usr_vector.y);
-	XDouble ml = gstate->miter_limit;
-
-	_cairo_polygon_init (&polygon);
+	/* dot product of incoming slope vector with outgoing slope vector */
+	double	in_dot_out = ((-in->usr_vector.x * out->usr_vector.x)+
+			      (-in->usr_vector.y * out->usr_vector.y));
+	double	ml = gstate->miter_limit;
 
-	if (2 <= ml * ml * (1 - c)) {
-	    XDouble x1, y1, x2, y2;
-	    XDouble mx, my;
-	    XDouble dx1, dx2, dy1, dy2;
+	/*
+	 * Check the miter limit -- lines meeting at an acute angle
+	 * can generate long miters, the limit converts them to bevel
+	 *
+	 * We want to know when the miter is within the miter limit.
+	 * That's straightforward to specify:
+	 *
+	 *	secant (psi / 2) <= ml
+	 *
+	 * where psi is the angle between in and out
+	 *
+	 *				secant(psi/2) = 1/sin(psi/2)
+	 *	1/sin(psi/2) <= ml
+	 *	1 <= ml sin(psi/2)
+	 *	1 <= ml² sin²(psi/2)
+	 *	2 <= ml² 2 sin²(psi/2)
+	 *				2·sin²(psi/2) = 1-cos(psi)
+	 *	2 <= ml² (1-cos(psi))
+	 *
+	 *				in · out = |in| |out| cos (psi)
+	 *
+	 * in and out are both unit vectors, so:
+	 *
+	 *				in · out = cos (psi)
+	 *
+	 *	2 <= ml² (1 - in · out)
+	 * 	 
+	 */
+	if (2 <= ml * ml * (1 - in_dot_out)) {
+	    double		x1, y1, x2, y2;
+	    double		mx, my;
+	    double		dx1, dx2, dy1, dy2;
+	    cairo_polygon_t	polygon;
 	    cairo_point_t	outer;
 
-	    x1 = XFixedToDouble (inpt->x);
-	    y1 = XFixedToDouble (inpt->y);
+	    /* 
+	     * we've got the points already transformed to device
+	     * space, but need to do some computation with them and
+	     * also need to transform the slope from user space to
+	     * device space
+	     */
+	    /* outer point of incoming line face */
+	    x1 = cairo_fixed_to_double (inpt->x);
+	    y1 = cairo_fixed_to_double (inpt->y);
 	    dx1 = in->usr_vector.x;
 	    dy1 = in->usr_vector.y;
 	    cairo_matrix_transform_distance (&gstate->ctm, &dx1, &dy1);
 	    
-	    x2 = XFixedToDouble (outpt->x);
-	    y2 = XFixedToDouble (outpt->y);
+	    /* outer point of outgoing line face */
+	    x2 = cairo_fixed_to_double (outpt->x);
+	    y2 = cairo_fixed_to_double (outpt->y);
 	    dx2 = out->usr_vector.x;
 	    dy2 = out->usr_vector.y;
 	    cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
 	    
+	    /*
+	     * Compute the location of the outer corner of the miter.
+	     * That's pretty easy -- just the intersection of the two
+	     * outer edges.  We've got slopes and points on each
+	     * of those edges.  Compute my directly, then compute
+	     * mx by using the edge with the larger dy; that avoids
+	     * dividing by values close to zero.
+	     */
 	    my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
 		  (dx1 * dy2 - dx2 * dy1));
-	    if (dy1)
+	    if (fabs (dy1) >= fabs (dy2))
 		mx = (my - y1) * dx1 / dy1 + x1;
 	    else
 		mx = (my - y2) * dx2 / dy2 + x2;
 	    
-	    outer.x = XDoubleToFixed (mx);
-	    outer.y = XDoubleToFixed (my);
+	    /*
+	     * Draw the quadrilateral
+	     */
+	    outer.x = cairo_double_to_fixed (mx);
+	    outer.y = cairo_double_to_fixed (my);
+	    _cairo_polygon_init (&polygon);
 	    _cairo_polygon_add_edge (&polygon, &in->pt, inpt);
 	    _cairo_polygon_add_edge (&polygon, inpt, &outer);
 	    _cairo_polygon_add_edge (&polygon, &outer, outpt);
@@ -314,8 +362,8 @@
 	dx *= gstate->line_width / 2.0;
 	dy *= gstate->line_width / 2.0;
 	cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
-	fvector.dx = XDoubleToFixed (dx);
-	fvector.dy = XDoubleToFixed (dy);
+	fvector.dx = cairo_double_to_fixed (dx);
+	fvector.dy = cairo_double_to_fixed (dy);
 	occw.x = f->ccw.x + fvector.dx;
 	occw.y = f->ccw.y + fvector.dy;
 	ocw.x = f->cw.x + fvector.dx;
@@ -345,8 +393,8 @@
     XPointDouble usr_vector;
     cairo_point_t offset_ccw, offset_cw;
 
-    dx = XFixedToDouble (slope->dx);
-    dy = XFixedToDouble (slope->dy);
+    dx = cairo_fixed_to_double (slope->dx);
+    dy = cairo_fixed_to_double (slope->dy);
 
     cairo_matrix_transform_distance (&gstate->ctm_inverse, &dx, &dy);
 
@@ -368,8 +416,8 @@
 
     cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
 
-    offset_ccw.x = XDoubleToFixed (dx);
-    offset_ccw.y = XDoubleToFixed (dy);
+    offset_ccw.x = cairo_double_to_fixed (dx);
+    offset_ccw.y = cairo_double_to_fixed (dy);
     offset_cw.x = -offset_ccw.x;
     offset_cw.y = -offset_ccw.y;
 
@@ -470,8 +518,8 @@
     int first = 1;
     cairo_stroke_face_t sub_start, sub_end;
     
-    dx = XFixedToDouble (p2->x - p1->x);
-    dy = XFixedToDouble (p2->y - p1->y);
+    dx = cairo_fixed_to_double (p2->x - p1->x);
+    dy = cairo_fixed_to_double (p2->y - p1->y);
 
     cairo_matrix_transform_distance (&gstate->ctm_inverse, &dx, &dy);
 
@@ -486,8 +534,8 @@
         dx2 = dx * (mag - remain)/mag;
 	dy2 = dy * (mag - remain)/mag;
 	cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
-	fd2.x = XDoubleToFixed (dx2);
-	fd2.y = XDoubleToFixed (dy2);
+	fd2.x = cairo_double_to_fixed (dx2);
+	fd2.y = cairo_double_to_fixed (dy2);
 	fd2.x += p1->x;
 	fd2.y += p1->y;
 	/*

Index: cairoint.h
===================================================================
RCS file: /local/src/CVS/cairo/src/cairoint.h,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- cairoint.h	4 Sep 2003 18:21:15 -0000	1.12
+++ cairoint.h	4 Sep 2003 18:54:09 -0000	1.13
@@ -94,6 +94,9 @@
 /* The common 16.16 format gets a shorter name */
 typedef cairo_fixed_16_16_t cairo_fixed_t;
 
+#define cairo_double_to_fixed(f)    ((cairo_fixed_t) ((f) * 65536))
+#define cairo_fixed_to_double(d)    (((double) (d)) / 65536)
+
 typedef struct cairo_point {
     cairo_fixed_t x;
     cairo_fixed_t y;




More information about the Commit mailing list