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