1 /* GTS - Library for the manipulation of triangulated surfaces
2 * Copyright (C) 1999 Stéphane Popinet
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
25 * @a00: element [0][0].
26 * @a01: element [0][1].
27 * @a02: element [0][2].
28 * @a03: element [0][3].
29 * @a10: element [1][0].
30 * @a11: element [1][1].
31 * @a12: element [1][2].
32 * @a13: element [1][3].
33 * @a20: element [2][0].
34 * @a21: element [2][1].
35 * @a22: element [2][2].
36 * @a23: element [2][3].
37 * @a30: element [3][0].
38 * @a31: element [3][1].
39 * @a32: element [3][2].
40 * @a33: element [3][3].
42 * Allocates memory and initializes a new #GtsMatrix.
44 * Returns: a pointer to the newly created #GtsMatrix.
46 GtsMatrix
* gts_matrix_new (gdouble a00
, gdouble a01
, gdouble a02
, gdouble a03
,
47 gdouble a10
, gdouble a11
, gdouble a12
, gdouble a13
,
48 gdouble a20
, gdouble a21
, gdouble a22
, gdouble a23
,
49 gdouble a30
, gdouble a31
, gdouble a32
, gdouble a33
)
53 m
= g_malloc (4*sizeof (GtsVector4
));
55 m
[0][0] = a00
; m
[1][0] = a10
; m
[2][0] = a20
; m
[3][0] = a30
;
56 m
[0][1] = a01
; m
[1][1] = a11
; m
[2][1] = a21
; m
[3][1] = a31
;
57 m
[0][2] = a02
; m
[1][2] = a12
; m
[2][2] = a22
; m
[3][2] = a32
;
58 m
[0][3] = a03
; m
[1][3] = a13
; m
[2][3] = a23
; m
[3][3] = a33
;
66 * @a00: element [0][0].
67 * @a01: element [0][1].
68 * @a02: element [0][2].
69 * @a03: element [0][3].
70 * @a10: element [1][0].
71 * @a11: element [1][1].
72 * @a12: element [1][2].
73 * @a13: element [1][3].
74 * @a20: element [2][0].
75 * @a21: element [2][1].
76 * @a22: element [2][2].
77 * @a23: element [2][3].
78 * @a30: element [3][0].
79 * @a31: element [3][1].
80 * @a32: element [3][2].
81 * @a33: element [3][3].
83 * Set values of matrix elements.
85 void gts_matrix_assign (GtsMatrix
* m
,
86 gdouble a00
, gdouble a01
, gdouble a02
, gdouble a03
,
87 gdouble a10
, gdouble a11
, gdouble a12
, gdouble a13
,
88 gdouble a20
, gdouble a21
, gdouble a22
, gdouble a23
,
89 gdouble a30
, gdouble a31
, gdouble a32
, gdouble a33
)
91 g_return_if_fail (m
!= NULL
);
93 m
[0][0] = a00
; m
[1][0] = a10
; m
[2][0] = a20
; m
[3][0] = a30
;
94 m
[0][1] = a01
; m
[1][1] = a11
; m
[2][1] = a21
; m
[3][1] = a31
;
95 m
[0][2] = a02
; m
[1][2] = a12
; m
[2][2] = a22
; m
[3][2] = a32
;
96 m
[0][3] = a03
; m
[1][3] = a13
; m
[2][3] = a23
; m
[3][3] = a33
;
100 * gts_matrix_projection:
101 * @t: a #GtsTriangle.
103 * Creates a new #GtsMatrix representing the projection onto a plane of normal
106 * Returns: a pointer to the newly created #GtsMatrix.
108 GtsMatrix
* gts_matrix_projection (GtsTriangle
* t
)
110 GtsVertex
* v1
, * v2
, * v3
;
111 GtsEdge
* e1
, * e2
, * e3
;
113 gdouble x1
, y1
, z1
, x2
, y2
, z2
, x3
, y3
, z3
, l
;
115 g_return_val_if_fail (t
!= NULL
, NULL
);
117 m
= g_malloc (4*sizeof (GtsVector4
));
118 gts_triangle_vertices_edges (t
, NULL
, &v1
, &v2
, &v3
, &e1
, &e2
, &e3
);
120 x1
= GTS_POINT (v2
)->x
- GTS_POINT (v1
)->x
;
121 y1
= GTS_POINT (v2
)->y
- GTS_POINT (v1
)->y
;
122 z1
= GTS_POINT (v2
)->z
- GTS_POINT (v1
)->z
;
123 x2
= GTS_POINT (v3
)->x
- GTS_POINT (v1
)->x
;
124 y2
= GTS_POINT (v3
)->y
- GTS_POINT (v1
)->y
;
125 z2
= GTS_POINT (v3
)->z
- GTS_POINT (v1
)->z
;
126 x3
= y1
*z2
- z1
*y2
; y3
= z1
*x2
- x1
*z2
; z3
= x1
*y2
- y1
*x2
;
127 x2
= y3
*z1
- z3
*y1
; y2
= z3
*x1
- x3
*z1
; z2
= x3
*y1
- y3
*x1
;
129 g_assert ((l
= sqrt (x1
*x1
+ y1
*y1
+ z1
*z1
)) > 0.0);
130 m
[0][0] = x1
/l
; m
[1][0] = y1
/l
; m
[2][0] = z1
/l
; m
[3][0] = 0.;
131 g_assert ((l
= sqrt (x2
*x2
+ y2
*y2
+ z2
*z2
)) > 0.0);
132 m
[0][1] = x2
/l
; m
[1][1] = y2
/l
; m
[2][1] = z2
/l
; m
[3][1] = 0.;
133 g_assert ((l
= sqrt (x3
*x3
+ y3
*y3
+ z3
*z3
)) > 0.0);
134 m
[0][2] = x3
/l
; m
[1][2] = y3
/l
; m
[2][2] = z3
/l
; m
[3][2] = 0.;
135 m
[0][3] = 0; m
[1][3] = 0.; m
[2][3] = 0.; m
[3][3] = 1.;
141 * gts_matrix_transpose:
144 * Returns: a pointer to a newly created #GtsMatrix transposed of @m.
146 GtsMatrix
* gts_matrix_transpose (GtsMatrix
* m
)
150 g_return_val_if_fail (m
!= NULL
, NULL
);
152 mi
= g_malloc (4*sizeof (GtsVector4
));
154 mi
[0][0] = m
[0][0]; mi
[1][0] = m
[0][1];
155 mi
[2][0] = m
[0][2]; mi
[3][0] = m
[0][3];
156 mi
[0][1] = m
[1][0]; mi
[1][1] = m
[1][1];
157 mi
[2][1] = m
[1][2]; mi
[3][1] = m
[1][3];
158 mi
[0][2] = m
[2][0]; mi
[1][2] = m
[2][1];
159 mi
[2][2] = m
[2][2]; mi
[3][2] = m
[2][3];
160 mi
[0][3] = m
[3][0]; mi
[1][3] = m
[3][1];
161 mi
[2][3] = m
[3][2]; mi
[3][3] = m
[3][3];
167 * calculate the determinant of a 2x2 matrix.
172 * from "Graphics Gems", Academic Press, 1990
174 static gdouble
det2x2 (gdouble a
, gdouble b
, gdouble c
, gdouble d
)
183 * calculate the determinant of a 3x3 matrix
193 * from "Graphics Gems", Academic Press, 1990
195 static gdouble
det3x3 (gdouble a1
, gdouble a2
, gdouble a3
,
196 gdouble b1
, gdouble b2
, gdouble b3
,
197 gdouble c1
, gdouble c2
, gdouble c3
)
201 ans3
= a1
* det2x2( b2
, b3
, c2
, c3
)
202 - b1
* det2x2( a2
, a3
, c2
, c3
)
203 + c1
* det2x2( a2
, a3
, b2
, b3
);
208 * gts_matrix_determinant:
211 * Returns: the value of det(@m).
213 gdouble
gts_matrix_determinant (GtsMatrix
* m
)
216 gdouble a1
, a2
, a3
, a4
, b1
, b2
, b3
, b4
, c1
, c2
, c3
, c4
, d1
, d2
, d3
, d4
;
218 g_return_val_if_fail (m
!= NULL
, 0.0);
220 a1
= m
[0][0]; b1
= m
[0][1];
221 c1
= m
[0][2]; d1
= m
[0][3];
223 a2
= m
[1][0]; b2
= m
[1][1];
224 c2
= m
[1][2]; d2
= m
[1][3];
226 a3
= m
[2][0]; b3
= m
[2][1];
227 c3
= m
[2][2]; d3
= m
[2][3];
229 a4
= m
[3][0]; b4
= m
[3][1];
230 c4
= m
[3][2]; d4
= m
[3][3];
232 ans4
= a1
* det3x3 (b2
, b3
, b4
, c2
, c3
, c4
, d2
, d3
, d4
)
233 - b1
* det3x3 (a2
, a3
, a4
, c2
, c3
, c4
, d2
, d3
, d4
)
234 + c1
* det3x3 (a2
, a3
, a4
, b2
, b3
, b4
, d2
, d3
, d4
)
235 - d1
* det3x3 (a2
, a3
, a4
, b2
, b3
, b4
, c2
, c3
, c4
);
241 * adjoint( original_matrix, inverse_matrix )
243 * calculate the adjoint of a 4x4 matrix
245 * Let a denote the minor determinant of matrix A obtained by
248 * deleting the ith row and jth column from A.
254 * The matrix B = (b ) is the adjoint of A
257 static GtsMatrix
* adjoint (GtsMatrix
* m
)
259 gdouble a1
, a2
, a3
, a4
, b1
, b2
, b3
, b4
;
260 gdouble c1
, c2
, c3
, c4
, d1
, d2
, d3
, d4
;
263 a1
= m
[0][0]; b1
= m
[0][1];
264 c1
= m
[0][2]; d1
= m
[0][3];
266 a2
= m
[1][0]; b2
= m
[1][1];
267 c2
= m
[1][2]; d2
= m
[1][3];
269 a3
= m
[2][0]; b3
= m
[2][1];
270 c3
= m
[2][2]; d3
= m
[2][3];
272 a4
= m
[3][0]; b4
= m
[3][1];
273 c4
= m
[3][2]; d4
= m
[3][3];
275 ma
= g_malloc (4*sizeof (GtsVector4
));
277 /* row column labeling reversed since we transpose rows & columns */
279 ma
[0][0] = det3x3 (b2
, b3
, b4
, c2
, c3
, c4
, d2
, d3
, d4
);
280 ma
[1][0] = - det3x3 (a2
, a3
, a4
, c2
, c3
, c4
, d2
, d3
, d4
);
281 ma
[2][0] = det3x3 (a2
, a3
, a4
, b2
, b3
, b4
, d2
, d3
, d4
);
282 ma
[3][0] = - det3x3 (a2
, a3
, a4
, b2
, b3
, b4
, c2
, c3
, c4
);
284 ma
[0][1] = - det3x3 (b1
, b3
, b4
, c1
, c3
, c4
, d1
, d3
, d4
);
285 ma
[1][1] = det3x3 (a1
, a3
, a4
, c1
, c3
, c4
, d1
, d3
, d4
);
286 ma
[2][1] = - det3x3 (a1
, a3
, a4
, b1
, b3
, b4
, d1
, d3
, d4
);
287 ma
[3][1] = det3x3 (a1
, a3
, a4
, b1
, b3
, b4
, c1
, c3
, c4
);
289 ma
[0][2] = det3x3 (b1
, b2
, b4
, c1
, c2
, c4
, d1
, d2
, d4
);
290 ma
[1][2] = - det3x3 (a1
, a2
, a4
, c1
, c2
, c4
, d1
, d2
, d4
);
291 ma
[2][2] = det3x3 (a1
, a2
, a4
, b1
, b2
, b4
, d1
, d2
, d4
);
292 ma
[3][2] = - det3x3 (a1
, a2
, a4
, b1
, b2
, b4
, c1
, c2
, c4
);
294 ma
[0][3] = - det3x3 (b1
, b2
, b3
, c1
, c2
, c3
, d1
, d2
, d3
);
295 ma
[1][3] = det3x3 (a1
, a2
, a3
, c1
, c2
, c3
, d1
, d2
, d3
);
296 ma
[2][3] = - det3x3 (a1
, a2
, a3
, b1
, b2
, b3
, d1
, d2
, d3
);
297 ma
[3][3] = det3x3 (a1
, a2
, a3
, b1
, b2
, b3
, c1
, c2
, c3
);
304 * gts_matrix_inverse:
307 * Returns: a pointer to a newly created #GtsMatrix inverse of @m or %NULL
308 * if @m is not invertible.
310 GtsMatrix
* gts_matrix_inverse (GtsMatrix
* m
)
316 g_return_val_if_fail (m
!= NULL
, NULL
);
318 det
= gts_matrix_determinant (m
);
323 for (i
= 0; i
< 4; i
++)
324 for(j
= 0; j
< 4; j
++)
331 * gts_matrix3_inverse:
332 * @m: a 3x3 #GtsMatrix.
334 * Returns: a pointer to a newly created 3x3 #GtsMatrix inverse of @m or %NULL
335 * if @m is not invertible.
337 GtsMatrix
* gts_matrix3_inverse (GtsMatrix
* m
)
342 g_return_val_if_fail (m
!= NULL
, NULL
);
344 det
= (m
[0][0]*(m
[1][1]*m
[2][2] - m
[2][1]*m
[1][2]) -
345 m
[0][1]*(m
[1][0]*m
[2][2] - m
[2][0]*m
[1][2]) +
346 m
[0][2]*(m
[1][0]*m
[2][1] - m
[2][0]*m
[1][1]));
350 mi
= g_malloc0 (4*sizeof (GtsVector
));
352 mi
[0][0] = (m
[1][1]*m
[2][2] - m
[1][2]*m
[2][1])/det
;
353 mi
[0][1] = (m
[2][1]*m
[0][2] - m
[0][1]*m
[2][2])/det
;
354 mi
[0][2] = (m
[0][1]*m
[1][2] - m
[1][1]*m
[0][2])/det
;
355 mi
[1][0] = (m
[1][2]*m
[2][0] - m
[1][0]*m
[2][2])/det
;
356 mi
[1][1] = (m
[0][0]*m
[2][2] - m
[2][0]*m
[0][2])/det
;
357 mi
[1][2] = (m
[1][0]*m
[0][2] - m
[0][0]*m
[1][2])/det
;
358 mi
[2][0] = (m
[1][0]*m
[2][1] - m
[2][0]*m
[1][1])/det
;
359 mi
[2][1] = (m
[2][0]*m
[0][1] - m
[0][0]*m
[2][1])/det
;
360 mi
[2][2] = (m
[0][0]*m
[1][1] - m
[0][1]*m
[1][0])/det
;
368 * @fptr: a file descriptor.
370 * Print @m to file @fptr.
372 void gts_matrix_print (GtsMatrix
* m
, FILE * fptr
)
374 g_return_if_fail (m
!= NULL
);
375 g_return_if_fail (fptr
!= NULL
);
378 "[[%15.7g %15.7g %15.7g %15.7g]\n"
379 " [%15.7g %15.7g %15.7g %15.7g]\n"
380 " [%15.7g %15.7g %15.7g %15.7g]\n"
381 " [%15.7g %15.7g %15.7g %15.7g]]\n",
382 m
[0][0], m
[0][1], m
[0][2], m
[0][3],
383 m
[1][0], m
[1][1], m
[1][2], m
[1][3],
384 m
[2][0], m
[2][1], m
[2][2], m
[2][3],
385 m
[3][0], m
[3][1], m
[3][2], m
[3][3]);
391 * @fptr: a file descriptor.
393 * Print @s to file @fptr.
395 void gts_vector_print (GtsVector v
, FILE * fptr
)
397 g_return_if_fail (fptr
!= NULL
);
400 "[%15.7g %15.7g %15.7g ]\n",
407 * @fptr: a file descriptor.
409 * Print @v to file @fptr.
411 void gts_vector4_print (GtsVector4 v
, FILE * fptr
)
413 g_return_if_fail (fptr
!= NULL
);
416 "[%15.7g %15.7g %15.7g %15.7g]\n",
417 v
[0], v
[1], v
[2], v
[3]);
421 #define COSALPHA2 0.999695413509 /* alpha = 1 degree */
423 #define SINALPHA2 3.04586490453e-4 /* alpha = 1 degree */
426 * gts_matrix_compatible_row:
429 * @n: the number of previous constraints of @A.x=@b.
433 * Given a system of @n constraints @A.x=@b adds to it the compatible
434 * constraints defined by @A1.x=@b1. The compatibility is determined
435 * by insuring that the resulting system is well-conditioned (see
436 * Lindstrom and Turk (1998, 1999)).
438 * Returns: the number of constraints of the resulting system.
440 guint
gts_matrix_compatible_row (GtsMatrix
* A
,
448 g_return_val_if_fail (A
!= NULL
, 0);
450 na1
= gts_vector_scalar (A1
, A1
);
456 A1
[0] /= na1
; A1
[1] /= na1
; A1
[2] /= na1
; b1
/= na1
;
459 gdouble a0a1
= gts_vector_scalar (A
[0], A1
);
460 if (a0a1
*a0a1
>= COSALPHA2
)
467 gts_vector_cross (V
, A
[0], A
[1]);
468 s
= gts_vector_scalar (V
, A1
);
469 if (s
*s
<= gts_vector_scalar (V
, V
)*SINALPHA2
)
473 A
[n
][0] = A1
[0]; A
[n
][1] = A1
[1]; A
[n
][2] = A1
[2]; b
[n
] = b1
;
478 * gts_matrix_quadratic_optimization:
481 * @n: the number of constraints (must be smaller than 3).
482 * @H: a symmetric positive definite Hessian.
485 * Solve a quadratic optimization problem: Given a quadratic objective function
486 * f which can be written as: f(x) = x^t.@H.x + @c^t.x + k, where @H is the
487 * symmetric positive definite Hessian of f and k is a constant, find the
488 * minimum of f subject to the set of @n prior linear constraints, defined by
489 * the first @n rows of @A and @b (@A.x = @b). The new constraints given by
490 * the minimization are added to @A and @b only if they are linearly
491 * independent as determined by gts_matrix_compatible_row().
493 * Returns: the new number of constraints defined by @A and @b.
495 guint
gts_matrix_quadratic_optimization (GtsMatrix
* A
,
501 g_return_val_if_fail (A
!= NULL
, 0);
502 g_return_val_if_fail (b
!= NULL
, 0);
503 g_return_val_if_fail (n
< 3, 0);
504 g_return_val_if_fail (H
!= NULL
, 0);
508 n
= gts_matrix_compatible_row (A
, b
, n
, H
[0], - c
[0]);
509 n
= gts_matrix_compatible_row (A
, b
, n
, H
[1], - c
[1]);
510 n
= gts_matrix_compatible_row (A
, b
, n
, H
[2], - c
[2]);
514 GtsVector Q0
= {0., 0., 0.};
515 GtsVector Q1
= {0., 0., 0.};
517 gdouble max
= A
[0][0]*A
[0][0];
520 /* build a vector orthogonal to the constraint */
521 if (A
[0][1]*A
[0][1] > max
) { max
= A
[0][1]*A
[0][1]; d
= 1; }
522 if (A
[0][2]*A
[0][2] > max
) { max
= A
[0][2]*A
[0][2]; d
= 2; }
524 case 0: Q0
[0] = - A
[0][2]/A
[0][0]; Q0
[2] = 1.0; break;
525 case 1: Q0
[1] = - A
[0][2]/A
[0][1]; Q0
[2] = 1.0; break;
526 case 2: Q0
[2] = - A
[0][0]/A
[0][2]; Q0
[0] = 1.0; break;
529 /* build a second vector orthogonal to the first and to the constraint */
530 gts_vector_cross (Q1
, A
[0], Q0
);
532 A1
[0] = gts_vector_scalar (Q0
, H
[0]);
533 A1
[1] = gts_vector_scalar (Q0
, H
[1]);
534 A1
[2] = gts_vector_scalar (Q0
, H
[2]);
536 n
= gts_matrix_compatible_row (A
, b
, n
, A1
, - gts_vector_scalar (Q0
, c
));
538 A1
[0] = gts_vector_scalar (Q1
, H
[0]);
539 A1
[1] = gts_vector_scalar (Q1
, H
[1]);
540 A1
[2] = gts_vector_scalar (Q1
, H
[2]);
542 n
= gts_matrix_compatible_row (A
, b
, n
, A1
, - gts_vector_scalar (Q1
, c
));
547 /* build a vector orthogonal to the two constraints */
550 gts_vector_cross (Q
, A
[0], A
[1]);
551 A1
[0] = gts_vector_scalar (Q
, H
[0]);
552 A1
[1] = gts_vector_scalar (Q
, H
[1]);
553 A1
[2] = gts_vector_scalar (Q
, H
[2]);
555 n
= gts_matrix_compatible_row (A
, b
, n
, A1
, - gts_vector_scalar (Q
, c
));
560 g_assert_not_reached ();
566 * gts_matrix_destroy:
569 * Free all the memory allocated for @m.
571 void gts_matrix_destroy (GtsMatrix
* m
)
577 * gts_matrix_product:
579 * @m2: another #GtsMatrix.
581 * Returns: a new #GtsMatrix, product of @m1 and @m2.
583 GtsMatrix
* gts_matrix_product (GtsMatrix
* m1
, GtsMatrix
* m2
)
588 g_return_val_if_fail (m1
!= NULL
, NULL
);
589 g_return_val_if_fail (m2
!= NULL
, NULL
);
590 g_return_val_if_fail (m1
!= m2
, NULL
);
592 m
= g_malloc (4*sizeof (GtsVector4
));
594 for (i
= 0; i
< 4; i
++)
595 for (j
= 0; j
< 4; j
++)
596 m
[i
][j
] = m1
[i
][0]*m2
[0][j
] + m1
[i
][1]*m2
[1][j
] +
597 m1
[i
][2]*m2
[2][j
] + m1
[i
][3]*m2
[3][j
];
603 * @m: a #GtsMatrix or $NULL.
605 * Initializes @m to zeros. Allocates a matrix if @m is %NULL.
607 * Returns: the zero'ed matrix.
609 GtsMatrix
* gts_matrix_zero (GtsMatrix
* m
)
612 m
= g_malloc0 (4*sizeof (GtsVector4
));
614 m
[0][0] = m
[1][0] = m
[2][0] = m
[3][0] = 0.;
615 m
[0][1] = m
[1][1] = m
[2][1] = m
[3][1] = 0.;
616 m
[0][2] = m
[1][2] = m
[2][2] = m
[3][2] = 0.;
617 m
[0][3] = m
[1][3] = m
[2][3] = m
[3][3] = 0.;
623 * gts_matrix_identity:
624 * @m: a #GtsMatrix or %NULL.
626 * Initializes @m to an identity matrix. Allocates a matrix if @m is %NULL.
628 * Returns: the identity matrix.
630 GtsMatrix
* gts_matrix_identity (GtsMatrix
* m
)
632 m
= gts_matrix_zero (m
);
633 m
[0][0] = m
[1][1] = m
[2][2] = m
[3][3] = 1.;
639 * @m: a #GtsMatrix or %NULL.
640 * @s: the scaling vector.
642 * Initializes @m to a scaling matrix for @s. Allocates a matrix if @m
645 * Returns: the scaling matrix.
647 GtsMatrix
* gts_matrix_scale (GtsMatrix
* m
, GtsVector s
)
649 m
= gts_matrix_zero (m
);
658 * gts_matrix_translate:
659 * @m: a #GtsMatrix or %NULL.
660 * @t: the translation vector.
662 * Initializes @m to a translation matrix for @t. Allocates a new
663 * matrix if @m is %NULL.
665 * Returns: the translation matix.
667 GtsMatrix
* gts_matrix_translate (GtsMatrix
* m
, GtsVector t
)
669 m
= gts_matrix_zero (m
);
674 m
[0][0] = m
[1][1] = m
[2][2] = 1.;
680 * @m: a #GtsMatrix or %NULL.
681 * @r: the rotation axis.
682 * @angle: the angle (in radians) to rotate by.
684 * Initializes @m to a rotation matrix around @r by @angle.
685 * Allocates a new matrix if @m is %NULL.
687 * Returns: the rotation matrix.
689 GtsMatrix
* gts_matrix_rotate (GtsMatrix
* m
,
695 gts_vector_normalize (r
);
702 m
= g_malloc (4*sizeof (GtsVector4
));
704 m
[0][0] = r
[0]*r
[0]*c1
+ c
;
705 m
[0][1] = r
[0]*r
[1]*c1
- r
[2]*s
;
706 m
[0][2] = r
[0]*r
[2]*c1
+ r
[1]*s
;
709 m
[1][0] = r
[1]*r
[0]*c1
+ r
[2]*s
;
710 m
[1][1] = r
[1]*r
[1]*c1
+ c
;
711 m
[1][2] = r
[1]*r
[2]*c1
- r
[0]*s
;
714 m
[2][0] = r
[2]*r
[0]*c1
- r
[1]*s
;
715 m
[2][1] = r
[2]*r
[1]*c1
+ r
[0]*s
;
716 m
[2][2] = r
[2]*r
[2]*c1
+ c
;