]> git.saurik.com Git - wxWidgets.git/blob - src/common/matrix.cpp
More BLOB fixes
[wxWidgets.git] / src / common / matrix.cpp
1 // Name: matrix.cpp
2 // Purpose: wxTransformMatrix class
3 // Author: Chris Breeze, Julian Smart
4 // Modified by: Klaas Holwerda
5 // Created: 01/02/97
6 // RCS-ID: $Id$
7 // Copyright: (c) Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
12 #pragma implementation "matrix.h"
13 #endif
14
15 // Note: this is intended to be used in wxDC at some point to replace
16 // the current system of scaling/translation. It is not yet used.
17
18 // For compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
20
21 #ifdef __BORLANDC__
22 #pragma hdrstop
23 #endif
24
25 #ifndef WX_PRECOMP
26 #include "wx/defs.h"
27 #endif
28
29 #include "wx/matrix.h"
30 #include <math.h>
31
32 static const double pi = 3.1415926535;
33
34 wxTransformMatrix::wxTransformMatrix(void)
35 {
36 m_isIdentity = FALSE;
37
38 Identity();
39 }
40
41 wxTransformMatrix::wxTransformMatrix(const wxTransformMatrix& mat)
42 : wxObject()
43 {
44 (*this) = mat;
45 }
46
47 double wxTransformMatrix::GetValue(int col, int row) const
48 {
49 if (row < 0 || row > 2 || col < 0 || col > 2)
50 return 0.0;
51
52 return m_matrix[col][row];
53 }
54
55 void wxTransformMatrix::SetValue(int col, int row, double value)
56 {
57 if (row < 0 || row > 2 || col < 0 || col > 2)
58 return;
59
60 m_matrix[col][row] = value;
61 m_isIdentity = IsIdentity1();
62 }
63
64 void wxTransformMatrix::operator = (const wxTransformMatrix& mat)
65 {
66 int i, j;
67 for (i = 0; i < 3; i++)
68 {
69 for (j = 0; j < 3; j++)
70 {
71 m_matrix[i][j] = mat.m_matrix[i][j];
72 }
73 }
74 m_isIdentity = mat.m_isIdentity;
75 }
76
77 bool wxTransformMatrix::operator == (const wxTransformMatrix& mat)
78 {
79 if (m_isIdentity==TRUE && mat.m_isIdentity==TRUE)
80 return TRUE;
81
82 int i, j;
83 for (i = 0; i < 3; i++)
84 {
85 for (j = 0; j < 3; j++)
86 {
87 if (m_matrix[i][j] != mat.m_matrix[i][j])
88 return FALSE;
89 }
90 }
91 return TRUE;
92 }
93
94 bool wxTransformMatrix::operator != (const wxTransformMatrix& mat)
95 {
96 return (! ((*this) == mat));
97 }
98
99 double& wxTransformMatrix::operator()(int col, int row)
100 {
101 if (row < 0 || row > 2 || col < 0 || col > 2)
102 return m_matrix[0][0];
103
104 return m_matrix[col][row];
105 }
106
107 double wxTransformMatrix::operator()(int col, int row) const
108 {
109 if (row < 0 || row > 2 || col < 0 || col > 2)
110 return 0.0;
111
112 return m_matrix[col][row];
113 }
114
115 // Invert matrix
116 bool wxTransformMatrix::Invert(void)
117 {
118 double inverseMatrix[3][3];
119
120 // calculate the adjoint
121 inverseMatrix[0][0] = wxCalculateDet(m_matrix[1][1],m_matrix[2][1],m_matrix[1][2],m_matrix[2][2]);
122 inverseMatrix[0][1] = -wxCalculateDet(m_matrix[0][1],m_matrix[2][1],m_matrix[0][2],m_matrix[2][2]);
123 inverseMatrix[0][2] = wxCalculateDet(m_matrix[0][1],m_matrix[1][1],m_matrix[0][2],m_matrix[1][2]);
124
125 inverseMatrix[1][0] = -wxCalculateDet(m_matrix[1][0],m_matrix[2][0],m_matrix[1][2],m_matrix[2][2]);
126 inverseMatrix[1][1] = wxCalculateDet(m_matrix[0][0],m_matrix[2][0],m_matrix[0][2],m_matrix[2][2]);
127 inverseMatrix[1][2] = -wxCalculateDet(m_matrix[0][0],m_matrix[1][0],m_matrix[0][2],m_matrix[1][2]);
128
129 inverseMatrix[2][0] = wxCalculateDet(m_matrix[1][0],m_matrix[2][0],m_matrix[1][1],m_matrix[2][1]);
130 inverseMatrix[2][1] = -wxCalculateDet(m_matrix[0][0],m_matrix[2][0],m_matrix[0][1],m_matrix[2][1]);
131 inverseMatrix[2][2] = wxCalculateDet(m_matrix[0][0],m_matrix[1][0],m_matrix[0][1],m_matrix[1][1]);
132
133 // now divide by the determinant
134 double det = m_matrix[0][0] * inverseMatrix[0][0] + m_matrix[0][1] * inverseMatrix[1][0] + m_matrix[0][2] * inverseMatrix[2][0];
135 if (det != 0.0)
136 {
137 inverseMatrix[0][0] /= det; inverseMatrix[1][0] /= det; inverseMatrix[2][0] /= det;
138 inverseMatrix[0][1] /= det; inverseMatrix[1][1] /= det; inverseMatrix[2][1] /= det;
139 inverseMatrix[0][2] /= det; inverseMatrix[1][2] /= det; inverseMatrix[2][2] /= det;
140
141 int i, j;
142 for (i = 0; i < 3; i++)
143 {
144 for (j = 0; j < 3; j++)
145 {
146 m_matrix[i][j] = inverseMatrix[i][j];
147 }
148 }
149 m_isIdentity = IsIdentity1();
150 return TRUE;
151 }
152 else
153 {
154 return FALSE;
155 }
156 }
157
158 // Make into identity matrix
159 bool wxTransformMatrix::Identity(void)
160 {
161 m_matrix[0][0] = m_matrix[1][1] = m_matrix[2][2] = 1.0;
162 m_matrix[1][0] = m_matrix[2][0] = m_matrix[0][1] = m_matrix[2][1] = m_matrix[0][2] = m_matrix[1][2] = 0.0;
163 m_isIdentity = TRUE;
164
165 return TRUE;
166 }
167
168 // Scale by scale (isotropic scaling i.e. the same in x and y):
169 // | scale 0 0 |
170 // matrix' = | 0 scale 0 | x matrix
171 // | 0 0 scale |
172 //
173 bool wxTransformMatrix::Scale(double scale)
174 {
175 int i, j;
176 for (i = 0; i < 3; i++)
177 {
178 for (j = 0; j < 3; j++)
179 {
180 m_matrix[i][j] *= scale;
181 }
182 }
183 m_isIdentity = IsIdentity1();
184
185 return TRUE;
186 }
187
188
189 // scale a matrix in 2D
190 //
191 // xs 0 xc(1-xs)
192 // 0 ys yc(1-ys)
193 // 0 0 1
194 //
195 wxTransformMatrix& wxTransformMatrix::Scale(const double &xs, const double &ys,const double &xc, const double &yc)
196 {
197 double r00,r10,r20,r01,r11,r21;
198
199 if (m_isIdentity)
200 {
201 double tx =xc*(1-xs);
202 double ty =yc*(1-ys);
203 r00 = xs;
204 r10 = 0;
205 r20 = tx;
206 r01 = 0;
207 r11 = ys;
208 r21 = ty;
209 }
210 else if (xc!=0 || yc!=0)
211 {
212 double tx =xc*(1-xs);
213 double ty =yc*(1-ys);
214 r00 = xs * m_matrix[0][0];
215 r10 = xs * m_matrix[1][0];
216 r20 = xs * m_matrix[2][0] + tx;
217 r01 = ys * m_matrix[0][1];
218 r11 = ys * m_matrix[1][1];
219 r21 = ys * m_matrix[2][1] + ty;
220 }
221 else
222 {
223 r00 = xs * m_matrix[0][0];
224 r10 = xs * m_matrix[1][0];
225 r20 = xs * m_matrix[2][0];
226 r01 = ys * m_matrix[0][1];
227 r11 = ys * m_matrix[1][1];
228 r21 = ys * m_matrix[2][1];
229 }
230
231 m_matrix[0][0] = r00;
232 m_matrix[1][0] = r10;
233 m_matrix[2][0] = r20;
234 m_matrix[0][1] = r01;
235 m_matrix[1][1] = r11;
236 m_matrix[2][1] = r21;
237
238 /* or like this
239 // first translate to origin O
240 (*this).Translate(-x_cen, -y_cen);
241
242 // now do the scaling
243 wxTransformMatrix scale;
244 scale.m_matrix[0][0] = x_fac;
245 scale.m_matrix[1][1] = y_fac;
246 scale.m_isIdentity = IsIdentity1();
247
248 *this = scale * (*this);
249
250 // translate back from origin to x_cen, y_cen
251 (*this).Translate(x_cen, y_cen);
252 */
253
254 m_isIdentity = IsIdentity1();
255
256 return *this;
257 }
258
259
260 // mirror a matrix in x, y
261 //
262 // -1 0 0 Y-mirror
263 // 0 -1 0 X-mirror
264 // 0 0 -1 Z-mirror
265 wxTransformMatrix& wxTransformMatrix::Mirror(bool x, bool y)
266 {
267 wxTransformMatrix temp;
268 if (x)
269 {
270 temp.m_matrix[1][1] = -1;
271 temp.m_isIdentity=FALSE;
272 }
273 if (y)
274 {
275 temp.m_matrix[0][0] = -1;
276 temp.m_isIdentity=FALSE;
277 }
278
279 *this = temp * (*this);
280 m_isIdentity = IsIdentity1();
281 return *this;
282 }
283
284 // Translate by dx, dy:
285 // | 1 0 dx |
286 // matrix' = | 0 1 dy | x matrix
287 // | 0 0 1 |
288 //
289 bool wxTransformMatrix::Translate(double dx, double dy)
290 {
291 int i;
292 for (i = 0; i < 3; i++)
293 m_matrix[i][0] += dx * m_matrix[i][2];
294 for (i = 0; i < 3; i++)
295 m_matrix[i][1] += dy * m_matrix[i][2];
296
297 m_isIdentity = IsIdentity1();
298
299 return TRUE;
300 }
301
302 // Rotate clockwise by the given number of degrees:
303 // | cos sin 0 |
304 // matrix' = | -sin cos 0 | x matrix
305 // | 0 0 1 |
306 bool wxTransformMatrix::Rotate(double degrees)
307 {
308 Rotate(-degrees,0,0);
309 return TRUE;
310 }
311
312 // counter clockwise rotate around a point
313 //
314 // cos(r) -sin(r) x(1-cos(r))+y(sin(r)
315 // sin(r) cos(r) y(1-cos(r))-x(sin(r)
316 // 0 0 1
317 wxTransformMatrix& wxTransformMatrix::Rotate(const double &degrees, const double &x, const double &y)
318 {
319 double angle = degrees * pi / 180.0;
320 double c = cos(angle);
321 double s = sin(angle);
322 double r00,r10,r20,r01,r11,r21;
323
324 if (m_isIdentity)
325 {
326 double tx = x*(1-c)+y*s;
327 double ty = y*(1-c)-x*s;
328 r00 = c ;
329 r10 = -s;
330 r20 = tx;
331 r01 = s;
332 r11 = c;
333 r21 = ty;
334 }
335 else if (x!=0 || y!=0)
336 {
337 double tx = x*(1-c)+y*s;
338 double ty = y*(1-c)-x*s;
339 r00 = c * m_matrix[0][0] - s * m_matrix[0][1] + tx * m_matrix[0][2];
340 r10 = c * m_matrix[1][0] - s * m_matrix[1][1] + tx * m_matrix[1][2];
341 r20 = c * m_matrix[2][0] - s * m_matrix[2][1] + tx;// * m_matrix[2][2];
342 r01 = c * m_matrix[0][1] + s * m_matrix[0][0] + ty * m_matrix[0][2];
343 r11 = c * m_matrix[1][1] + s * m_matrix[1][0] + ty * m_matrix[1][2];
344 r21 = c * m_matrix[2][1] + s * m_matrix[2][0] + ty;// * m_matrix[2][2];
345 }
346 else
347 {
348 r00 = c * m_matrix[0][0] - s * m_matrix[0][1];
349 r10 = c * m_matrix[1][0] - s * m_matrix[1][1];
350 r20 = c * m_matrix[2][0] - s * m_matrix[2][1];
351 r01 = c * m_matrix[0][1] + s * m_matrix[0][0];
352 r11 = c * m_matrix[1][1] + s * m_matrix[1][0];
353 r21 = c * m_matrix[2][1] + s * m_matrix[2][0];
354 }
355
356 m_matrix[0][0] = r00;
357 m_matrix[1][0] = r10;
358 m_matrix[2][0] = r20;
359 m_matrix[0][1] = r01;
360 m_matrix[1][1] = r11;
361 m_matrix[2][1] = r21;
362
363 /* or like this
364 wxTransformMatrix rotate;
365 rotate.m_matrix[2][0] = tx;
366 rotate.m_matrix[2][1] = ty;
367
368 rotate.m_matrix[0][0] = c;
369 rotate.m_matrix[0][1] = s;
370
371 rotate.m_matrix[1][0] = -s;
372 rotate.m_matrix[1][1] = c;
373
374 rotate.m_isIdentity=false;
375 *this = rotate * (*this);
376 */
377 m_isIdentity = IsIdentity1();
378
379 return *this;
380 }
381
382 // Transform a point from logical to device coordinates
383 bool wxTransformMatrix::TransformPoint(double x, double y, double& tx, double& ty) const
384 {
385 if (IsIdentity())
386 {
387 tx = x; ty = y; return TRUE;
388 }
389
390 tx = x * m_matrix[0][0] + y * m_matrix[1][0] + m_matrix[2][0];
391 ty = x * m_matrix[0][1] + y * m_matrix[1][1] + m_matrix[2][1];
392
393 return TRUE;
394 }
395
396 // Transform a point from device to logical coordinates.
397
398 // Example of use:
399 // wxTransformMatrix mat = dc.GetTransformation();
400 // mat.Invert();
401 // mat.InverseTransformPoint(x, y, x1, y1);
402 // OR (shorthand:)
403 // dc.LogicalToDevice(x, y, x1, y1);
404 // The latter is slightly less efficient if we're doing several
405 // conversions, since the matrix is inverted several times.
406 bool wxTransformMatrix::InverseTransformPoint(double x, double y, double& tx, double& ty) const
407 {
408 if (IsIdentity())
409 {
410 tx = x; ty = y; return TRUE;
411 }
412
413 double z = (1.0 - m_matrix[0][2] * x - m_matrix[1][2] * y) / m_matrix[2][2];
414 if (z == 0.0)
415 {
416 // z = 0.0000001;
417 return FALSE;
418 }
419 tx = x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0];
420 ty = x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1];
421 return TRUE;
422 }
423
424 wxTransformMatrix& wxTransformMatrix::operator*=(const double& t)
425 {
426 for (int i = 0; i < 3; i++)
427 for (int j = 0; j < 3; j++)
428 m_matrix[i][j]*= t;
429 m_isIdentity = IsIdentity1();
430 return *this;
431 }
432
433 wxTransformMatrix& wxTransformMatrix::operator/=(const double& t)
434 {
435 for (int i = 0; i < 3; i++)
436 for (int j = 0; j < 3; j++)
437 m_matrix[i][j]/= t;
438 m_isIdentity = IsIdentity1();
439 return *this;
440 }
441
442 wxTransformMatrix& wxTransformMatrix::operator+=(const wxTransformMatrix& mat)
443 {
444 for (int i = 0; i < 3; i++)
445 for (int j = 0; j < 3; j++)
446 m_matrix[i][j] += mat.m_matrix[i][j];
447 m_isIdentity = IsIdentity1();
448 return *this;
449 }
450
451 wxTransformMatrix& wxTransformMatrix::operator-=(const wxTransformMatrix& mat)
452 {
453 for (int i = 0; i < 3; i++)
454 for (int j = 0; j < 3; j++)
455 m_matrix[i][j] -= mat.m_matrix[i][j];
456 m_isIdentity = IsIdentity1();
457 return *this;
458 }
459
460 wxTransformMatrix& wxTransformMatrix::operator*=(const wxTransformMatrix& mat)
461 {
462
463 if (mat.m_isIdentity)
464 return *this;
465 if (m_isIdentity)
466 {
467 *this = mat;
468 return *this;
469 }
470 else
471 {
472 wxTransformMatrix result;
473 for (int i = 0; i < 3; i++)
474 {
475 for (int j = 0; j < 3; j++)
476 {
477 double sum = 0;
478 for (int k = 0; k < 3; k++)
479 sum += m_matrix[k][i] * mat.m_matrix[j][k];
480 result.m_matrix[j][i] = sum;
481 }
482 }
483 *this = result;
484 }
485
486 m_isIdentity = IsIdentity1();
487 return *this;
488 }
489
490
491 // constant operators
492 wxTransformMatrix wxTransformMatrix::operator*(const double& t) const
493 {
494 wxTransformMatrix result = *this;
495 result *= t;
496 result.m_isIdentity = result.IsIdentity1();
497 return result;
498 }
499
500 wxTransformMatrix wxTransformMatrix::operator/(const double& t) const
501 {
502 wxTransformMatrix result = *this;
503 // wxASSERT(t!=0);
504 result /= t;
505 result.m_isIdentity = result.IsIdentity1();
506 return result;
507 }
508
509 wxTransformMatrix wxTransformMatrix::operator+(const wxTransformMatrix& m) const
510 {
511 wxTransformMatrix result = *this;
512 result += m;
513 result.m_isIdentity = result.IsIdentity1();
514 return result;
515 }
516
517 wxTransformMatrix wxTransformMatrix::operator-(const wxTransformMatrix& m) const
518 {
519 wxTransformMatrix result = *this;
520 result -= m;
521 result.m_isIdentity = result.IsIdentity1();
522 return result;
523 }
524
525
526 wxTransformMatrix wxTransformMatrix::operator*(const wxTransformMatrix& m) const
527 {
528 wxTransformMatrix result = *this;
529 result *= m;
530 result.m_isIdentity = result.IsIdentity1();
531 return result;
532 }
533
534
535 wxTransformMatrix wxTransformMatrix::operator-() const
536 {
537 wxTransformMatrix result = *this;
538 for (int i = 0; i < 3; i++)
539 for (int j = 0; j < 3; j++)
540 result.m_matrix[i][j] = -(this->m_matrix[i][j]);
541 result.m_isIdentity = result.IsIdentity1();
542 return result;
543 }
544
545 static double CheckInt(double getal)
546 {
547 // check if the number is very close to an integer
548 if ( (ceil(getal) - getal) < 0.0001)
549 return ceil(getal);
550
551 else if ( (getal - floor(getal)) < 0.0001)
552 return floor(getal);
553
554 return getal;
555
556 }
557
558 double wxTransformMatrix::Get_scaleX()
559 {
560 double scale_factor;
561 double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi);
562 if (rot_angle != 90 && rot_angle != -90)
563 scale_factor = m_matrix[0][0]/cos((rot_angle/180)*pi);
564 else
565 scale_factor = m_matrix[0][0]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden !
566
567 scale_factor = CheckInt(scale_factor);
568 if (scale_factor < 0)
569 scale_factor = -scale_factor;
570
571 return scale_factor;
572 }
573
574 double wxTransformMatrix::Get_scaleY()
575 {
576 double scale_factor;
577 double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi);
578 if (rot_angle != 90 && rot_angle != -90)
579 scale_factor = m_matrix[1][1]/cos((rot_angle/180)*pi);
580 else
581 scale_factor = m_matrix[1][1]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden !
582
583 scale_factor = CheckInt(scale_factor);
584 if (scale_factor < 0)
585
586 scale_factor = -scale_factor;
587
588 return scale_factor;
589
590 }
591
592 double wxTransformMatrix::GetRotation()
593 {
594 double temp1 = GetValue(0,0); // for angle calculation
595 double temp2 = GetValue(0,1); //
596
597 // Rotation
598 double rot_angle = atan2(temp2,temp1)*180/pi;
599
600 rot_angle = CheckInt(rot_angle);
601 return rot_angle;
602 }
603
604 void wxTransformMatrix::SetRotation(double rotation)
605 {
606 double x=GetValue(2,0);
607 double y=GetValue(2,1);
608 Rotate(-GetRotation(), x, y);
609 Rotate(rotation, x, y);
610 }
611