Upload Tizen2.0 source
[framework/graphics/cairo.git] / doc / tutorial / src / singular.c
1 /**
2  * Uses Singular values of transformation matrix to find the length of the
3  * major and minor axes of the scaled pen.
4  *
5  * Put this file in cairo/doc/tutorial/src and type "make"
6  */
7
8 #define WIDTH 300
9 #define HEIGHT 300
10
11 #include "cairo-tutorial.h"
12
13 #include <math.h>
14
15 /*
16  * Finds the singular values of the non-translation part of matrix.
17  *
18  * Let M be the cairo transformation matrix in question:
19  *
20  *       ⌈xx xy⌉
21  *   M = |yx yy|
22  *       ⌊x0 y0⌋
23  *
24  * The non-translation part is:
25  *
26  *   A = ⌈xx xy⌉
27  *       ⌊yx yy⌋
28  *
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.
31  *
32  *   A⁺ A = ⌈xx yx⌉⌈xx xy⌉ = ⌈xx²+yx²     xx*xy+yx*yy⌉
33  *          ⌊xy yy⌋⌊yx yy⌋   ⌊xx*xy+yx*yy     xy²+yy²⌋
34  *
35  * Name those:
36  *
37  *   B = A⁺ A = ⌈a k⌉
38  *              ⌊k b⌋
39  *
40  * The eigenvalues of B satisfy:
41  *
42  *   λ² - (a+b).λ + a.b - k² = 0
43  *
44  * The eigenvalues are:
45  *                __________________
46  *       (a+b) ± √(a+b)² - 4(a.b-k²)
47  *   λ = ---------------------------
48  *                   2
49  * that simplifies to:
50  *                  _______________
51  *   λ = (a+b)/2 ± √((a-b)/2)² + k²
52  *
53  * And the Singular values are the root of λs.
54  *
55  */
56 static void
57 get_singular_values (const cairo_matrix_t *matrix,
58                      double *major,
59                      double *minor)
60 {
61     double xx = matrix->xx, xy = matrix->xy;
62     double yx = matrix->yx, yy = matrix->yy;
63
64     double a = xx*xx+yx*yx;
65     double b = xy*xy+yy*yy;
66     double k = xx*xy+yx*yy;
67
68     double f = (a+b) * .5;
69     double g = (a-b) * .5;
70     double delta = sqrt (g*g + k*k);
71
72     if (major)
73         *major = sqrt (f + delta);
74     if (minor)
75         *minor = sqrt (f - delta);
76 }
77
78 /*
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.
81  *
82  * Returned values are in device units.
83  */
84 static void
85 get_pen_axes (cairo_t *cr,
86               double *major,
87               double *minor)
88 {
89     double width;
90     cairo_matrix_t matrix;
91
92     width = cairo_get_line_width (cr);
93     cairo_get_matrix (cr, &matrix);
94
95     get_singular_values (&matrix, major, minor);
96
97     if (major)
98         *major *= width;
99     if (minor)
100         *minor *= width;
101 }
102
103 static void
104 draw (cairo_t *cr, int width, int height)
105 {
106     double major_width, minor_width;
107
108     /* clear background */
109     cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
110     cairo_paint (cr);
111
112 #define W width
113 #define H height
114 #define B ((width+height)/16)
115
116     /* the spline we want to stroke */
117     cairo_move_to  (cr, W-B, B);
118     cairo_curve_to (cr, -W,   B,
119                         2*W, H-B,
120                         B,   H-B);
121
122     /* the effect is show better with round caps */
123     cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
124
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);
130
131     get_pen_axes (cr, &major_width, &minor_width);
132
133     /* stroke with "major" pen in translucent red */
134     cairo_save (cr);
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);
139     cairo_restore (cr);
140
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);
144
145     /* stroke with "minor" pen in translucent yellow */
146     cairo_save (cr);
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);
151     cairo_restore (cr);
152
153     /* stroke with hairline in black */
154     cairo_save (cr);
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);
159     cairo_restore (cr);
160
161     cairo_new_path (cr);
162 }