Add stubs for Direct3D9 backend.
[cairo/gpu.git] / src / cairo-matrix.c
blobb9e7290a63a485bf1a5da516a28f8890b20a818c
1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2002 University of Southern California
5 * This library is free software; you can redistribute it and/or
6 * modify it either under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation
8 * (the "LGPL") or, at your option, under the terms of the Mozilla
9 * Public License Version 1.1 (the "MPL"). If you do not alter this
10 * notice, a recipient may use your version of this file under either
11 * the MPL or the LGPL.
13 * You should have received a copy of the LGPL along with this library
14 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
19 * The contents of this file are subject to the Mozilla Public License
20 * Version 1.1 (the "License"); you may not use this file except in
21 * compliance with the License. You may obtain a copy of the License at
22 * http://www.mozilla.org/MPL/
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 * the specific language governing rights and limitations.
28 * The Original Code is the cairo graphics library.
30 * The Initial Developer of the Original Code is University of Southern
31 * California.
33 * Contributor(s):
34 * Carl D. Worth <cworth@cworth.org>
37 #define _GNU_SOURCE
39 #include "cairoint.h"
41 #if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
42 #define ISFINITE(x) isfinite (x)
43 #else
44 #define ISFINITE(x) ((x) * (x) >= 0.) /* check for NaNs */
45 #endif
47 static void
48 _cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar);
50 static void
51 _cairo_matrix_compute_adjoint (cairo_matrix_t *matrix);
53 /**
54 * cairo_matrix_init_identity:
55 * @matrix: a #cairo_matrix_t
57 * Modifies @matrix to be an identity transformation.
58 **/
59 void
60 cairo_matrix_init_identity (cairo_matrix_t *matrix)
62 cairo_matrix_init (matrix,
63 1, 0,
64 0, 1,
65 0, 0);
67 slim_hidden_def(cairo_matrix_init_identity);
69 /**
70 * cairo_matrix_init:
71 * @matrix: a #cairo_matrix_t
72 * @xx: xx component of the affine transformation
73 * @yx: yx component of the affine transformation
74 * @xy: xy component of the affine transformation
75 * @yy: yy component of the affine transformation
76 * @x0: X translation component of the affine transformation
77 * @y0: Y translation component of the affine transformation
79 * Sets @matrix to be the affine transformation given by
80 * @xx, @yx, @xy, @yy, @x0, @y0. The transformation is given
81 * by:
82 * <programlisting>
83 * x_new = xx * x + xy * y + x0;
84 * y_new = yx * x + yy * y + y0;
85 * </programlisting>
86 **/
87 void
88 cairo_matrix_init (cairo_matrix_t *matrix,
89 double xx, double yx,
91 double xy, double yy,
92 double x0, double y0)
94 matrix->xx = xx; matrix->yx = yx;
95 matrix->xy = xy; matrix->yy = yy;
96 matrix->x0 = x0; matrix->y0 = y0;
98 slim_hidden_def(cairo_matrix_init);
101 * _cairo_matrix_get_affine:
102 * @matrix: a #cairo_matrix_t
103 * @xx: location to store xx component of matrix
104 * @yx: location to store yx component of matrix
105 * @xy: location to store xy component of matrix
106 * @yy: location to store yy component of matrix
107 * @x0: location to store x0 (X-translation component) of matrix, or %NULL
108 * @y0: location to store y0 (Y-translation component) of matrix, or %NULL
110 * Gets the matrix values for the affine transformation that @matrix represents.
111 * See cairo_matrix_init().
114 * This function is a leftover from the old public API, but is still
115 * mildly useful as an internal means for getting at the matrix
116 * members in a positional way. For example, when reassigning to some
117 * external matrix type, or when renaming members to more meaningful
118 * names (such as a,b,c,d,e,f) for particular manipulations.
120 void
121 _cairo_matrix_get_affine (const cairo_matrix_t *matrix,
122 double *xx, double *yx,
123 double *xy, double *yy,
124 double *x0, double *y0)
126 *xx = matrix->xx;
127 *yx = matrix->yx;
129 *xy = matrix->xy;
130 *yy = matrix->yy;
132 if (x0)
133 *x0 = matrix->x0;
134 if (y0)
135 *y0 = matrix->y0;
139 * cairo_matrix_init_translate:
140 * @matrix: a #cairo_matrix_t
141 * @tx: amount to translate in the X direction
142 * @ty: amount to translate in the Y direction
144 * Initializes @matrix to a transformation that translates by @tx and
145 * @ty in the X and Y dimensions, respectively.
147 void
148 cairo_matrix_init_translate (cairo_matrix_t *matrix,
149 double tx, double ty)
151 cairo_matrix_init (matrix,
152 1, 0,
153 0, 1,
154 tx, ty);
156 slim_hidden_def(cairo_matrix_init_translate);
159 * cairo_matrix_translate:
160 * @matrix: a #cairo_matrix_t
161 * @tx: amount to translate in the X direction
162 * @ty: amount to translate in the Y direction
164 * Applies a translation by @tx, @ty to the transformation in
165 * @matrix. The effect of the new transformation is to first translate
166 * the coordinates by @tx and @ty, then apply the original transformation
167 * to the coordinates.
169 void
170 cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty)
172 cairo_matrix_t tmp;
174 cairo_matrix_init_translate (&tmp, tx, ty);
176 cairo_matrix_multiply (matrix, &tmp, matrix);
178 slim_hidden_def (cairo_matrix_translate);
181 * cairo_matrix_init_scale:
182 * @matrix: a #cairo_matrix_t
183 * @sx: scale factor in the X direction
184 * @sy: scale factor in the Y direction
186 * Initializes @matrix to a transformation that scales by @sx and @sy
187 * in the X and Y dimensions, respectively.
189 void
190 cairo_matrix_init_scale (cairo_matrix_t *matrix,
191 double sx, double sy)
193 cairo_matrix_init (matrix,
194 sx, 0,
195 0, sy,
196 0, 0);
198 slim_hidden_def(cairo_matrix_init_scale);
201 * cairo_matrix_scale:
202 * @matrix: a #cairo_matrix_t
203 * @sx: scale factor in the X direction
204 * @sy: scale factor in the Y direction
206 * Applies scaling by @sx, @sy to the transformation in @matrix. The
207 * effect of the new transformation is to first scale the coordinates
208 * by @sx and @sy, then apply the original transformation to the coordinates.
210 void
211 cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy)
213 cairo_matrix_t tmp;
215 cairo_matrix_init_scale (&tmp, sx, sy);
217 cairo_matrix_multiply (matrix, &tmp, matrix);
219 slim_hidden_def(cairo_matrix_scale);
222 * cairo_matrix_init_rotate:
223 * @matrix: a #cairo_matrix_t
224 * @radians: angle of rotation, in radians. The direction of rotation
225 * is defined such that positive angles rotate in the direction from
226 * the positive X axis toward the positive Y axis. With the default
227 * axis orientation of cairo, positive angles rotate in a clockwise
228 * direction.
230 * Initialized @matrix to a transformation that rotates by @radians.
232 void
233 cairo_matrix_init_rotate (cairo_matrix_t *matrix,
234 double radians)
236 double s;
237 double c;
239 s = sin (radians);
240 c = cos (radians);
242 cairo_matrix_init (matrix,
243 c, s,
244 -s, c,
245 0, 0);
247 slim_hidden_def(cairo_matrix_init_rotate);
250 * cairo_matrix_rotate:
251 * @matrix: a #cairo_matrix_t
252 * @radians: angle of rotation, in radians. The direction of rotation
253 * is defined such that positive angles rotate in the direction from
254 * the positive X axis toward the positive Y axis. With the default
255 * axis orientation of cairo, positive angles rotate in a clockwise
256 * direction.
258 * Applies rotation by @radians to the transformation in
259 * @matrix. The effect of the new transformation is to first rotate the
260 * coordinates by @radians, then apply the original transformation
261 * to the coordinates.
263 void
264 cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
266 cairo_matrix_t tmp;
268 cairo_matrix_init_rotate (&tmp, radians);
270 cairo_matrix_multiply (matrix, &tmp, matrix);
274 * cairo_matrix_multiply:
275 * @result: a #cairo_matrix_t in which to store the result
276 * @a: a #cairo_matrix_t
277 * @b: a #cairo_matrix_t
279 * Multiplies the affine transformations in @a and @b together
280 * and stores the result in @result. The effect of the resulting
281 * transformation is to first apply the transformation in @a to the
282 * coordinates and then apply the transformation in @b to the
283 * coordinates.
285 * It is allowable for @result to be identical to either @a or @b.
288 * XXX: The ordering of the arguments to this function corresponds
289 * to [row_vector]*A*B. If we want to use column vectors instead,
290 * then we need to switch the two arguments and fix up all
291 * uses.
293 void
294 cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b)
296 cairo_matrix_t r;
298 r.xx = a->xx * b->xx + a->yx * b->xy;
299 r.yx = a->xx * b->yx + a->yx * b->yy;
301 r.xy = a->xy * b->xx + a->yy * b->xy;
302 r.yy = a->xy * b->yx + a->yy * b->yy;
304 r.x0 = a->x0 * b->xx + a->y0 * b->xy + b->x0;
305 r.y0 = a->x0 * b->yx + a->y0 * b->yy + b->y0;
307 *result = r;
309 slim_hidden_def(cairo_matrix_multiply);
312 * cairo_matrix_transform_distance:
313 * @matrix: a #cairo_matrix_t
314 * @dx: X component of a distance vector. An in/out parameter
315 * @dy: Y component of a distance vector. An in/out parameter
317 * Transforms the distance vector (@dx,@dy) by @matrix. This is
318 * similar to cairo_matrix_transform_point() except that the translation
319 * components of the transformation are ignored. The calculation of
320 * the returned vector is as follows:
322 * <programlisting>
323 * dx2 = dx1 * a + dy1 * c;
324 * dy2 = dx1 * b + dy1 * d;
325 * </programlisting>
327 * Affine transformations are position invariant, so the same vector
328 * always transforms to the same vector. If (@x1,@y1) transforms
329 * to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to
330 * (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2.
332 void
333 cairo_matrix_transform_distance (const cairo_matrix_t *matrix, double *dx, double *dy)
335 double new_x, new_y;
337 new_x = (matrix->xx * *dx + matrix->xy * *dy);
338 new_y = (matrix->yx * *dx + matrix->yy * *dy);
340 *dx = new_x;
341 *dy = new_y;
343 slim_hidden_def(cairo_matrix_transform_distance);
346 * cairo_matrix_transform_point:
347 * @matrix: a #cairo_matrix_t
348 * @x: X position. An in/out parameter
349 * @y: Y position. An in/out parameter
351 * Transforms the point (@x, @y) by @matrix.
353 void
354 cairo_matrix_transform_point (const cairo_matrix_t *matrix, double *x, double *y)
356 cairo_matrix_transform_distance (matrix, x, y);
358 *x += matrix->x0;
359 *y += matrix->y0;
361 slim_hidden_def(cairo_matrix_transform_point);
363 void
364 _cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
365 double *x1, double *y1,
366 double *x2, double *y2,
367 cairo_bool_t *is_tight)
369 int i;
370 double quad_x[4], quad_y[4];
371 double min_x, max_x;
372 double min_y, max_y;
374 if (_cairo_matrix_is_identity (matrix)) {
375 if (is_tight)
376 *is_tight = TRUE;
378 return;
381 if (matrix->xy == 0. && matrix->yx == 0.) {
382 /* non-rotation/skew matrix, just map the two extreme points */
383 quad_x[0] = *x1;
384 quad_y[0] = *y1;
385 cairo_matrix_transform_distance (matrix, &quad_x[0], &quad_y[0]);
387 quad_x[1] = *x2;
388 quad_y[1] = *y2;
389 cairo_matrix_transform_distance (matrix, &quad_x[1], &quad_y[1]);
391 if (quad_x[0] < quad_x[1]) {
392 *x1 = quad_x[0] + matrix->x0;
393 *x2 = quad_x[1] + matrix->x0;
394 } else {
395 *x1 = quad_x[1] + matrix->x0;
396 *x2 = quad_x[0] + matrix->x0;
399 if (quad_y[0] < quad_y[1]) {
400 *y1 = quad_y[0] + matrix->y0;
401 *y2 = quad_y[1] + matrix->y0;
402 } else {
403 *y1 = quad_y[1] + matrix->y0;
404 *y2 = quad_y[0] + matrix->y0;
407 if (is_tight)
408 *is_tight = TRUE;
410 return;
413 /* general matrix */
414 quad_x[0] = *x1;
415 quad_y[0] = *y1;
416 cairo_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]);
418 quad_x[1] = *x2;
419 quad_y[1] = *y1;
420 cairo_matrix_transform_point (matrix, &quad_x[1], &quad_y[1]);
422 quad_x[2] = *x1;
423 quad_y[2] = *y2;
424 cairo_matrix_transform_point (matrix, &quad_x[2], &quad_y[2]);
426 quad_x[3] = *x2;
427 quad_y[3] = *y2;
428 cairo_matrix_transform_point (matrix, &quad_x[3], &quad_y[3]);
430 min_x = max_x = quad_x[0];
431 min_y = max_y = quad_y[0];
433 for (i=1; i < 4; i++) {
434 if (quad_x[i] < min_x)
435 min_x = quad_x[i];
436 if (quad_x[i] > max_x)
437 max_x = quad_x[i];
439 if (quad_y[i] < min_y)
440 min_y = quad_y[i];
441 if (quad_y[i] > max_y)
442 max_y = quad_y[i];
445 *x1 = min_x;
446 *y1 = min_y;
447 *x2 = max_x;
448 *y2 = max_y;
450 if (is_tight) {
451 /* it's tight if and only if the four corner points form an axis-aligned
452 rectangle.
453 And that's true if and only if we can derive corners 0 and 3 from
454 corners 1 and 2 in one of two straightforward ways...
455 We could use a tolerance here but for now we'll fall back to FALSE in the case
456 of floating point error.
458 *is_tight =
459 (quad_x[1] == quad_x[0] && quad_y[1] == quad_y[3] &&
460 quad_x[2] == quad_x[3] && quad_y[2] == quad_y[0]) ||
461 (quad_x[1] == quad_x[3] && quad_y[1] == quad_y[0] &&
462 quad_x[2] == quad_x[0] && quad_y[2] == quad_y[3]);
466 cairo_private void
467 _cairo_matrix_transform_bounding_box_fixed (const cairo_matrix_t *matrix,
468 cairo_box_t *bbox,
469 cairo_bool_t *is_tight)
471 double x1, y1, x2, y2;
473 _cairo_box_to_doubles (bbox, &x1, &y1, &x2, &y2);
474 _cairo_matrix_transform_bounding_box (matrix, &x1, &y1, &x2, &y2, is_tight);
475 _cairo_box_from_doubles (bbox, &x1, &y1, &x2, &y2);
478 static void
479 _cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar)
481 matrix->xx *= scalar;
482 matrix->yx *= scalar;
484 matrix->xy *= scalar;
485 matrix->yy *= scalar;
487 matrix->x0 *= scalar;
488 matrix->y0 *= scalar;
491 /* This function isn't a correct adjoint in that the implicit 1 in the
492 homogeneous result should actually be ad-bc instead. But, since this
493 adjoint is only used in the computation of the inverse, which
494 divides by det (A)=ad-bc anyway, everything works out in the end. */
495 static void
496 _cairo_matrix_compute_adjoint (cairo_matrix_t *matrix)
498 /* adj (A) = transpose (C:cofactor (A,i,j)) */
499 double a, b, c, d, tx, ty;
501 _cairo_matrix_get_affine (matrix,
502 &a, &b,
503 &c, &d,
504 &tx, &ty);
506 cairo_matrix_init (matrix,
507 d, -b,
508 -c, a,
509 c*ty - d*tx, b*tx - a*ty);
513 * cairo_matrix_invert:
514 * @matrix: a #cairo_matrix_t
516 * Changes @matrix to be the inverse of its original value. Not
517 * all transformation matrices have inverses; if the matrix
518 * collapses points together (it is <firstterm>degenerate</firstterm>),
519 * then it has no inverse and this function will fail.
521 * Returns: If @matrix has an inverse, modifies @matrix to
522 * be the inverse matrix and returns %CAIRO_STATUS_SUCCESS. Otherwise,
523 * returns %CAIRO_STATUS_INVALID_MATRIX.
525 cairo_status_t
526 cairo_matrix_invert (cairo_matrix_t *matrix)
528 double det;
530 /* Simple scaling|translation matrices are quite common... */
531 if (matrix->xy == 0. && matrix->yx == 0.) {
532 matrix->x0 = -matrix->x0;
533 matrix->y0 = -matrix->y0;
535 if (matrix->xx != 1.) {
536 if (matrix->xx == 0.)
537 return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
539 matrix->xx = 1. / matrix->xx;
540 matrix->x0 *= matrix->xx;
543 if (matrix->yy != 1.) {
544 if (matrix->yy == 0.)
545 return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
547 matrix->yy = 1. / matrix->yy;
548 matrix->y0 *= matrix->yy;
551 return CAIRO_STATUS_SUCCESS;
554 /* inv (A) = 1/det (A) * adj (A) */
555 det = _cairo_matrix_compute_determinant (matrix);
557 if (! ISFINITE (det))
558 return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
560 if (det == 0)
561 return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
563 _cairo_matrix_compute_adjoint (matrix);
564 _cairo_matrix_scalar_multiply (matrix, 1 / det);
566 return CAIRO_STATUS_SUCCESS;
568 slim_hidden_def(cairo_matrix_invert);
570 cairo_bool_t
571 _cairo_matrix_is_invertible (const cairo_matrix_t *matrix)
573 double det;
575 det = _cairo_matrix_compute_determinant (matrix);
577 return ISFINITE (det) && det != 0.;
580 double
581 _cairo_matrix_compute_determinant (const cairo_matrix_t *matrix)
583 double a, b, c, d;
585 a = matrix->xx; b = matrix->yx;
586 c = matrix->xy; d = matrix->yy;
588 return a*d - b*c;
592 * _cairo_matrix_compute_basis_scale_factors:
593 * @matrix: a matrix
594 * @basis_scale: the scale factor in the direction of basis
595 * @normal_scale: the scale factor in the direction normal to the basis
596 * @x_basis: basis to use. X basis if true, Y basis otherwise.
598 * Computes |Mv| and det(M)/|Mv| for v=[1,0] if x_basis is true, and v=[0,1]
599 * otherwise, and M is @matrix.
601 * Return value: the scale factor of @matrix on the height of the font,
602 * or 1.0 if @matrix is %NULL.
604 cairo_status_t
605 _cairo_matrix_compute_basis_scale_factors (const cairo_matrix_t *matrix,
606 double *basis_scale, double *normal_scale,
607 cairo_bool_t x_basis)
609 double det;
611 det = _cairo_matrix_compute_determinant (matrix);
613 if (! ISFINITE (det))
614 return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
616 if (det == 0)
618 *basis_scale = *normal_scale = 0;
620 else
622 double x = x_basis != 0;
623 double y = x == 0;
624 double major, minor;
626 cairo_matrix_transform_distance (matrix, &x, &y);
627 major = sqrt(x*x + y*y);
629 * ignore mirroring
631 if (det < 0)
632 det = -det;
633 if (major)
634 minor = det / major;
635 else
636 minor = 0.0;
637 if (x_basis)
639 *basis_scale = major;
640 *normal_scale = minor;
642 else
644 *basis_scale = minor;
645 *normal_scale = major;
649 return CAIRO_STATUS_SUCCESS;
652 cairo_bool_t
653 _cairo_matrix_is_identity (const cairo_matrix_t *matrix)
655 return (matrix->xx == 1.0 && matrix->yx == 0.0 &&
656 matrix->xy == 0.0 && matrix->yy == 1.0 &&
657 matrix->x0 == 0.0 && matrix->y0 == 0.0);
660 cairo_bool_t
661 _cairo_matrix_is_translation (const cairo_matrix_t *matrix)
663 return (matrix->xx == 1.0 && matrix->yx == 0.0 &&
664 matrix->xy == 0.0 && matrix->yy == 1.0);
667 cairo_bool_t
668 _cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix,
669 int *itx, int *ity)
671 if (_cairo_matrix_is_translation (matrix))
673 cairo_fixed_t x0_fixed = _cairo_fixed_from_double (matrix->x0);
674 cairo_fixed_t y0_fixed = _cairo_fixed_from_double (matrix->y0);
676 if (_cairo_fixed_is_integer (x0_fixed) &&
677 _cairo_fixed_is_integer (y0_fixed))
679 if (itx)
680 *itx = _cairo_fixed_integer_part (x0_fixed);
681 if (ity)
682 *ity = _cairo_fixed_integer_part (y0_fixed);
684 return TRUE;
688 return FALSE;
691 /* By pixel exact here, we mean a matrix that is composed only of
692 * 90 degree rotations, flips, and integer translations and produces a 1:1
693 * mapping between source and destination pixels. If we transform an image
694 * with a pixel-exact matrix, filtering is not useful.
696 cairo_private cairo_bool_t
697 _cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix)
699 cairo_fixed_t x0_fixed, y0_fixed;
701 if (matrix->xy == 0.0 && matrix->yx == 0.0) {
702 if (! (matrix->xx == 1.0 || matrix->xx == -1.0))
703 return FALSE;
704 if (! (matrix->yy == 1.0 || matrix->yy == -1.0))
705 return FALSE;
706 } else if (matrix->xx == 0.0 && matrix->yy == 0.0) {
707 if (! (matrix->xy == 1.0 || matrix->xy == -1.0))
708 return FALSE;
709 if (! (matrix->yx == 1.0 || matrix->yx == -1.0))
710 return FALSE;
711 } else
712 return FALSE;
714 x0_fixed = _cairo_fixed_from_double (matrix->x0);
715 y0_fixed = _cairo_fixed_from_double (matrix->y0);
717 return _cairo_fixed_is_integer (x0_fixed) && _cairo_fixed_is_integer (y0_fixed);
721 A circle in user space is transformed into an ellipse in device space.
723 The following is a derivation of a formula to calculate the length of the
724 major axis for this ellipse; this is useful for error bounds calculations.
726 Thanks to Walter Brisken <wbrisken@aoc.nrao.edu> for this derivation:
728 1. First some notation:
730 All capital letters represent vectors in two dimensions. A prime '
731 represents a transformed coordinate. Matrices are written in underlined
732 form, ie _R_. Lowercase letters represent scalar real values.
734 2. The question has been posed: What is the maximum expansion factor
735 achieved by the linear transformation
737 X' = X _R_
739 where _R_ is a real-valued 2x2 matrix with entries:
741 _R_ = [a b]
742 [c d] .
744 In other words, what is the maximum radius, MAX[ |X'| ], reached for any
745 X on the unit circle ( |X| = 1 ) ?
747 3. Some useful formulae
749 (A) through (C) below are standard double-angle formulae. (D) is a lesser
750 known result and is derived below:
752 (A) sin²(θ) = (1 - cos(2*θ))/2
753 (B) cos²(θ) = (1 + cos(2*θ))/2
754 (C) sin(θ)*cos(θ) = sin(2*θ)/2
755 (D) MAX[a*cos(θ) + b*sin(θ)] = sqrt(a² + b²)
757 Proof of (D):
759 find the maximum of the function by setting the derivative to zero:
761 -a*sin(θ)+b*cos(θ) = 0
763 From this it follows that
765 tan(θ) = b/a
767 and hence
769 sin(θ) = b/sqrt(a² + b²)
773 cos(θ) = a/sqrt(a² + b²)
775 Thus the maximum value is
777 MAX[a*cos(θ) + b*sin(θ)] = (a² + b²)/sqrt(a² + b²)
778 = sqrt(a² + b²)
780 4. Derivation of maximum expansion
782 To find MAX[ |X'| ] we search brute force method using calculus. The unit
783 circle on which X is constrained is to be parameterized by t:
785 X(θ) = (cos(θ), sin(θ))
787 Thus
789 X'(θ) = X(θ) * _R_ = (cos(θ), sin(θ)) * [a b]
790 [c d]
791 = (a*cos(θ) + c*sin(θ), b*cos(θ) + d*sin(θ)).
793 Define
795 r(θ) = |X'(θ)|
797 Thus
799 r²(θ) = (a*cos(θ) + c*sin(θ))² + (b*cos(θ) + d*sin(θ))²
800 = (a² + b²)*cos²(θ) + (c² + d²)*sin²(θ)
801 + 2*(a*c + b*d)*cos(θ)*sin(θ)
803 Now apply the double angle formulae (A) to (C) from above:
805 r²(θ) = (a² + b² + c² + d²)/2
806 + (a² + b² - c² - d²)*cos(2*θ)/2
807 + (a*c + b*d)*sin(2*θ)
808 = f + g*cos(φ) + h*sin(φ)
810 Where
812 f = (a² + b² + c² + d²)/2
813 g = (a² + b² - c² - d²)/2
814 h = (a*c + d*d)
815 φ = 2*θ
817 It is clear that MAX[ |X'| ] = sqrt(MAX[ r² ]). Here we determine MAX[ r² ]
818 using (D) from above:
820 MAX[ r² ] = f + sqrt(g² + h²)
822 And finally
824 MAX[ |X'| ] = sqrt( f + sqrt(g² + h²) )
826 Which is the solution to this problem.
828 Walter Brisken
829 2004/10/08
831 (Note that the minor axis length is at the minimum of the above solution,
832 which is just sqrt ( f - sqrt(g² + h²) ) given the symmetry of (D)).
835 For another derivation of the same result, using Singular Value Decomposition,
836 see doc/tutorial/src/singular.c.
839 /* determine the length of the major axis of a circle of the given radius
840 after applying the transformation matrix. */
841 double
842 _cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix,
843 double radius)
845 double a, b, c, d, f, g, h, i, j;
847 _cairo_matrix_get_affine (matrix,
848 &a, &b,
849 &c, &d,
850 NULL, NULL);
852 i = a*a + b*b;
853 j = c*c + d*d;
855 f = 0.5 * (i + j);
856 g = 0.5 * (i - j);
857 h = a*c + b*d;
859 return radius * sqrt (f + sqrt (g*g+h*h));
862 * we don't need the minor axis length, which is
863 * double min = radius * sqrt (f - sqrt (g*g+h*h));
867 void
868 _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
869 pixman_transform_t *pixman_transform,
870 double xc,
871 double yc)
873 static const pixman_transform_t pixman_identity_transform = {{
874 {1 << 16, 0, 0},
875 { 0, 1 << 16, 0},
876 { 0, 0, 1 << 16}
879 if (_cairo_matrix_is_identity (matrix)) {
880 *pixman_transform = pixman_identity_transform;
881 } else {
882 cairo_matrix_t inv;
883 unsigned max_iterations;
885 pixman_transform->matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx);
886 pixman_transform->matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy);
887 pixman_transform->matrix[0][2] = _cairo_fixed_16_16_from_double (matrix->x0);
889 pixman_transform->matrix[1][0] = _cairo_fixed_16_16_from_double (matrix->yx);
890 pixman_transform->matrix[1][1] = _cairo_fixed_16_16_from_double (matrix->yy);
891 pixman_transform->matrix[1][2] = _cairo_fixed_16_16_from_double (matrix->y0);
893 pixman_transform->matrix[2][0] = 0;
894 pixman_transform->matrix[2][1] = 0;
895 pixman_transform->matrix[2][2] = 1 << 16;
897 /* The conversion above breaks cairo's translation invariance:
898 * a translation of (a, b) in device space translates to
899 * a translation of (xx * a + xy * b, yx * a + yy * b)
900 * for cairo, while pixman uses rounded versions of xx ... yy.
901 * This error increases as a and b get larger.
903 * To compensate for this, we fix the point (xc, yc) in pattern
904 * space and adjust pixman's transform to agree with cairo's at
905 * that point.
908 if (_cairo_matrix_is_translation (matrix))
909 return;
911 /* Note: If we can't invert the transformation, skip the adjustment. */
912 inv = *matrix;
913 if (cairo_matrix_invert (&inv) != CAIRO_STATUS_SUCCESS)
914 return;
916 /* find the pattern space coordinate that maps to (xc, yc) */
917 xc += .5; yc += .5; /* offset for the pixel centre */
918 max_iterations = 5;
919 do {
920 double x,y;
921 pixman_vector_t vector;
922 cairo_fixed_16_16_t dx, dy;
924 vector.vector[0] = _cairo_fixed_16_16_from_double (xc);
925 vector.vector[1] = _cairo_fixed_16_16_from_double (yc);
926 vector.vector[2] = 1 << 16;
928 if (! pixman_transform_point_3d (pixman_transform, &vector))
929 return;
931 x = pixman_fixed_to_double (vector.vector[0]);
932 y = pixman_fixed_to_double (vector.vector[1]);
933 cairo_matrix_transform_point (&inv, &x, &y);
935 /* Ideally, the vector should now be (xc, yc).
936 * We can now compensate for the resulting error.
938 x -= xc;
939 y -= yc;
940 cairo_matrix_transform_distance (matrix, &x, &y);
941 dx = _cairo_fixed_16_16_from_double (x);
942 dy = _cairo_fixed_16_16_from_double (y);
943 pixman_transform->matrix[0][2] -= dx;
944 pixman_transform->matrix[1][2] -= dy;
946 if (dx == 0 && dy == 0)
947 break;
948 } while (--max_iterations);