📄 cairo-matrix.c
字号:
double dx1, dy1; double dx2, dy2; double min_x, max_x; double min_y, max_y; quad_x[0] = *x; quad_y[0] = *y; cairo_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]); dx1 = *width; dy1 = 0; cairo_matrix_transform_distance (matrix, &dx1, &dy1); quad_x[1] = quad_x[0] + dx1; quad_y[1] = quad_y[0] + dy1; dx2 = 0; dy2 = *height; cairo_matrix_transform_distance (matrix, &dx2, &dy2); quad_x[2] = quad_x[0] + dx2; quad_y[2] = quad_y[0] + dy2; quad_x[3] = quad_x[0] + dx1 + dx2; quad_y[3] = quad_y[0] + dy1 + dy2; min_x = max_x = quad_x[0]; min_y = max_y = quad_y[0]; for (i=1; i < 4; i++) { if (quad_x[i] < min_x) min_x = quad_x[i]; if (quad_x[i] > max_x) max_x = quad_x[i]; if (quad_y[i] < min_y) min_y = quad_y[i]; if (quad_y[i] > max_y) max_y = quad_y[i]; } *x = min_x; *y = min_y; *width = max_x - min_x; *height = max_y - min_y;}static void_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar){ matrix->xx *= scalar; matrix->yx *= scalar; matrix->xy *= scalar; matrix->yy *= scalar; matrix->x0 *= scalar; matrix->y0 *= scalar;}/* This function isn't a correct adjoint in that the implicit 1 in the homogeneous result should actually be ad-bc instead. But, since this adjoint is only used in the computation of the inverse, which divides by det (A)=ad-bc anyway, everything works out in the end. */static void_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix){ /* adj (A) = transpose (C:cofactor (A,i,j)) */ double a, b, c, d, tx, ty; _cairo_matrix_get_affine (matrix, &a, &b, &c, &d, &tx, &ty); cairo_matrix_init (matrix, d, -b, -c, a, c*ty - d*tx, b*tx - a*ty);}/** * cairo_matrix_invert: * @matrix: a @cairo_matrix_t * * Changes @matrix to be the inverse of it's original value. Not * all transformation matrices have inverses; if the matrix * collapses points together (it is <firstterm>degenerate</firstterm>), * then it has no inverse and this function will fail. * * Returns: If @matrix has an inverse, modifies @matrix to * be the inverse matrix and returns %CAIRO_STATUS_SUCCESS. Otherwise, * returns %CAIRO_STATUS_INVALID_MATRIX. **/cairo_status_tcairo_matrix_invert (cairo_matrix_t *matrix){ /* inv (A) = 1/det (A) * adj (A) */ double det; _cairo_matrix_compute_determinant (matrix, &det); if (det == 0) return CAIRO_STATUS_INVALID_MATRIX; _cairo_matrix_compute_adjoint (matrix); _cairo_matrix_scalar_multiply (matrix, 1 / det); return CAIRO_STATUS_SUCCESS;}slim_hidden_def(cairo_matrix_invert);void_cairo_matrix_compute_determinant (const cairo_matrix_t *matrix, double *det){ double a, b, c, d; a = matrix->xx; b = matrix->yx; c = matrix->xy; d = matrix->yy; *det = a*d - b*c;}/* Compute the amount that each basis vector is scaled by. */cairo_status_t_cairo_matrix_compute_scale_factors (const cairo_matrix_t *matrix, double *sx, double *sy, int x_major){ double det; _cairo_matrix_compute_determinant (matrix, &det); if (det == 0) { *sx = *sy = 0; } else { double x = x_major != 0; double y = x == 0; double major, minor; cairo_matrix_transform_distance (matrix, &x, &y); major = sqrt(x*x + y*y); /* * ignore mirroring */ if (det < 0) det = -det; if (major) minor = det / major; else minor = 0.0; if (x_major) { *sx = major; *sy = minor; } else { *sx = minor; *sy = major; } } return CAIRO_STATUS_SUCCESS;}cairo_bool_t_cairo_matrix_is_identity (const cairo_matrix_t *matrix){ return (matrix->xx == 1.0 && matrix->yx == 0.0 && matrix->xy == 0.0 && matrix->yy == 1.0 && matrix->x0 == 0.0 && matrix->y0 == 0.0);}cairo_bool_t_cairo_matrix_is_integer_translation(const cairo_matrix_t *m, int *itx, int *ity){ cairo_bool_t is_integer_translation; cairo_fixed_t x0_fixed, y0_fixed; x0_fixed = _cairo_fixed_from_double (m->x0); y0_fixed = _cairo_fixed_from_double (m->y0); is_integer_translation = ((m->xx == 1.0) && (m->yx == 0.0) && (m->xy == 0.0) && (m->yy == 1.0) && (_cairo_fixed_is_integer(x0_fixed)) && (_cairo_fixed_is_integer(y0_fixed))); if (! is_integer_translation) return FALSE; if (itx) *itx = _cairo_fixed_integer_part(x0_fixed); if (ity) *ity = _cairo_fixed_integer_part(y0_fixed); 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@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, f, g, h, i, j; _cairo_matrix_get_affine (matrix, &a, &b, &c, &d, NULL, NULL); i = a*a + b*b; j = c*c + d*d; f = 0.5 * (i + j); g = 0.5 * (i - j); 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)); */}void_cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, pixman_transform_t *pixman_transform){ pixman_transform->matrix[0][0] = _cairo_fixed_from_double (matrix->xx); pixman_transform->matrix[0][1] = _cairo_fixed_from_double (matrix->xy); pixman_transform->matrix[0][2] = _cairo_fixed_from_double (matrix->x0); pixman_transform->matrix[1][0] = _cairo_fixed_from_double (matrix->yx); pixman_transform->matrix[1][1] = _cairo_fixed_from_double (matrix->yy); pixman_transform->matrix[1][2] = _cairo_fixed_from_double (matrix->y0); pixman_transform->matrix[2][0] = 0; pixman_transform->matrix[2][1] = 0; pixman_transform->matrix[2][2] = _cairo_fixed_from_double (1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -