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