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