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