2 // Purpose: wxTransformMatrix class
3 // Author: Chris Breeze, Julian Smart
4 // Modified by: Klaas Holwerda
7 // Copyright: (c) Julian Smart and Markus Holzem
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
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 #if ! (defined(__WXMAC__) && defined(__UNIX__))
33 const double pi
= 3.1415926535;
36 wxTransformMatrix::wxTransformMatrix(void)
43 wxTransformMatrix::wxTransformMatrix(const wxTransformMatrix
& mat
)
48 double wxTransformMatrix::GetValue(int col
, int row
) const
50 if (row
< 0 || row
> 2 || col
< 0 || col
> 2)
53 return m_matrix
[col
][row
];
56 void wxTransformMatrix::SetValue(int col
, int row
, double value
)
58 if (row
< 0 || row
> 2 || col
< 0 || col
> 2)
61 m_matrix
[col
][row
] = value
;
62 m_isIdentity
= IsIdentity1();
65 void wxTransformMatrix::operator = (const wxTransformMatrix
& mat
)
68 for (i
= 0; i
< 3; i
++)
70 for (j
= 0; j
< 3; j
++)
72 m_matrix
[i
][j
] = mat
.m_matrix
[i
][j
];
75 m_isIdentity
= mat
.m_isIdentity
;
78 bool wxTransformMatrix::operator == (const wxTransformMatrix
& mat
)
80 if (m_isIdentity
==TRUE
&& mat
.m_isIdentity
==TRUE
)
84 for (i
= 0; i
< 3; i
++)
86 for (j
= 0; j
< 3; j
++)
88 if (m_matrix
[i
][j
] != mat
.m_matrix
[i
][j
])
95 bool wxTransformMatrix::operator != (const wxTransformMatrix
& mat
)
97 return (! ((*this) == mat
));
100 double& wxTransformMatrix::operator()(int col
, int row
)
102 if (row
< 0 || row
> 2 || col
< 0 || col
> 2)
103 return m_matrix
[0][0];
105 return m_matrix
[col
][row
];
108 double wxTransformMatrix::operator()(int col
, int row
) const
110 if (row
< 0 || row
> 2 || col
< 0 || col
> 2)
113 return m_matrix
[col
][row
];
117 bool wxTransformMatrix::Invert(void)
119 double inverseMatrix
[3][3];
121 // calculate the adjoint
122 inverseMatrix
[0][0] = wxCalculateDet(m_matrix
[1][1],m_matrix
[2][1],m_matrix
[1][2],m_matrix
[2][2]);
123 inverseMatrix
[0][1] = -wxCalculateDet(m_matrix
[0][1],m_matrix
[2][1],m_matrix
[0][2],m_matrix
[2][2]);
124 inverseMatrix
[0][2] = wxCalculateDet(m_matrix
[0][1],m_matrix
[1][1],m_matrix
[0][2],m_matrix
[1][2]);
126 inverseMatrix
[1][0] = -wxCalculateDet(m_matrix
[1][0],m_matrix
[2][0],m_matrix
[1][2],m_matrix
[2][2]);
127 inverseMatrix
[1][1] = wxCalculateDet(m_matrix
[0][0],m_matrix
[2][0],m_matrix
[0][2],m_matrix
[2][2]);
128 inverseMatrix
[1][2] = -wxCalculateDet(m_matrix
[0][0],m_matrix
[1][0],m_matrix
[0][2],m_matrix
[1][2]);
130 inverseMatrix
[2][0] = wxCalculateDet(m_matrix
[1][0],m_matrix
[2][0],m_matrix
[1][1],m_matrix
[2][1]);
131 inverseMatrix
[2][1] = -wxCalculateDet(m_matrix
[0][0],m_matrix
[2][0],m_matrix
[0][1],m_matrix
[2][1]);
132 inverseMatrix
[2][2] = wxCalculateDet(m_matrix
[0][0],m_matrix
[1][0],m_matrix
[0][1],m_matrix
[1][1]);
134 // now divide by the determinant
135 double det
= m_matrix
[0][0] * inverseMatrix
[0][0] + m_matrix
[0][1] * inverseMatrix
[1][0] + m_matrix
[0][2] * inverseMatrix
[2][0];
138 inverseMatrix
[0][0] /= det
; inverseMatrix
[1][0] /= det
; inverseMatrix
[2][0] /= det
;
139 inverseMatrix
[0][1] /= det
; inverseMatrix
[1][1] /= det
; inverseMatrix
[2][1] /= det
;
140 inverseMatrix
[0][2] /= det
; inverseMatrix
[1][2] /= det
; inverseMatrix
[2][2] /= det
;
143 for (i
= 0; i
< 3; i
++)
145 for (j
= 0; j
< 3; j
++)
147 m_matrix
[i
][j
] = inverseMatrix
[i
][j
];
150 m_isIdentity
= IsIdentity1();
159 // Make into identity matrix
160 bool wxTransformMatrix::Identity(void)
162 m_matrix
[0][0] = m_matrix
[1][1] = m_matrix
[2][2] = 1.0;
163 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;
169 // Scale by scale (isotropic scaling i.e. the same in x and y):
171 // matrix' = | 0 scale 0 | x matrix
174 bool wxTransformMatrix::Scale(double scale
)
177 for (i
= 0; i
< 3; i
++)
179 for (j
= 0; j
< 3; j
++)
181 m_matrix
[i
][j
] *= scale
;
184 m_isIdentity
= IsIdentity1();
190 // scale a matrix in 2D
196 wxTransformMatrix
& wxTransformMatrix::Scale(const double &xs
, const double &ys
,const double &xc
, const double &yc
)
198 double r00
,r10
,r20
,r01
,r11
,r21
;
202 double tx
=xc
*(1-xs
);
203 double ty
=yc
*(1-ys
);
211 else if (xc
!=0 || yc
!=0)
213 double tx
=xc
*(1-xs
);
214 double ty
=yc
*(1-ys
);
215 r00
= xs
* m_matrix
[0][0];
216 r10
= xs
* m_matrix
[1][0];
217 r20
= xs
* m_matrix
[2][0] + tx
;
218 r01
= ys
* m_matrix
[0][1];
219 r11
= ys
* m_matrix
[1][1];
220 r21
= ys
* m_matrix
[2][1] + ty
;
224 r00
= xs
* m_matrix
[0][0];
225 r10
= xs
* m_matrix
[1][0];
226 r20
= xs
* m_matrix
[2][0];
227 r01
= ys
* m_matrix
[0][1];
228 r11
= ys
* m_matrix
[1][1];
229 r21
= ys
* m_matrix
[2][1];
232 m_matrix
[0][0] = r00
;
233 m_matrix
[1][0] = r10
;
234 m_matrix
[2][0] = r20
;
235 m_matrix
[0][1] = r01
;
236 m_matrix
[1][1] = r11
;
237 m_matrix
[2][1] = r21
;
240 // first translate to origin O
241 (*this).Translate(-x_cen, -y_cen);
243 // now do the scaling
244 wxTransformMatrix scale;
245 scale.m_matrix[0][0] = x_fac;
246 scale.m_matrix[1][1] = y_fac;
247 scale.m_isIdentity = IsIdentity1();
249 *this = scale * (*this);
251 // translate back from origin to x_cen, y_cen
252 (*this).Translate(x_cen, y_cen);
255 m_isIdentity
= IsIdentity1();
261 // mirror a matrix in x, y
266 wxTransformMatrix
& wxTransformMatrix::Mirror(bool x
, bool y
)
268 wxTransformMatrix temp
;
271 temp
.m_matrix
[1][1] = -1;
272 temp
.m_isIdentity
=FALSE
;
276 temp
.m_matrix
[0][0] = -1;
277 temp
.m_isIdentity
=FALSE
;
280 *this = temp
* (*this);
281 m_isIdentity
= IsIdentity1();
285 // Translate by dx, dy:
287 // matrix' = | 0 1 dy | x matrix
290 bool wxTransformMatrix::Translate(double dx
, double dy
)
293 for (i
= 0; i
< 3; i
++)
294 m_matrix
[i
][0] += dx
* m_matrix
[i
][2];
295 for (i
= 0; i
< 3; i
++)
296 m_matrix
[i
][1] += dy
* m_matrix
[i
][2];
298 m_isIdentity
= IsIdentity1();
303 // Rotate clockwise by the given number of degrees:
305 // matrix' = | -sin cos 0 | x matrix
307 bool wxTransformMatrix::Rotate(double degrees
)
309 Rotate(-degrees
,0,0);
313 // counter clockwise rotate around a point
315 // cos(r) -sin(r) x(1-cos(r))+y(sin(r)
316 // sin(r) cos(r) y(1-cos(r))-x(sin(r)
318 wxTransformMatrix
& wxTransformMatrix::Rotate(const double °rees
, const double &x
, const double &y
)
320 double angle
= degrees
* pi
/ 180.0;
321 double c
= cos(angle
);
322 double s
= sin(angle
);
323 double r00
,r10
,r20
,r01
,r11
,r21
;
327 double tx
= x
*(1-c
)+y
*s
;
328 double ty
= y
*(1-c
)-x
*s
;
336 else if (x
!=0 || y
!=0)
338 double tx
= x
*(1-c
)+y
*s
;
339 double ty
= y
*(1-c
)-x
*s
;
340 r00
= c
* m_matrix
[0][0] - s
* m_matrix
[0][1] + tx
* m_matrix
[0][2];
341 r10
= c
* m_matrix
[1][0] - s
* m_matrix
[1][1] + tx
* m_matrix
[1][2];
342 r20
= c
* m_matrix
[2][0] - s
* m_matrix
[2][1] + tx
;// * m_matrix[2][2];
343 r01
= c
* m_matrix
[0][1] + s
* m_matrix
[0][0] + ty
* m_matrix
[0][2];
344 r11
= c
* m_matrix
[1][1] + s
* m_matrix
[1][0] + ty
* m_matrix
[1][2];
345 r21
= c
* m_matrix
[2][1] + s
* m_matrix
[2][0] + ty
;// * m_matrix[2][2];
349 r00
= c
* m_matrix
[0][0] - s
* m_matrix
[0][1];
350 r10
= c
* m_matrix
[1][0] - s
* m_matrix
[1][1];
351 r20
= c
* m_matrix
[2][0] - s
* m_matrix
[2][1];
352 r01
= c
* m_matrix
[0][1] + s
* m_matrix
[0][0];
353 r11
= c
* m_matrix
[1][1] + s
* m_matrix
[1][0];
354 r21
= c
* m_matrix
[2][1] + s
* m_matrix
[2][0];
357 m_matrix
[0][0] = r00
;
358 m_matrix
[1][0] = r10
;
359 m_matrix
[2][0] = r20
;
360 m_matrix
[0][1] = r01
;
361 m_matrix
[1][1] = r11
;
362 m_matrix
[2][1] = r21
;
365 wxTransformMatrix rotate;
366 rotate.m_matrix[2][0] = tx;
367 rotate.m_matrix[2][1] = ty;
369 rotate.m_matrix[0][0] = c;
370 rotate.m_matrix[0][1] = s;
372 rotate.m_matrix[1][0] = -s;
373 rotate.m_matrix[1][1] = c;
375 rotate.m_isIdentity=false;
376 *this = rotate * (*this);
378 m_isIdentity
= IsIdentity1();
383 // Transform a point from logical to device coordinates
384 bool wxTransformMatrix::TransformPoint(double x
, double y
, double& tx
, double& ty
) const
388 tx
= x
; ty
= y
; return TRUE
;
391 tx
= x
* m_matrix
[0][0] + y
* m_matrix
[1][0] + m_matrix
[2][0];
392 ty
= x
* m_matrix
[0][1] + y
* m_matrix
[1][1] + m_matrix
[2][1];
397 // Transform a point from device to logical coordinates.
400 // wxTransformMatrix mat = dc.GetTransformation();
402 // mat.InverseTransformPoint(x, y, x1, y1);
404 // dc.LogicalToDevice(x, y, x1, y1);
405 // The latter is slightly less efficient if we're doing several
406 // conversions, since the matrix is inverted several times.
407 bool wxTransformMatrix::InverseTransformPoint(double x
, double y
, double& tx
, double& ty
) const
411 tx
= x
; ty
= y
; return TRUE
;
414 double z
= (1.0 - m_matrix
[0][2] * x
- m_matrix
[1][2] * y
) / m_matrix
[2][2];
420 tx
= x
* m_matrix
[0][0] + y
* m_matrix
[1][0] + z
* m_matrix
[2][0];
421 ty
= x
* m_matrix
[0][1] + y
* m_matrix
[1][1] + z
* m_matrix
[2][1];
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 double& t
)
436 for (int i
= 0; i
< 3; i
++)
437 for (int j
= 0; j
< 3; 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
)
454 for (int i
= 0; i
< 3; i
++)
455 for (int j
= 0; j
< 3; j
++)
456 m_matrix
[i
][j
] -= mat
.m_matrix
[i
][j
];
457 m_isIdentity
= IsIdentity1();
461 wxTransformMatrix
& wxTransformMatrix::operator*=(const wxTransformMatrix
& mat
)
464 if (mat
.m_isIdentity
)
473 wxTransformMatrix result
;
474 for (int i
= 0; i
< 3; i
++)
476 for (int j
= 0; j
< 3; j
++)
479 for (int k
= 0; k
< 3; k
++)
480 sum
+= m_matrix
[k
][i
] * mat
.m_matrix
[j
][k
];
481 result
.m_matrix
[j
][i
] = sum
;
487 m_isIdentity
= IsIdentity1();
492 // constant operators
493 wxTransformMatrix
wxTransformMatrix::operator*(const double& t
) const
495 wxTransformMatrix result
= *this;
497 result
.m_isIdentity
= result
.IsIdentity1();
501 wxTransformMatrix
wxTransformMatrix::operator/(const double& t
) const
503 wxTransformMatrix result
= *this;
506 result
.m_isIdentity
= result
.IsIdentity1();
510 wxTransformMatrix
wxTransformMatrix::operator+(const wxTransformMatrix
& m
) const
512 wxTransformMatrix result
= *this;
514 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 wxTransformMatrix
& m
) const
529 wxTransformMatrix result
= *this;
531 result
.m_isIdentity
= result
.IsIdentity1();
536 wxTransformMatrix
wxTransformMatrix::operator-() const
538 wxTransformMatrix result
= *this;
539 for (int i
= 0; i
< 3; i
++)
540 for (int j
= 0; j
< 3; j
++)
541 result
.m_matrix
[i
][j
] = -(this->m_matrix
[i
][j
]);
542 result
.m_isIdentity
= result
.IsIdentity1();
546 static double CheckInt(double getal
)
548 // check if the number is very close to an integer
549 if ( (ceil(getal
) - getal
) < 0.0001)
552 else if ( (getal
- floor(getal
)) < 0.0001)
559 double wxTransformMatrix::Get_scaleX()
562 double rot_angle
= CheckInt(atan2(m_matrix
[1][0],m_matrix
[0][0])*180/pi
);
563 if (rot_angle
!= 90 && rot_angle
!= -90)
564 scale_factor
= m_matrix
[0][0]/cos((rot_angle
/180)*pi
);
566 scale_factor
= m_matrix
[0][0]/sin((rot_angle
/180)*pi
); // er kan nl. niet door 0 gedeeld worden !
568 scale_factor
= CheckInt(scale_factor
);
569 if (scale_factor
< 0)
570 scale_factor
= -scale_factor
;
575 double wxTransformMatrix::Get_scaleY()
578 double rot_angle
= CheckInt(atan2(m_matrix
[1][0],m_matrix
[0][0])*180/pi
);
579 if (rot_angle
!= 90 && rot_angle
!= -90)
580 scale_factor
= m_matrix
[1][1]/cos((rot_angle
/180)*pi
);
582 scale_factor
= m_matrix
[1][1]/sin((rot_angle
/180)*pi
); // er kan nl. niet door 0 gedeeld worden !
584 scale_factor
= CheckInt(scale_factor
);
585 if (scale_factor
< 0)
587 scale_factor
= -scale_factor
;
593 double wxTransformMatrix::GetRotation()
595 double temp1
= GetValue(0,0); // for angle calculation
596 double temp2
= GetValue(0,1); //
599 double rot_angle
= atan2(temp2
,temp1
)*180/pi
;
601 rot_angle
= CheckInt(rot_angle
);
605 void wxTransformMatrix::SetRotation(double rotation
)
607 double x
=GetValue(2,0);
608 double y
=GetValue(2,1);
609 Rotate(-GetRotation(), x
, y
);
610 Rotate(rotation
, x
, y
);