[cairo-commit] cairo/src cairo-matrix.c, 1.30, 1.31 cairo-pen.c,
1.24, 1.25 cairoint.h, 1.202, 1.203
Bertram Felgenhauer
commit at pdx.freedesktop.org
Mon Aug 22 16:48:31 PDT 2005
Committed by: inte
Update of /cvs/cairo/cairo/src
In directory gabe:/tmp/cvs-serv13483/src
Modified Files:
cairo-matrix.c cairo-pen.c cairoint.h
Log Message:
2005-08-22 Bertram Felgenhauer <int-e at gmx.de>
* src/cairo-pen.c (_cairo_pen_vertices_needed): use new function.
strip comment of derivation for major axis length.
* src/cairo-matrix.c (_cairo_matrix_transformed_circle_major_axis):
use _cairo_matrix_get_affine to retrieve matrix entries.
* src/cairoint.h, src/cairo-matrix.c
(_cairo_matrix_transformed_circle_major_axis): new function split out
of cairo-pen.c. UTF8-ify the comment that explains the calculation.
Index: cairo-matrix.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-matrix.c,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -d -r1.30 -r1.31
--- cairo-matrix.c 5 Aug 2005 17:05:29 -0000 1.30
+++ cairo-matrix.c 22 Aug 2005 23:48:28 -0000 1.31
@@ -587,3 +587,148 @@
return TRUE;
}
+
+/*
+ A circle in user space is transformed into an ellipse in device space.
+
+ The following is a derivation of a formula to calculate the length of the
+ major axis for this ellipse; this is useful for error bounds calculations.
+
+ Thanks to Walter Brisken <wbrisken at aoc.nrao.edu> for this derivation:
+
+ 1. First some notation:
+
+ All capital letters represent vectors in two dimensions. A prime '
+ represents a transformed coordinate. Matrices are written in underlined
+ form, ie _R_. Lowercase letters represent scalar real values.
+
+ 2. The question has been posed: What is the maximum expansion factor
+ achieved by the linear transformation
+
+ X' = X _R_
+
+ where _R_ is a real-valued 2x2 matrix with entries:
+
+ _R_ = [a b]
+ [c d] .
+
+ In other words, what is the maximum radius, MAX[ |X'| ], reached for any
+ X on the unit circle ( |X| = 1 ) ?
+
+
+ 3. Some useful formulae
+
+ (A) through (C) below are standard double-angle formulae. (D) is a lesser
+ known result and is derived below:
+
+ (A) sin²(θ) = (1 - cos(2*θ))/2
+ (B) cos²(θ) = (1 + cos(2*θ))/2
+ (C) sin(θ)*cos(θ) = sin(2*θ)/2
+ (D) MAX[a*cos(θ) + b*sin(θ)] = sqrt(a² + b²)
+
+ Proof of (D):
+
+ find the maximum of the function by setting the derivative to zero:
+
+ -a*sin(θ)+b*cos(θ) = 0
+
+ From this it follows that
+
+ tan(θ) = b/a
+
+ and hence
+
+ sin(θ) = b/sqrt(a² + b²)
+
+ and
+
+ cos(θ) = a/sqrt(a² + b²)
+
+ Thus the maximum value is
+
+ MAX[a*cos(θ) + b*sin(θ)] = (a² + b²)/sqrt(a² + b²)
+ = sqrt(a² + b²)
+
+
+ 4. Derivation of maximum expansion
+
+ To find MAX[ |X'| ] we search brute force method using calculus. The unit
+ circle on which X is constrained is to be parameterized by t:
+
+ X(θ) = (cos(θ), sin(θ))
+
+ Thus
+
+ X'(θ) = X(θ) * _R_ = (cos(θ), sin(θ)) * [a b]
+ [c d]
+ = (a*cos(θ) + c*sin(θ), b*cos(θ) + d*sin(θ)).
+
+ Define
+
+ r(θ) = |X'(θ)|
+
+ Thus
+
+ r²(θ) = (a*cos(θ) + c*sin(θ))² + (b*cos(θ) + d*sin(θ))²
+ = (a² + b²)*cos²(θ) + (c² + d²)*sin²(θ)
+ + 2*(a*c + b*d)*cos(θ)*sin(θ)
+
+ Now apply the double angle formulae (A) to (C) from above:
+
+ r²(θ) = (a² + b² + c² + d²)/2
+ + (a² + b² - c² - d²)*cos(2*θ)/2
+ + (a*c + b*d)*sin(2*θ)
+ = f + g*cos(Ï) + h*sin(Ï)
+
+ Where
+
+ f = (a² + b² + c² + d²)/2
+ g = (a² + b² - c² - d²)/2
+ h = (a*c + d*d)
+ Ï = 2*θ
+
+ It is clear that MAX[ |X'| ] = sqrt(MAX[ r² ]). Here we determine MAX[ r² ]
+ using (D) from above:
+
+ MAX[ r² ] = f + sqrt(g² + h²)
+
+ And finally
+
+ MAX[ |X'| ] = sqrt( f + sqrt(g² + h²) )
+
+ Which is the solution to this problem.
+
+
+ Walter Brisken
+ 2004/10/08
+
+ (Note that the minor axis length is at the minimum of the above solution,
+ which is just sqrt ( f - sqrt(g² + h²) ) given the symmetry of (D)).
+*/
+
+/* determine the length of the major axis of a circle of the given radius
+ after applying the transformation matrix. */
+double
+_cairo_matrix_transformed_circle_major_axis (cairo_matrix_t *matrix, double radius)
+{
+ double a, b, c, d;
+
+ _cairo_matrix_get_affine (matrix,
+ &a, &b,
+ &c, &d,
+ NULL, NULL);
+
+ double i = a*a + b*b;
+ double j = c*c + d*d;
+
+ double f = 0.5 * (i + j);
+ double g = 0.5 * (i - j);
+ double h = a*c + b*d;
+
+ return radius * sqrt (f + sqrt (g*g+h*h));
+
+ /*
+ * we don't need the minor axis length, which is
+ * double min = radius * sqrt (f - sqrt (g*g+h*h));
+ */
+}
Index: cairo-pen.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-pen.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- cairo-pen.c 22 Aug 2005 23:29:56 -0000 1.24
+++ cairo-pen.c 22 Aug 2005 23:48:28 -0000 1.25
@@ -173,132 +173,13 @@
We construct the pen by computing points along the circumference
using equally spaced angles.
-We show below that this approximation to the ellipse has
-maximum error at the major axis of the ellipse.
-So, we need to compute the length of the major axis and then
-use that to compute the number of sides needed in our pen.
-
-Thanks to Walter Brisken <wbrisken at aoc.nrao.edu> for this
-derivation:
-
-1. First some notation:
-
-All capital letters represent vectors in two dimensions. A prime '
-represents a transformed coordinate. Matrices are written in underlined
-form, ie _R_. Lowercase letters represent scalar real values.
-
-The letter t is used to represent the greek letter theta.
-
-2. The question has been posed: What is the maximum expansion factor
-achieved by the linear transformation
-
-X' = X _R_
-
-where _R_ is a real-valued 2x2 matrix with entries:
-
-_R_ = [a b]
- [c d] .
-
-In other words, what is the maximum radius, MAX[ |X'| ], reached for any
-X on the unit circle ( |X| = 1 ) ?
-
-
-3. Some useful formulae
-
-(A) through (C) below are standard double-angle formulae. (D) is a lesser
-known result and is derived below:
-
-(A) sin^2(t) = (1 - cos(2*t))/2
-(B) cos^2(t) = (1 + cos(2*t))/2
-(C) sin(t)*cos(t) = sin(2*t)/2
-(D) MAX[a*cos(t) + b*sin(t)] = sqrt(a^2 + b^2)
-
-Proof of (D):
-
-find the maximum of the function by setting the derivative to zero:
-
- -a*sin(t)+b*cos(t) = 0
-
-From this it follows that
-
- tan(t) = b/a
-
-and hence
-
- sin(t) = b/sqrt(a^2 + b^2)
-
-and
-
- cos(t) = a/sqrt(a^2 + b^2)
-
-Thus the maximum value is
-
- MAX[a*cos(t) + b*sin(t)] = (a^2 + b^2)/sqrt(a^2 + b^2)
- = sqrt(a^2 + b^2)
-
-
-4. Derivation of maximum expansion
-
-To find MAX[ |X'| ] we search brute force method using calculus. The unit
-circle on which X is constrained is to be parameterized by t:
-
- X(t) = (cos(t), sin(t))
-
-Thus
-
- X'(t) = X(t) * _R_ = (cos(t), sin(t)) * [a b]
- [c d]
- = (a*cos(t) + c*sin(t), b*cos(t) + d*sin(t)).
-
-Define
-
- r(t) = |X'(t)|
-
-Thus
-
- r^2(t) = (a*cos(t) + c*sin(t))^2 + (b*cos(t) + d*sin(t))^2
- = (a^2 + b^2)*cos^2(t) + (c^2 + d^2)*sin^2(t)
- + 2*(a*c + b*d)*cos(t)*sin(t)
-
-Now apply the double angle formulae (A) to (C) from above:
-
- r^2(t) = (a^2 + b^2 + c^2 + d^2)/2
- + (a^2 + b^2 - c^2 - d^2)*cos(2*t)/2
- + (a*c + b*d)*sin(2*t)
- = f + g*cos(u) + h*sin(u)
-
-Where
-
- f = (a^2 + b^2 + c^2 + d^2)/2
- g = (a^2 + b^2 - c^2 - d^2)/2
- h = (a*c + b*d)
- u = 2*t
-
-It is clear that MAX[ |X'| ] = sqrt(MAX[ r^2 ]). Here we determine MAX[ r^2 ]
-using (D) from above:
-
- MAX[ r^2 ] = f + sqrt(g^2 + h^2)
-
-And finally
-
- MAX[ |X'| ] = sqrt( f + sqrt(g^2 + h^2) )
-
-Which is the solution to this problem.
-
-
-Walter Brisken
-2004/10/08
-
-(Note that the minor axis length is at the minimum of the above solution,
-which is just sqrt (f - sqrt (g^2 + h^2)) given the symmetry of (D)).
-
-Now to compute how many sides to use for the pen formed by
-a regular polygon.
+We show that this approximation to the ellipse has maximum error at the
+major axis of the ellipse.
Set
- M = major axis length (computed by above formula)
- m = minor axis length (computed by above formula)
+ M = major axis length
+ m = minor axis length
Align 'M' along the X axis and 'm' along the Y axis and draw
an ellipse parameterized by angle 't':
@@ -363,12 +244,11 @@
Remembering that â is half of our angle between vertices,
the number of vertices is then
-vertices = ceil(2Ï/2â).
- = ceil(Ï/â).
+ vertices = ceil(2Ï/2â).
+ = ceil(Ï/â).
Note that this also equation works for M == m (a circle) as it
doesn't matter where on the circle the error is computed.
-
*/
static int
@@ -376,29 +256,15 @@
double radius,
cairo_matrix_t *matrix)
{
- double a = matrix->xx, b = matrix->yx;
- double c = matrix->xy, d = matrix->yy;
-
- double i = a*a + b*b;
- double j = c*c + d*d;
-
- double f = 0.5 * (i + j);
- double g = 0.5 * (i - j);
- double h = a*c + b*d;
-
/*
- * compute major and minor axes lengths for
- * a pen with the specified radius
+ * the pen is a circle that gets transformed to an ellipse by matrix.
+ * compute major axis length for a pen with the specified radius.
+ * we don't need the minor axis length.
*/
- double major_axis = radius * sqrt (f + sqrt (g*g+h*h));
+ double major_axis = _cairo_matrix_transformed_circle_major_axis(matrix, radius);
/*
- * we don't need the minor axis length, which is
- * double min = radius * sqrt (f - sqrt (g*g+h*h));
- */
-
- /*
* compute number of vertices needed
*/
int num_vertices;
Index: cairoint.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairoint.h,v
retrieving revision 1.202
retrieving revision 1.203
diff -u -d -r1.202 -r1.203
--- cairoint.h 22 Aug 2005 04:04:52 -0000 1.202
+++ cairoint.h 22 Aug 2005 23:48:28 -0000 1.203
@@ -1866,6 +1866,9 @@
_cairo_matrix_is_integer_translation(const cairo_matrix_t *matrix,
int *itx, int *ity);
+cairo_private double
+_cairo_matrix_transformed_circle_major_axis(cairo_matrix_t *matrix, double radius);
+
/* cairo_traps.c */
cairo_private void
_cairo_traps_init (cairo_traps_t *traps);
More information about the cairo-commit
mailing list