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