2 // Purpose: wxTransformMatrix class
3 // Author: Chris Breeze, Julian Smart
4 // Modified by: Klaas Holwerda
7 // Copyright: (c) Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
12 #pragma implementation "matrix.h"
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.
18 // For compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
29 #include "wx/matrix.h"
32 static const double pi = 3.1415926535;
34 wxTransformMatrix::wxTransformMatrix(void)
41 wxTransformMatrix::wxTransformMatrix(const wxTransformMatrix& mat)
47 double wxTransformMatrix::GetValue(int col, int row) const
49 if (row < 0 || row > 2 || col < 0 || col > 2)
52 return m_matrix[col][row];
55 void wxTransformMatrix::SetValue(int col, int row, double value)
57 if (row < 0 || row > 2 || col < 0 || col > 2)
60 m_matrix[col][row] = value;
61 m_isIdentity = IsIdentity1();
64 void wxTransformMatrix::operator = (const wxTransformMatrix& mat)
67 for (i = 0; i < 3; i++)
69 for (j = 0; j < 3; j++)
71 m_matrix[i][j] = mat.m_matrix[i][j];
74 m_isIdentity = mat.m_isIdentity;
77 bool wxTransformMatrix::operator == (const wxTransformMatrix& mat)
79 if (m_isIdentity==TRUE && mat.m_isIdentity==TRUE)
83 for (i = 0; i < 3; i++)
85 for (j = 0; j < 3; j++)
87 if (m_matrix[i][j] != mat.m_matrix[i][j])
94 bool wxTransformMatrix::operator != (const wxTransformMatrix& mat)
96 return (! ((*this) == mat));
99 double& wxTransformMatrix::operator()(int col, int row)
101 if (row < 0 || row > 2 || col < 0 || col > 2)
102 return m_matrix[0][0];
104 return m_matrix[col][row];
107 double wxTransformMatrix::operator()(int col, int row) const
109 if (row < 0 || row > 2 || col < 0 || col > 2)
112 return m_matrix[col][row];
116 bool wxTransformMatrix::Invert(void)
118 double inverseMatrix[3][3];
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]);
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]);
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]);
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];
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;
142 for (i = 0; i < 3; i++)
144 for (j = 0; j < 3; j++)
146 m_matrix[i][j] = inverseMatrix[i][j];
149 m_isIdentity = IsIdentity1();
158 // Make into identity matrix
159 bool wxTransformMatrix::Identity(void)
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;
168 // Scale by scale (isotropic scaling i.e. the same in x and y):
170 // matrix' = | 0 scale 0 | x matrix
173 bool wxTransformMatrix::Scale(double scale)
176 for (i = 0; i < 3; i++)
178 for (j = 0; j < 3; j++)
180 m_matrix[i][j] *= scale;
183 m_isIdentity = IsIdentity1();
189 // scale a matrix in 2D
195 wxTransformMatrix& wxTransformMatrix::Scale(const double &xs, const double &ys,const double &xc, const double &yc)
197 double r00,r10,r20,r01,r11,r21;
201 double tx =xc*(1-xs);
202 double ty =yc*(1-ys);
210 else if (xc!=0 || yc!=0)
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;
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];
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;
239 // first translate to origin O
240 (*this).Translate(-x_cen, -y_cen);
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();
248 *this = scale * (*this);
250 // translate back from origin to x_cen, y_cen
251 (*this).Translate(x_cen, y_cen);
254 m_isIdentity = IsIdentity1();
260 // mirror a matrix in x, y
265 wxTransformMatrix& wxTransformMatrix::Mirror(bool x, bool y)
267 wxTransformMatrix temp;
270 temp.m_matrix[1][1] = -1;
271 temp.m_isIdentity=FALSE;
275 temp.m_matrix[0][0] = -1;
276 temp.m_isIdentity=FALSE;
279 *this = temp * (*this);
280 m_isIdentity = IsIdentity1();
284 // Translate by dx, dy:
286 // matrix' = | 0 1 dy | x matrix
289 bool wxTransformMatrix::Translate(double dx, double dy)
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];
297 m_isIdentity = IsIdentity1();
302 // Rotate clockwise by the given number of degrees:
304 // matrix' = | -sin cos 0 | x matrix
306 bool wxTransformMatrix::Rotate(double degrees)
308 Rotate(-degrees,0,0);
312 // counter clockwise rotate around a point
314 // cos(r) -sin(r) x(1-cos(r))+y(sin(r)
315 // sin(r) cos(r) y(1-cos(r))-x(sin(r)
317 wxTransformMatrix& wxTransformMatrix::Rotate(const double °rees, const double &x, const double &y)
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;
326 double tx = x*(1-c)+y*s;
327 double ty = y*(1-c)-x*s;
335 else if (x!=0 || y!=0)
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];
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];
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;
364 wxTransformMatrix rotate;
365 rotate.m_matrix[2][0] = tx;
366 rotate.m_matrix[2][1] = ty;
368 rotate.m_matrix[0][0] = c;
369 rotate.m_matrix[0][1] = s;
371 rotate.m_matrix[1][0] = -s;
372 rotate.m_matrix[1][1] = c;
374 rotate.m_isIdentity=false;
375 *this = rotate * (*this);
377 m_isIdentity = IsIdentity1();
382 // Transform a point from logical to device coordinates
383 bool wxTransformMatrix::TransformPoint(double x, double y, double& tx, double& ty) const
387 tx = x; ty = y; return TRUE;
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];
396 // Transform a point from device to logical coordinates.
399 // wxTransformMatrix mat = dc.GetTransformation();
401 // mat.InverseTransformPoint(x, y, x1, y1);
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
410 tx = x; ty = y; return TRUE;
413 double z = (1.0 - m_matrix[0][2] * x - m_matrix[1][2] * y) / m_matrix[2][2];
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];
424 wxTransformMatrix& wxTransformMatrix::operator*=(const double& t)
426 for (int i = 0; i < 3; i++)
427 for (int j = 0; j < 3; j++)
429 m_isIdentity = IsIdentity1();
433 wxTransformMatrix& wxTransformMatrix::operator/=(const double& t)
435 for (int i = 0; i < 3; i++)
436 for (int j = 0; j < 3; j++)
438 m_isIdentity = IsIdentity1();
442 wxTransformMatrix& wxTransformMatrix::operator+=(const wxTransformMatrix& mat)
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();
451 wxTransformMatrix& wxTransformMatrix::operator-=(const wxTransformMatrix& mat)
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();
460 wxTransformMatrix& wxTransformMatrix::operator*=(const wxTransformMatrix& mat)
463 if (mat.m_isIdentity)
472 wxTransformMatrix result;
473 for (int i = 0; i < 3; i++)
475 for (int j = 0; j < 3; j++)
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;
486 m_isIdentity = IsIdentity1();
491 // constant operators
492 wxTransformMatrix wxTransformMatrix::operator*(const double& t) const
494 wxTransformMatrix result = *this;
496 result.m_isIdentity = result.IsIdentity1();
500 wxTransformMatrix wxTransformMatrix::operator/(const double& t) const
502 wxTransformMatrix result = *this;
505 result.m_isIdentity = result.IsIdentity1();
509 wxTransformMatrix wxTransformMatrix::operator+(const wxTransformMatrix& m) const
511 wxTransformMatrix result = *this;
513 result.m_isIdentity = result.IsIdentity1();
517 wxTransformMatrix wxTransformMatrix::operator-(const wxTransformMatrix& m) const
519 wxTransformMatrix result = *this;
521 result.m_isIdentity = result.IsIdentity1();
526 wxTransformMatrix wxTransformMatrix::operator*(const wxTransformMatrix& m) const
528 wxTransformMatrix result = *this;
530 result.m_isIdentity = result.IsIdentity1();
535 wxTransformMatrix wxTransformMatrix::operator-() const
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();
545 static double CheckInt(double getal)
547 // check if the number is very close to an integer
548 if ( (ceil(getal) - getal) < 0.0001)
551 else if ( (getal - floor(getal)) < 0.0001)
558 double wxTransformMatrix::Get_scaleX()
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);
565 scale_factor = m_matrix[0][0]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden !
567 scale_factor = CheckInt(scale_factor);
568 if (scale_factor < 0)
569 scale_factor = -scale_factor;
574 double wxTransformMatrix::Get_scaleY()
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);
581 scale_factor = m_matrix[1][1]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden !
583 scale_factor = CheckInt(scale_factor);
584 if (scale_factor < 0)
586 scale_factor = -scale_factor;
592 double wxTransformMatrix::GetRotation()
594 double temp1 = GetValue(0,0); // for angle calculation
595 double temp2 = GetValue(0,1); //
598 double rot_angle = atan2(temp2,temp1)*180/pi;
600 rot_angle = CheckInt(rot_angle);
604 void wxTransformMatrix::SetRotation(double rotation)
606 double x=GetValue(2,0);
607 double y=GetValue(2,1);
608 Rotate(-GetRotation(), x, y);
609 Rotate(rotation, x, y);