]> git.saurik.com Git - wxWidgets.git/blob - src/common/matrix.cpp
turning on old quit apple event handling
[wxWidgets.git] / src / common / matrix.cpp
1 // Name:        matrix.cpp
2 // Purpose:     wxTransformMatrix class
3 // Author:      Chris Breeze, Julian Smart
4 // Modified by: Klaas Holwerda
5 // Created:     01/02/97
6 // RCS-ID:      $Id$
7 // Copyright:   (c) Julian Smart
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
12 #pragma implementation "matrix.h"
13 #endif
14
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.
17
18 // For compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
20
21 #ifdef __BORLANDC__
22 #pragma hdrstop
23 #endif
24
25 #ifndef WX_PRECOMP
26 #include "wx/defs.h"
27 #endif
28
29 #include "wx/matrix.h"
30 #include <math.h>
31
32 static const double pi = 3.1415926535;
33
34 wxTransformMatrix::wxTransformMatrix(void)
35 {
36     m_isIdentity = FALSE;
37
38     Identity();
39 }
40
41 wxTransformMatrix::wxTransformMatrix(const wxTransformMatrix& mat)
42     : wxObject()
43 {
44     (*this) = mat;
45 }
46
47 double wxTransformMatrix::GetValue(int col, int row) const
48 {
49     if (row < 0 || row > 2 || col < 0 || col > 2)
50         return 0.0;
51
52     return m_matrix[col][row];
53 }
54
55 void wxTransformMatrix::SetValue(int col, int row, double value)
56 {
57     if (row < 0 || row > 2 || col < 0 || col > 2)
58         return;
59
60     m_matrix[col][row] = value;
61     m_isIdentity = IsIdentity1();
62 }
63
64 void wxTransformMatrix::operator = (const wxTransformMatrix& mat)
65 {
66     int i, j;
67     for (i = 0; i < 3; i++)
68     {
69         for (j = 0; j < 3; j++)
70         {
71             m_matrix[i][j] = mat.m_matrix[i][j];
72         }
73     }
74     m_isIdentity = mat.m_isIdentity;
75 }
76
77 bool wxTransformMatrix::operator == (const wxTransformMatrix& mat)
78 {
79     if (m_isIdentity==TRUE && mat.m_isIdentity==TRUE)
80         return TRUE;
81
82     int i, j;
83     for (i = 0; i < 3; i++)
84     {
85         for (j = 0; j < 3; j++)
86         {
87             if (m_matrix[i][j] != mat.m_matrix[i][j])
88                 return FALSE;
89         }
90     }
91     return TRUE;
92 }
93
94 bool wxTransformMatrix::operator != (const wxTransformMatrix& mat)
95 {
96     return (! ((*this) == mat));
97 }
98
99 double& wxTransformMatrix::operator()(int col, int row)
100 {
101     if (row < 0 || row > 2 || col < 0 || col > 2)
102         return m_matrix[0][0];
103
104     return m_matrix[col][row];
105 }
106
107 double wxTransformMatrix::operator()(int col, int row) const
108 {
109     if (row < 0 || row > 2 || col < 0 || col > 2)
110         return 0.0;
111
112     return m_matrix[col][row];
113 }
114
115 // Invert matrix
116 bool wxTransformMatrix::Invert(void)
117 {
118     double inverseMatrix[3][3];
119
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]);
124
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]);
128
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]);
132
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];
135     if (det != 0.0)
136     {
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;
140
141         int i, j;
142         for (i = 0; i < 3; i++)
143         {
144             for (j = 0; j < 3; j++)
145             {
146                 m_matrix[i][j] = inverseMatrix[i][j];
147             }
148         }
149         m_isIdentity = IsIdentity1();
150         return TRUE;
151     }
152     else
153     {
154         return FALSE;
155     }
156 }
157
158 // Make into identity matrix
159 bool wxTransformMatrix::Identity(void)
160 {
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;
163     m_isIdentity = TRUE;
164
165     return TRUE;
166 }
167
168 // Scale by scale (isotropic scaling i.e. the same in x and y):
169 //           | scale  0      0      |
170 // matrix' = |  0     scale  0      | x matrix
171 //           |  0     0      scale  |
172 //
173 bool wxTransformMatrix::Scale(double scale)
174 {
175     int i, j;
176     for (i = 0; i < 3; i++)
177     {
178         for (j = 0; j < 3; j++)
179         {
180             m_matrix[i][j] *= scale;
181         }
182     }
183     m_isIdentity = IsIdentity1();
184
185     return TRUE;
186 }
187
188
189 // scale a matrix in 2D
190 //
191 //     xs    0      xc(1-xs)
192 //     0    ys      yc(1-ys)
193 //     0     0      1
194 //
195 wxTransformMatrix&  wxTransformMatrix::Scale(const double &xs, const double &ys,const double &xc, const double &yc)
196 {
197     double r00,r10,r20,r01,r11,r21;
198
199     if (m_isIdentity)
200     {
201         double tx  =xc*(1-xs);
202         double ty  =yc*(1-ys);
203         r00 = xs;
204         r10 = 0;
205         r20 = tx;
206         r01 = 0;
207         r11 = ys;
208         r21 = ty;
209     }
210     else if (xc!=0 || yc!=0)
211     {
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;
220     }
221     else
222     {
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];
229     }
230
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;
237
238 /* or like this
239     // first translate to origin O
240     (*this).Translate(-x_cen, -y_cen);
241
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();
247
248     *this = scale * (*this);
249
250     // translate back from origin to x_cen, y_cen
251     (*this).Translate(x_cen, y_cen);
252 */
253
254     m_isIdentity = IsIdentity1();
255
256     return *this;
257 }
258
259
260 // mirror a matrix in x, y
261 //
262 //     -1      0      0     Y-mirror
263 //      0     -1      0     X-mirror
264 //      0      0     -1     Z-mirror
265 wxTransformMatrix&  wxTransformMatrix::Mirror(bool x, bool y)
266 {
267     wxTransformMatrix temp;
268     if (x)
269     {
270         temp.m_matrix[1][1] = -1;
271         temp.m_isIdentity=FALSE;
272     }
273     if (y)
274     {
275         temp.m_matrix[0][0] = -1;
276         temp.m_isIdentity=FALSE;
277     }
278
279     *this = temp * (*this);
280     m_isIdentity = IsIdentity1();
281     return *this;
282 }
283
284 // Translate by dx, dy:
285 //           | 1  0 dx |
286 // matrix' = | 0  1 dy | x matrix
287 //           | 0  0  1 |
288 //
289 bool wxTransformMatrix::Translate(double dx, double dy)
290 {
291     int i;
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];
296
297     m_isIdentity = IsIdentity1();
298
299     return TRUE;
300 }
301
302 // Rotate clockwise by the given number of degrees:
303 //           |  cos sin 0 |
304 // matrix' = | -sin cos 0 | x matrix
305 //           |   0   0  1 |
306 bool wxTransformMatrix::Rotate(double degrees)
307 {
308     Rotate(-degrees,0,0);
309     return TRUE;
310 }
311
312 // counter clockwise rotate around a point
313 //
314 //  cos(r) -sin(r)    x(1-cos(r))+y(sin(r)
315 //  sin(r)  cos(r)    y(1-cos(r))-x(sin(r)
316 //    0      0        1
317 wxTransformMatrix&  wxTransformMatrix::Rotate(const double &degrees, const double &x, const double &y)
318 {
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;
323
324     if (m_isIdentity)
325     {
326         double tx  = x*(1-c)+y*s;
327         double ty  = y*(1-c)-x*s;
328         r00 = c ;
329         r10 = -s;
330         r20 = tx;
331         r01 = s;
332         r11 = c;
333         r21 = ty;
334     }
335     else if (x!=0 || y!=0)
336     {
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];
345     }
346     else
347     {
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];
354     }
355
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;
362
363 /* or like this
364     wxTransformMatrix rotate;
365     rotate.m_matrix[2][0] = tx;
366     rotate.m_matrix[2][1] = ty;
367
368     rotate.m_matrix[0][0] = c;
369     rotate.m_matrix[0][1] = s;
370
371     rotate.m_matrix[1][0] = -s;
372     rotate.m_matrix[1][1] = c;
373
374    rotate.m_isIdentity=false;
375    *this = rotate * (*this);
376 */
377     m_isIdentity = IsIdentity1();
378
379     return *this;
380 }
381
382 // Transform a point from logical to device coordinates
383 bool wxTransformMatrix::TransformPoint(double x, double y, double& tx, double& ty) const
384 {
385     if (IsIdentity())
386     {
387         tx = x; ty = y; return TRUE;
388     }
389
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];
392
393     return TRUE;
394 }
395
396 // Transform a point from device to logical coordinates.
397
398 // Example of use:
399 //   wxTransformMatrix mat = dc.GetTransformation();
400 //   mat.Invert();
401 //   mat.InverseTransformPoint(x, y, x1, y1);
402 // OR (shorthand:)
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
407 {
408     if (IsIdentity())
409     {
410         tx = x; ty = y; return TRUE;
411     }
412
413     double z = (1.0 - m_matrix[0][2] * x - m_matrix[1][2] * y) / m_matrix[2][2];
414     if (z == 0.0)
415     {
416 //      z = 0.0000001;
417         return FALSE;
418     }
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];
421     return TRUE;
422 }
423
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
433 wxTransformMatrix& wxTransformMatrix::operator/=(const double& t)
434 {
435     for (int i = 0; i < 3; i++)
436         for (int j = 0; j < 3; j++)
437             m_matrix[i][j]/= t;
438     m_isIdentity = IsIdentity1();
439     return *this;
440 }
441
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
451 wxTransformMatrix& wxTransformMatrix::operator-=(const wxTransformMatrix& mat)
452 {
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();
457     return *this;
458 }
459
460 wxTransformMatrix& wxTransformMatrix::operator*=(const wxTransformMatrix& mat)
461 {
462
463     if (mat.m_isIdentity)
464         return *this;
465     if (m_isIdentity)
466     {
467         *this = mat;
468         return *this;
469     }
470     else
471     {
472         wxTransformMatrix  result;
473         for (int i = 0; i < 3; i++)
474         {
475            for (int j = 0; j < 3; j++)
476            {
477                double sum = 0;
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;
481            }
482         }
483         *this = result;
484     }
485
486     m_isIdentity = IsIdentity1();
487     return *this;
488 }
489
490
491 // constant operators
492 wxTransformMatrix  wxTransformMatrix::operator*(const double& t) const
493 {
494     wxTransformMatrix result = *this;
495     result *= t;
496     result.m_isIdentity = result.IsIdentity1();
497     return result;
498 }
499
500 wxTransformMatrix  wxTransformMatrix::operator/(const double& t) const
501 {
502     wxTransformMatrix result = *this;
503 //    wxASSERT(t!=0);
504     result /= t;
505     result.m_isIdentity = result.IsIdentity1();
506     return result;
507 }
508
509 wxTransformMatrix  wxTransformMatrix::operator+(const wxTransformMatrix& m) const
510 {
511     wxTransformMatrix result = *this;
512     result += m;
513     result.m_isIdentity = result.IsIdentity1();
514     return result;
515 }
516
517 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
526 wxTransformMatrix  wxTransformMatrix::operator*(const wxTransformMatrix& m) const
527 {
528     wxTransformMatrix result = *this;
529     result *= m;
530     result.m_isIdentity = result.IsIdentity1();
531     return result;
532 }
533
534
535 wxTransformMatrix  wxTransformMatrix::operator-() const
536 {
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();
542     return result;
543 }
544
545 static double CheckInt(double getal)
546 {
547     // check if the number is very close to an integer
548     if ( (ceil(getal) - getal) < 0.0001)
549         return ceil(getal);
550
551     else if ( (getal - floor(getal)) < 0.0001)
552         return floor(getal);
553
554     return getal;
555
556 }
557
558 double wxTransformMatrix::Get_scaleX()
559 {
560     double scale_factor;
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);
564     else
565         scale_factor = m_matrix[0][0]/sin((rot_angle/180)*pi);  // er kan nl. niet door 0 gedeeld worden !
566
567     scale_factor = CheckInt(scale_factor);
568     if (scale_factor < 0)
569         scale_factor = -scale_factor;
570
571     return scale_factor;
572 }
573
574 double wxTransformMatrix::Get_scaleY()
575 {
576     double scale_factor;
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);
580     else
581        scale_factor = m_matrix[1][1]/sin((rot_angle/180)*pi);   // er kan nl. niet door 0 gedeeld worden !
582
583     scale_factor = CheckInt(scale_factor);
584     if (scale_factor < 0)
585
586         scale_factor = -scale_factor;
587
588     return scale_factor;
589
590 }
591
592 double wxTransformMatrix::GetRotation()
593 {
594     double temp1 = GetValue(0,0);   // for angle calculation
595     double temp2 = GetValue(0,1);   //
596
597     // Rotation
598     double rot_angle = atan2(temp2,temp1)*180/pi;
599
600     rot_angle = CheckInt(rot_angle);
601     return rot_angle;
602 }
603
604 void wxTransformMatrix::SetRotation(double rotation)
605 {
606     double x=GetValue(2,0);
607     double y=GetValue(2,1);
608     Rotate(-GetRotation(), x, y);
609     Rotate(rotation, x, y);
610 }
611