]> git.saurik.com Git - wxWidgets.git/blob - src/common/matrix.cpp
Improve wxCheckListBox appearance under Vista/Win7.
[wxWidgets.git] / src / common / matrix.cpp
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$
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
30 wxTransformMatrix::wxTransformMatrix(void)
31 {
32 m_isIdentity = false;
33
34 Identity();
35 }
36
37 wxTransformMatrix::wxTransformMatrix(const wxTransformMatrix& mat)
38 : wxObject()
39 {
40 (*this) = mat;
41 }
42
43 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
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
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
73 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
90 bool wxTransformMatrix::operator != (const wxTransformMatrix& mat) const
91 {
92 return (! ((*this) == mat));
93 }
94
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
103 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
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
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 //
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 //
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
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 //
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 |
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
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
374 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.
397 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
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
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 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
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
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
483 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
491 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
500 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
508 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
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
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
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
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
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
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
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 }