1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxTransformMatrix class
4 // Author: Chris Breeze, Julian Smart
5 // Modified by: Klaas Holwerda
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
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.
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
27 #include "wx/matrix.h"
29 static const double pi = M_PI;
31 wxTransformMatrix::wxTransformMatrix(void)
38 wxTransformMatrix::wxTransformMatrix(const wxTransformMatrix& mat)
44 double wxTransformMatrix::GetValue(int col, int row) const
46 if (row < 0 || row > 2 || col < 0 || col > 2)
49 return m_matrix[col][row];
52 void wxTransformMatrix::SetValue(int col, int row, double value)
54 if (row < 0 || row > 2 || col < 0 || col > 2)
57 m_matrix[col][row] = value;
58 m_isIdentity = IsIdentity1();
61 void wxTransformMatrix::operator = (const wxTransformMatrix& mat)
64 for (i = 0; i < 3; i++)
66 for (j = 0; j < 3; j++)
68 m_matrix[i][j] = mat.m_matrix[i][j];
71 m_isIdentity = mat.m_isIdentity;
74 bool wxTransformMatrix::operator == (const wxTransformMatrix& mat) const
76 if (m_isIdentity && mat.m_isIdentity)
80 for (i = 0; i < 3; i++)
82 for (j = 0; j < 3; j++)
84 if ( !wxIsSameDouble(m_matrix[i][j], mat.m_matrix[i][j]) )
91 bool wxTransformMatrix::operator != (const wxTransformMatrix& mat) const
93 return (! ((*this) == mat));
96 double& wxTransformMatrix::operator()(int col, int row)
98 if (row < 0 || row > 2 || col < 0 || col > 2)
99 return m_matrix[0][0];
101 return m_matrix[col][row];
104 double wxTransformMatrix::operator()(int col, int row) const
106 if (row < 0 || row > 2 || col < 0 || col > 2)
109 return m_matrix[col][row];
113 bool wxTransformMatrix::Invert(void)
115 double inverseMatrix[3][3];
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]);
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]);
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]);
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];
132 if ( wxIsNullDouble(det) )
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;
139 for (int i = 0; i < 3; i++)
141 for (int j = 0; j < 3; j++)
143 m_matrix[i][j] = inverseMatrix[i][j];
146 m_isIdentity = IsIdentity1();
150 // Make into identity matrix
151 bool wxTransformMatrix::Identity(void)
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;
160 // Scale by scale (isotropic scaling i.e. the same in x and y):
162 // matrix' = | 0 scale 0 | x matrix
165 bool wxTransformMatrix::Scale(double scale)
168 for (i = 0; i < 3; i++)
170 for (j = 0; j < 3; j++)
172 m_matrix[i][j] *= scale;
175 m_isIdentity = IsIdentity1();
181 // scale a matrix in 2D
187 wxTransformMatrix& wxTransformMatrix::Scale(const double &xs, const double &ys,const double &xc, const double &yc)
189 double r00,r10,r20,r01,r11,r21;
193 double tx = xc*(1-xs);
194 double ty = yc*(1-ys);
202 else if ( !wxIsNullDouble(xc) || !wxIsNullDouble(yc) )
204 double tx = xc*(1-xs);
205 double ty = yc*(1-ys);
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;
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];
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;
231 // first translate to origin O
232 (*this).Translate(-x_cen, -y_cen);
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();
240 *this = scale * (*this);
242 // translate back from origin to x_cen, y_cen
243 (*this).Translate(x_cen, y_cen);
246 m_isIdentity = IsIdentity1();
252 // mirror a matrix in x, y
257 wxTransformMatrix& wxTransformMatrix::Mirror(bool x, bool y)
259 wxTransformMatrix temp;
262 temp.m_matrix[1][1] = -1;
263 temp.m_isIdentity=false;
267 temp.m_matrix[0][0] = -1;
268 temp.m_isIdentity=false;
271 *this = temp * (*this);
272 m_isIdentity = IsIdentity1();
276 // Translate by dx, dy:
278 // matrix' = | 0 1 dy | x matrix
281 bool wxTransformMatrix::Translate(double dx, double dy)
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];
289 m_isIdentity = IsIdentity1();
294 // Rotate clockwise by the given number of degrees:
296 // matrix' = | -sin cos 0 | x matrix
298 bool wxTransformMatrix::Rotate(double degrees)
300 Rotate(-degrees,0,0);
304 // counter clockwise rotate around a point
306 // cos(r) -sin(r) x(1-cos(r))+y(sin(r)
307 // sin(r) cos(r) y(1-cos(r))-x(sin(r)
309 wxTransformMatrix& wxTransformMatrix::Rotate(const double °rees, const double &x, const double &y)
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;
318 double tx = x*(1-c)+y*s;
319 double ty = y*(1-c)-x*s;
327 else if ( !wxIsNullDouble(x) || !wxIsNullDouble(y) )
329 double tx = x*(1-c)+y*s;
330 double ty = y*(1-c)-x*s;
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];
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];
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;
356 wxTransformMatrix rotate;
357 rotate.m_matrix[2][0] = tx;
358 rotate.m_matrix[2][1] = ty;
360 rotate.m_matrix[0][0] = c;
361 rotate.m_matrix[0][1] = s;
363 rotate.m_matrix[1][0] = -s;
364 rotate.m_matrix[1][1] = c;
366 rotate.m_isIdentity=false;
367 *this = rotate * (*this);
369 m_isIdentity = IsIdentity1();
374 // Transform a point from logical to device coordinates
375 bool wxTransformMatrix::TransformPoint(double x, double y, double& tx, double& ty) const
379 tx = x; ty = y; return true;
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];
388 // Transform a point from device to logical coordinates.
391 // wxTransformMatrix mat = dc.GetTransformation();
393 // mat.InverseTransformPoint(x, y, x1, y1);
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.
398 bool wxTransformMatrix::InverseTransformPoint(double x, double y, double& tx, double& ty) const
407 const double z = (1.0 - m_matrix[0][2] * x - m_matrix[1][2] * y) / m_matrix[2][2];
408 if ( wxIsNullDouble(z) )
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];
416 wxTransformMatrix& wxTransformMatrix::operator*=(const double& t)
418 for (int i = 0; i < 3; i++)
419 for (int j = 0; j < 3; j++)
421 m_isIdentity = IsIdentity1();
425 wxTransformMatrix& wxTransformMatrix::operator/=(const double& t)
427 for (int i = 0; i < 3; i++)
428 for (int j = 0; j < 3; j++)
430 m_isIdentity = IsIdentity1();
434 wxTransformMatrix& wxTransformMatrix::operator+=(const wxTransformMatrix& mat)
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();
443 wxTransformMatrix& wxTransformMatrix::operator-=(const wxTransformMatrix& mat)
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();
452 wxTransformMatrix& wxTransformMatrix::operator*=(const wxTransformMatrix& mat)
455 if (mat.m_isIdentity)
464 wxTransformMatrix result;
465 for (int i = 0; i < 3; i++)
467 for (int j = 0; j < 3; j++)
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;
478 m_isIdentity = IsIdentity1();
483 // constant operators
484 wxTransformMatrix wxTransformMatrix::operator*(const double& t) const
486 wxTransformMatrix result = *this;
488 result.m_isIdentity = result.IsIdentity1();
492 wxTransformMatrix wxTransformMatrix::operator/(const double& t) const
494 wxTransformMatrix result = *this;
497 result.m_isIdentity = result.IsIdentity1();
501 wxTransformMatrix wxTransformMatrix::operator+(const wxTransformMatrix& m) const
503 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();
518 wxTransformMatrix wxTransformMatrix::operator*(const wxTransformMatrix& m) const
520 wxTransformMatrix result = *this;
522 result.m_isIdentity = result.IsIdentity1();
527 wxTransformMatrix wxTransformMatrix::operator-() const
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();
537 static double CheckInt(double getal)
539 // check if the number is very close to an integer
540 if ( (ceil(getal) - getal) < 0.0001)
543 else if ( (getal - floor(getal)) < 0.0001)
550 double wxTransformMatrix::Get_scaleX()
553 double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi);
554 if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) )
555 scale_factor = m_matrix[0][0]/cos((rot_angle/180)*pi);
557 scale_factor = m_matrix[0][0]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden !
559 scale_factor = CheckInt(scale_factor);
560 if (scale_factor < 0)
561 scale_factor = -scale_factor;
566 double wxTransformMatrix::Get_scaleY()
569 double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi);
570 if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) )
571 scale_factor = m_matrix[1][1]/cos((rot_angle/180)*pi);
573 scale_factor = m_matrix[1][1]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden !
575 scale_factor = CheckInt(scale_factor);
576 if (scale_factor < 0)
578 scale_factor = -scale_factor;
584 double wxTransformMatrix::GetRotation()
586 double temp1 = GetValue(0,0); // for angle calculation
587 double temp2 = GetValue(0,1); //
590 double rot_angle = atan2(temp2,temp1)*180/pi;
592 rot_angle = CheckInt(rot_angle);
596 void wxTransformMatrix::SetRotation(double rotation)
598 double x=GetValue(2,0);
599 double y=GetValue(2,1);
600 Rotate(-GetRotation(), x, y);
601 Rotate(rotation, x, y);