2 * Uses Singular values of transformation matrix to find the length of the
3 * major and minor axes of the scaled pen.
5 * Put this file in cairo/doc/tutorial/src and type "make"
11 #include "cairo-tutorial.h"
16 * Finds the singular values of the non-translation part of matrix.
18 * Let M be the cairo transformation matrix in question:
24 * The non-translation part is:
29 * The non-zero singular values of A are the square roots of the non-zero
30 * eigenvalues of A⁺ A, where A⁺ is A-transpose.
32 * A⁺ A = ⌈xx yx⌉⌈xx xy⌉ = ⌈xx²+yx² xx*xy+yx*yy⌉
33 * ⌊xy yy⌋⌊yx yy⌋ ⌊xx*xy+yx*yy xy²+yy²⌋
40 * The eigenvalues of B satisfy:
42 * λ² - (a+b).λ + a.b - k² = 0
44 * The eigenvalues are:
46 * (a+b) ± √(a+b)² - 4(a.b-k²)
47 * λ = ---------------------------
51 * λ = (a+b)/2 ± √((a-b)/2)² + k²
53 * And the Singular values are the root of λs.
57 get_singular_values (const cairo_matrix_t *matrix,
61 double xx = matrix->xx, xy = matrix->xy;
62 double yx = matrix->yx, yy = matrix->yy;
64 double a = xx*xx+yx*yx;
65 double b = xy*xy+yy*yy;
66 double k = xx*xy+yx*yy;
68 double f = (a+b) * .5;
69 double g = (a-b) * .5;
70 double delta = sqrt (g*g + k*k);
73 *major = sqrt (f + delta);
75 *minor = sqrt (f - delta);
79 * Finds the length of the major and minor axes of the pen for a cairo_t,
80 * identified by the current transformation matrix and line width.
82 * Returned values are in device units.
85 get_pen_axes (cairo_t *cr,
90 cairo_matrix_t matrix;
92 width = cairo_get_line_width (cr);
93 cairo_get_matrix (cr, &matrix);
95 get_singular_values (&matrix, major, minor);
104 draw (cairo_t *cr, int width, int height)
106 double major_width, minor_width;
108 /* clear background */
109 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
114 #define B ((width+height)/16)
116 /* the spline we want to stroke */
117 cairo_move_to (cr, W-B, B);
118 cairo_curve_to (cr, -W, B,
122 /* the effect is show better with round caps */
123 cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
125 /* set the skewed pen */
126 cairo_rotate (cr, +.7);
127 cairo_scale (cr, .5, 2.);
128 cairo_rotate (cr, -.7);
129 cairo_set_line_width (cr, B);
131 get_pen_axes (cr, &major_width, &minor_width);
133 /* stroke with "major" pen in translucent red */
135 cairo_identity_matrix (cr);
136 cairo_set_line_width (cr, major_width);
137 cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, .9);
138 cairo_stroke_preserve (cr);
141 /* stroke with skewed pen in translucent black */
142 cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, .9);
143 cairo_stroke_preserve (cr);
145 /* stroke with "minor" pen in translucent yellow */
147 cairo_identity_matrix (cr);
148 cairo_set_line_width (cr, minor_width);
149 cairo_set_source_rgba (cr, 1.0, 1.0, 0.0, .9);
150 cairo_stroke_preserve (cr);
153 /* stroke with hairline in black */
155 cairo_identity_matrix (cr);
156 cairo_set_line_width (cr, 1);
157 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
158 cairo_stroke_preserve (cr);