ReactOS  0.4.14-dev-55-g2da92ac
matrix.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007 Google (Evan Stade)
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #include <stdarg.h>
20 #include <math.h>
21 
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wingdi.h"
25 
26 #include "objbase.h"
27 
28 #include "gdiplus.h"
29 #include "gdiplus_private.h"
30 #include "wine/debug.h"
31 
33 
34 /* Multiplies two matrices of the form
35  *
36  * idx:0 idx:1 0
37  * idx:2 idx:3 0
38  * idx:4 idx:5 1
39  *
40  * and puts the output in out.
41  * */
43 {
44  REAL temp[6];
45  int i, odd;
46 
47  for(i = 0; i < 6; i++){
48  odd = i % 2;
49  temp[i] = left[i - odd] * right[odd] + left[i - odd + 1] * right[odd + 2] +
50  (i >= 4 ? right[odd + 4] : 0.0);
51  }
52 
53  memcpy(out, temp, 6 * sizeof(REAL));
54 }
55 
57 {
58  return matrix->matrix[0]*matrix->matrix[3] - matrix->matrix[1]*matrix->matrix[2];
59 }
60 
63 {
64  TRACE("(%.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p)\n", m11, m12, m21, m22, dx, dy, matrix);
65 
66  if(!matrix)
67  return InvalidParameter;
68 
69  *matrix = heap_alloc_zero(sizeof(GpMatrix));
70  if(!*matrix) return OutOfMemory;
71 
72  /* first row */
73  (*matrix)->matrix[0] = m11;
74  (*matrix)->matrix[1] = m12;
75  /* second row */
76  (*matrix)->matrix[2] = m21;
77  (*matrix)->matrix[3] = m22;
78  /* third row */
79  (*matrix)->matrix[4] = dx;
80  (*matrix)->matrix[5] = dy;
81 
82  return Ok;
83 }
84 
87 {
88  REAL m11, m12, m21, m22, dx, dy;
89  TRACE("(%p, %p, %p)\n", rect, pt, matrix);
90 
91  if(!matrix || !pt)
92  return InvalidParameter;
93 
94  m11 = (pt[1].X - pt[0].X) / rect->Width;
95  m21 = (pt[2].X - pt[0].X) / rect->Height;
96  dx = pt[0].X - m11 * rect->X - m21 * rect->Y;
97  m12 = (pt[1].Y - pt[0].Y) / rect->Width;
98  m22 = (pt[2].Y - pt[0].Y) / rect->Height;
99  dy = pt[0].Y - m12 * rect->X - m22 * rect->Y;
100 
101  return GdipCreateMatrix2(m11, m12, m21, m22, dx, dy, matrix);
102 }
103 
105  GpMatrix **matrix)
106 {
107  GpRectF rectF;
108  GpPointF ptF[3];
109  int i;
110 
111  TRACE("(%p, %p, %p)\n", rect, pt, matrix);
112 
113  rectF.X = (REAL)rect->X;
114  rectF.Y = (REAL)rect->Y;
115  rectF.Width = (REAL)rect->Width;
116  rectF.Height = (REAL)rect->Height;
117 
118  for (i = 0; i < 3; i++) {
119  ptF[i].X = (REAL)pt[i].X;
120  ptF[i].Y = (REAL)pt[i].Y;
121  }
122  return GdipCreateMatrix3(&rectF, ptF, matrix);
123 }
124 
126 {
127  TRACE("(%p, %p)\n", matrix, clone);
128 
129  if(!matrix || !clone)
130  return InvalidParameter;
131 
132  *clone = heap_alloc_zero(sizeof(GpMatrix));
133  if(!*clone) return OutOfMemory;
134 
135  **clone = *matrix;
136 
137  return Ok;
138 }
139 
141 {
142  TRACE("(%p)\n", matrix);
143 
144  if(!matrix)
145  return InvalidParameter;
146 
147  *matrix = heap_alloc_zero(sizeof(GpMatrix));
148  if(!*matrix) return OutOfMemory;
149 
150  (*matrix)->matrix[0] = 1.0;
151  (*matrix)->matrix[1] = 0.0;
152  (*matrix)->matrix[2] = 0.0;
153  (*matrix)->matrix[3] = 1.0;
154  (*matrix)->matrix[4] = 0.0;
155  (*matrix)->matrix[5] = 0.0;
156 
157  return Ok;
158 }
159 
161 {
162  TRACE("(%p)\n", matrix);
163 
164  if(!matrix)
165  return InvalidParameter;
166 
167  heap_free(matrix);
168 
169  return Ok;
170 }
171 
173  REAL *out)
174 {
175  TRACE("(%p, %p)\n", matrix, out);
176 
177  if(!matrix || !out)
178  return InvalidParameter;
179 
180  memcpy(out, matrix->matrix, sizeof(matrix->matrix));
181 
182  return Ok;
183 }
184 
186 {
187  GpMatrix copy;
188  REAL det;
189  BOOL invertible;
190 
191  TRACE("(%p)\n", matrix);
192 
193  if(!matrix)
194  return InvalidParameter;
195 
196  GdipIsMatrixInvertible(matrix, &invertible);
197  if(!invertible)
198  return InvalidParameter;
199 
200  /* optimize inverting simple scaling and translation matrices */
201  if(matrix->matrix[1] == 0 && matrix->matrix[2] == 0)
202  {
203  matrix->matrix[4] = -matrix->matrix[4] / matrix->matrix[0];
204  matrix->matrix[5] = -matrix->matrix[5] / matrix->matrix[3];
205  matrix->matrix[0] = 1 / matrix->matrix[0];
206  matrix->matrix[3] = 1 / matrix->matrix[3];
207 
208  return Ok;
209  }
210 
211  det = matrix_det(matrix);
212 
213  copy = *matrix;
214  /* store result */
215  matrix->matrix[0] = copy.matrix[3] / det;
216  matrix->matrix[1] = -copy.matrix[1] / det;
217  matrix->matrix[2] = -copy.matrix[2] / det;
218  matrix->matrix[3] = copy.matrix[0] / det;
219  matrix->matrix[4] = (copy.matrix[2]*copy.matrix[5]-copy.matrix[3]*copy.matrix[4]) / det;
220  matrix->matrix[5] = -(copy.matrix[0]*copy.matrix[5]-copy.matrix[1]*copy.matrix[4]) / det;
221 
222  return Ok;
223 }
224 
226 {
227  TRACE("(%p, %p)\n", matrix, result);
228 
229  if(!matrix || !result)
230  return InvalidParameter;
231 
232  if(matrix->matrix[1] == 0 && matrix->matrix[2] == 0)
233  *result = matrix->matrix[0] != 0 && matrix->matrix[3] != 0;
234  else
235  *result = (fabs(matrix_det(matrix)) >= 1e-5);
236 
237  return Ok;
238 }
239 
242 {
243  TRACE("(%p, %p, %d)\n", matrix, matrix2, order);
244 
245  if(!matrix || !matrix2)
246  return InvalidParameter;
247 
248  if(order == MatrixOrderAppend)
249  matrix_multiply(matrix->matrix, matrix2->matrix, matrix->matrix);
250  else if (order == MatrixOrderPrepend)
251  matrix_multiply(matrix2->matrix, matrix->matrix, matrix->matrix);
252  else
253  return InvalidParameter;
254 
255  return Ok;
256 }
257 
260 {
261  REAL cos_theta, sin_theta, rotate[6];
262 
263  TRACE("(%p, %.2f, %d)\n", matrix, angle, order);
264 
265  if(!matrix)
266  return InvalidParameter;
267 
268  angle = deg2rad(angle);
269  cos_theta = cos(angle);
270  sin_theta = sin(angle);
271 
272  rotate[0] = cos_theta;
273  rotate[1] = sin_theta;
274  rotate[2] = -sin_theta;
275  rotate[3] = cos_theta;
276  rotate[4] = 0.0;
277  rotate[5] = 0.0;
278 
279  if(order == MatrixOrderAppend)
280  matrix_multiply(matrix->matrix, rotate, matrix->matrix);
281  else if (order == MatrixOrderPrepend)
282  matrix_multiply(rotate, matrix->matrix, matrix->matrix);
283  else
284  return InvalidParameter;
285 
286  return Ok;
287 }
288 
291 {
292  REAL scale[6];
293 
294  TRACE("(%p, %.2f, %.2f, %d)\n", matrix, scaleX, scaleY, order);
295 
296  if(!matrix)
297  return InvalidParameter;
298 
299  scale[0] = scaleX;
300  scale[1] = 0.0;
301  scale[2] = 0.0;
302  scale[3] = scaleY;
303  scale[4] = 0.0;
304  scale[5] = 0.0;
305 
306  if(order == MatrixOrderAppend)
307  matrix_multiply(matrix->matrix, scale, matrix->matrix);
308  else if (order == MatrixOrderPrepend)
309  matrix_multiply(scale, matrix->matrix, matrix->matrix);
310  else
311  return InvalidParameter;
312 
313  return Ok;
314 }
315 
317  REAL m21, REAL m22, REAL dx, REAL dy)
318 {
319  TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", matrix, m11, m12,
320  m21, m22, dx, dy);
321 
322  if(!matrix)
323  return InvalidParameter;
324 
325  matrix->matrix[0] = m11;
326  matrix->matrix[1] = m12;
327  matrix->matrix[2] = m21;
328  matrix->matrix[3] = m22;
329  matrix->matrix[4] = dx;
330  matrix->matrix[5] = dy;
331 
332  return Ok;
333 }
334 
337 {
338  REAL shear[6];
339 
340  TRACE("(%p, %.2f, %.2f, %d)\n", matrix, shearX, shearY, order);
341 
342  if(!matrix)
343  return InvalidParameter;
344 
345  /* prepare transformation matrix */
346  shear[0] = 1.0;
347  shear[1] = shearY;
348  shear[2] = shearX;
349  shear[3] = 1.0;
350  shear[4] = 0.0;
351  shear[5] = 0.0;
352 
353  if(order == MatrixOrderAppend)
354  matrix_multiply(matrix->matrix, shear, matrix->matrix);
355  else if (order == MatrixOrderPrepend)
356  matrix_multiply(shear, matrix->matrix, matrix->matrix);
357  else
358  return InvalidParameter;
359 
360  return Ok;
361 }
362 
364  INT count)
365 {
366  REAL x, y;
367  INT i;
368 
369  TRACE("(%p, %p, %d)\n", matrix, pts, count);
370 
371  if(!matrix || !pts || count <= 0)
372  return InvalidParameter;
373 
374  for(i = 0; i < count; i++)
375  {
376  x = pts[i].X;
377  y = pts[i].Y;
378 
379  pts[i].X = x * matrix->matrix[0] + y * matrix->matrix[2] + matrix->matrix[4];
380  pts[i].Y = x * matrix->matrix[1] + y * matrix->matrix[3] + matrix->matrix[5];
381  }
382 
383  return Ok;
384 }
385 
387 {
388  GpPointF *ptsF;
389  GpStatus ret;
390  INT i;
391 
392  TRACE("(%p, %p, %d)\n", matrix, pts, count);
393 
394  if(count <= 0)
395  return InvalidParameter;
396 
397  ptsF = heap_alloc_zero(sizeof(GpPointF) * count);
398  if(!ptsF)
399  return OutOfMemory;
400 
401  for(i = 0; i < count; i++){
402  ptsF[i].X = (REAL)pts[i].X;
403  ptsF[i].Y = (REAL)pts[i].Y;
404  }
405 
407 
408  if(ret == Ok)
409  for(i = 0; i < count; i++){
410  pts[i].X = gdip_round(ptsF[i].X);
411  pts[i].Y = gdip_round(ptsF[i].Y);
412  }
413  heap_free(ptsF);
414 
415  return ret;
416 }
417 
419  REAL offsetY, GpMatrixOrder order)
420 {
421  REAL translate[6];
422 
423  TRACE("(%p, %.2f, %.2f, %d)\n", matrix, offsetX, offsetY, order);
424 
425  if(!matrix)
426  return InvalidParameter;
427 
428  translate[0] = 1.0;
429  translate[1] = 0.0;
430  translate[2] = 0.0;
431  translate[3] = 1.0;
432  translate[4] = offsetX;
433  translate[5] = offsetY;
434 
435  if(order == MatrixOrderAppend)
436  matrix_multiply(matrix->matrix, translate, matrix->matrix);
437  else if (order == MatrixOrderPrepend)
438  matrix_multiply(translate, matrix->matrix, matrix->matrix);
439  else
440  return InvalidParameter;
441 
442  return Ok;
443 }
444 
446 {
447  REAL x, y;
448  INT i;
449 
450  TRACE("(%p, %p, %d)\n", matrix, pts, count);
451 
452  if(!matrix || !pts || count <= 0)
453  return InvalidParameter;
454 
455  for(i = 0; i < count; i++)
456  {
457  x = pts[i].X;
458  y = pts[i].Y;
459 
460  pts[i].X = x * matrix->matrix[0] + y * matrix->matrix[2];
461  pts[i].Y = x * matrix->matrix[1] + y * matrix->matrix[3];
462  }
463 
464  return Ok;
465 }
466 
468 {
469  GpPointF *ptsF;
470  GpStatus ret;
471  INT i;
472 
473  TRACE("(%p, %p, %d)\n", matrix, pts, count);
474 
475  if(count <= 0)
476  return InvalidParameter;
477 
478  ptsF = heap_alloc_zero(sizeof(GpPointF) * count);
479  if(!ptsF)
480  return OutOfMemory;
481 
482  for(i = 0; i < count; i++){
483  ptsF[i].X = (REAL)pts[i].X;
484  ptsF[i].Y = (REAL)pts[i].Y;
485  }
486 
488  /* store back */
489  if(ret == Ok)
490  for(i = 0; i < count; i++){
491  pts[i].X = gdip_round(ptsF[i].X);
492  pts[i].Y = gdip_round(ptsF[i].Y);
493  }
494  heap_free(ptsF);
495 
496  return ret;
497 }
498 
500  BOOL *result)
501 {
502  TRACE("(%p, %p, %p)\n", matrix, matrix2, result);
503 
504  if(!matrix || !matrix2 || !result)
505  return InvalidParameter;
506  /* based on single array member of GpMatrix */
507  *result = (memcmp(matrix->matrix, matrix2->matrix, sizeof(GpMatrix)) == 0);
508 
509  return Ok;
510 }
511 
513 {
514  static const GpMatrix identity =
515  {
516  { 1.0, 0.0,
517  0.0, 1.0,
518  0.0, 0.0 }
519  };
520 
521  TRACE("(%p, %p)\n", matrix, result);
522 
523  if(!matrix || !result)
524  return InvalidParameter;
525 
527 }
GpStatus WINGDIPAPI GdipVectorTransformMatrixPointsI(GpMatrix *matrix, GpPoint *pts, INT count)
Definition: matrix.c:467
GpStatus WINGDIPAPI GdipSetMatrixElements(GpMatrix *matrix, REAL m11, REAL m12, REAL m21, REAL m22, REAL dx, REAL dy)
Definition: matrix.c:316
GLuint GLdouble GLdouble GLint GLint order
Definition: glext.h:11194
GpStatus WINGDIPAPI GdipVectorTransformMatrixPoints(GpMatrix *matrix, GpPointF *pts, INT count)
Definition: matrix.c:445
GpStatus WINGDIPAPI GdipCreateMatrix2(REAL m11, REAL m12, REAL m21, REAL m22, REAL dx, REAL dy, GpMatrix **matrix)
Definition: matrix.c:61
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
#define Y(I)
#define pt(x, y)
Definition: drawing.c:79
GLuint GLenum matrix
Definition: glext.h:9407
GpStatus WINGDIPAPI GdipGetMatrixElements(GDIPCONST GpMatrix *matrix, REAL *out)
Definition: matrix.c:172
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLint dy
Definition: linetemp.h:97
WINE_DEFAULT_DEBUG_CHANNEL(gdiplus)
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:9032
GpStatus WINGDIPAPI GdipCreateMatrix3I(GDIPCONST GpRect *rect, GDIPCONST GpPoint *pt, GpMatrix **matrix)
Definition: matrix.c:104
GpStatus WINGDIPAPI GdipCreateMatrix(GpMatrix **matrix)
Definition: matrix.c:140
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
Definition: unary.h:11
GLfloat angle
Definition: glext.h:10853
static REAL deg2rad(REAL degrees)
#define GDIPCONST
Definition: gdiplusflat.h:24
int32_t INT
Definition: typedefs.h:56
& rect
Definition: startmenu.cpp:1413
GpStatus WINGDIPAPI GdipCreateMatrix3(GDIPCONST GpRectF *rect, GDIPCONST GpPointF *pt, GpMatrix **matrix)
Definition: matrix.c:85
GpStatus WINGDIPAPI GdipIsMatrixInvertible(GDIPCONST GpMatrix *matrix, BOOL *result)
Definition: matrix.c:225
static void matrix_multiply(GDIPCONST REAL *left, GDIPCONST REAL *right, REAL *out)
Definition: matrix.c:42
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GpStatus WINGDIPAPI GdipIsMatrixEqual(GDIPCONST GpMatrix *matrix, GDIPCONST GpMatrix *matrix2, BOOL *result)
Definition: matrix.c:499
unsigned int BOOL
Definition: ntddk_ex.h:94
#define e
Definition: ke_i.h:82
#define WINGDIPAPI
Definition: gdiplusflat.h:22
_STLP_DECLSPEC complex< float > _STLP_CALL cos(const complex< float > &)
GpStatus WINGDIPAPI GdipCloneMatrix(GpMatrix *matrix, GpMatrix **clone)
Definition: matrix.c:125
REAL Height
Definition: gdiplustypes.h:264
static INT gdip_round(REAL x)
MatrixOrder
Definition: gdiplusenums.h:185
#define m11
GpStatus WINGDIPAPI GdipTransformMatrixPointsI(GpMatrix *matrix, GpPoint *pts, INT count)
Definition: matrix.c:386
#define m21
#define TRACE(s)
Definition: solgame.cpp:4
static void translate(POINT *pt, UINT count, const XFORM *xform)
Definition: metafile.c:2586
_STLP_MOVE_TO_STD_NAMESPACE void rotate(_ForwardIter __first, _ForwardIter __middle, _ForwardIter __last)
Definition: _algo.c:519
REAL X
Definition: gdiplustypes.h:261
#define m22
static FILE * out
Definition: regtests2xml.c:44
REAL Y
Definition: gdiplustypes.h:249
GLint left
Definition: glext.h:7726
GpStatus WINGDIPAPI GdipRotateMatrix(GpMatrix *matrix, REAL angle, GpMatrixOrder order)
Definition: matrix.c:258
GLdouble GLdouble right
Definition: glext.h:10859
int ret
GpStatus WINGDIPAPI GdipDeleteMatrix(GpMatrix *matrix)
Definition: matrix.c:160
GpStatus WINGDIPAPI GdipScaleMatrix(GpMatrix *matrix, REAL scaleX, REAL scaleY, GpMatrixOrder order)
Definition: matrix.c:289
REAL X
Definition: gdiplustypes.h:248
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GpStatus WINGDIPAPI GdipTransformMatrixPoints(GpMatrix *matrix, GpPointF *pts, INT count)
Definition: matrix.c:363
Status
Definition: gdiplustypes.h:24
REAL Width
Definition: gdiplustypes.h:263
GpStatus WINGDIPAPI GdipShearMatrix(GpMatrix *matrix, REAL shearX, REAL shearY, GpMatrixOrder order)
Definition: matrix.c:335
_Check_return_ _CRT_JIT_INTRINSIC double __cdecl fabs(_In_ double x)
GpStatus WINGDIPAPI GdipInvertMatrix(GpMatrix *matrix)
Definition: matrix.c:185
GpStatus WINGDIPAPI GdipTranslateMatrix(GpMatrix *matrix, REAL offsetX, REAL offsetY, GpMatrixOrder order)
Definition: matrix.c:418
static calc_node_t temp
Definition: rpn_ieee.c:38
INT copy(TCHAR source[MAX_PATH], TCHAR dest[MAX_PATH], INT append, DWORD lpdwFlags, BOOL bTouch)
Definition: copy.c:51
#define m12
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLint dx
Definition: linetemp.h:97
_STLP_DECLSPEC complex< float > _STLP_CALL sin(const complex< float > &)
static REAL matrix_det(GDIPCONST GpMatrix *matrix)
Definition: matrix.c:56
float REAL
Definition: types.h:41
GpStatus WINGDIPAPI GdipIsMatrixIdentity(GDIPCONST GpMatrix *matrix, BOOL *result)
Definition: matrix.c:512
REAL Y
Definition: gdiplustypes.h:262
GLuint64EXT * result
Definition: glext.h:11304
#define odd(x)
Definition: bidi.c:51
static BOOL heap_free(void *mem)
Definition: appwiz.h:75
GpStatus WINGDIPAPI GdipMultiplyMatrix(GpMatrix *matrix, GDIPCONST GpMatrix *matrix2, GpMatrixOrder order)
Definition: matrix.c:240