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