]> git.saurik.com Git - wxWidgets.git/blame - src/common/matrix.cpp
Make mouse capture checking asserts stronger and more detailed.
[wxWidgets.git] / src / common / matrix.cpp
CommitLineData
311765c2 1///////////////////////////////////////////////////////////////////////////////
8898456d 2// Name: src/common/matrix.cpp
c801d85f
KB
3// Purpose: wxTransformMatrix class
4// Author: Chris Breeze, Julian Smart
513abb88 5// Modified by: Klaas Holwerda
c801d85f 6// Created: 01/02/97
55d99c7a 7// Copyright: (c) Julian Smart
65571936 8// Licence: wxWindows licence
311765c2 9///////////////////////////////////////////////////////////////////////////////
c801d85f 10
c801d85f
KB
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__
18680f86 18 #pragma hdrstop
c801d85f
KB
19#endif
20
18680f86
WS
21#include "wx/matrix.h"
22
c801d85f 23#ifndef WX_PRECOMP
8898456d 24 #include "wx/math.h"
c801d85f
KB
25#endif
26
e0d31471 27static const double pi = M_PI;
c801d85f
KB
28
29wxTransformMatrix::wxTransformMatrix(void)
30{
4e32eea1 31 m_isIdentity = false;
c801d85f 32
513abb88 33 Identity();
c801d85f
KB
34}
35
36wxTransformMatrix::wxTransformMatrix(const wxTransformMatrix& mat)
1b0674f7 37 : wxObject()
c801d85f 38{
513abb88 39 (*this) = mat;
c801d85f
KB
40}
41
513abb88 42double wxTransformMatrix::GetValue(int col, int row) const
c801d85f 43{
513abb88
RR
44 if (row < 0 || row > 2 || col < 0 || col > 2)
45 return 0.0;
c801d85f 46
513abb88 47 return m_matrix[col][row];
c801d85f
KB
48}
49
513abb88 50void wxTransformMatrix::SetValue(int col, int row, double value)
c801d85f 51{
513abb88
RR
52 if (row < 0 || row > 2 || col < 0 || col > 2)
53 return;
c801d85f 54
513abb88
RR
55 m_matrix[col][row] = value;
56 m_isIdentity = IsIdentity1();
c801d85f
KB
57}
58
59void wxTransformMatrix::operator = (const wxTransformMatrix& mat)
60{
513abb88
RR
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;
c801d85f
KB
70}
71
fbfb8bcc 72bool wxTransformMatrix::operator == (const wxTransformMatrix& mat) const
c801d85f 73{
d0ee33f5 74 if (m_isIdentity && mat.m_isIdentity)
4e32eea1 75 return true;
513abb88
RR
76
77 int i, j;
78 for (i = 0; i < 3; i++)
79 {
80 for (j = 0; j < 3; j++)
81 {
c77a6796 82 if ( !wxIsSameDouble(m_matrix[i][j], mat.m_matrix[i][j]) )
4e32eea1 83 return false;
513abb88
RR
84 }
85 }
4e32eea1 86 return true;
c801d85f
KB
87}
88
fbfb8bcc 89bool wxTransformMatrix::operator != (const wxTransformMatrix& mat) const
c801d85f 90{
513abb88 91 return (! ((*this) == mat));
c801d85f
KB
92}
93
513abb88 94double& wxTransformMatrix::operator()(int col, int row)
c801d85f 95{
513abb88
RR
96 if (row < 0 || row > 2 || col < 0 || col > 2)
97 return m_matrix[0][0];
c801d85f 98
513abb88 99 return m_matrix[col][row];
c801d85f
KB
100}
101
513abb88 102double wxTransformMatrix::operator()(int col, int row) const
c801d85f 103{
513abb88
RR
104 if (row < 0 || row > 2 || col < 0 || col > 2)
105 return 0.0;
c801d85f 106
513abb88 107 return m_matrix[col][row];
c801d85f
KB
108}
109
110// Invert matrix
111bool wxTransformMatrix::Invert(void)
112{
513abb88
RR
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];
c77a6796
VZ
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;
513abb88 136
c77a6796
VZ
137 for (int i = 0; i < 3; i++)
138 {
139 for (int j = 0; j < 3; j++)
513abb88 140 {
c77a6796 141 m_matrix[i][j] = inverseMatrix[i][j];
513abb88 142 }
513abb88 143 }
c77a6796
VZ
144 m_isIdentity = IsIdentity1();
145 return true;
c801d85f
KB
146}
147
148// Make into identity matrix
149bool wxTransformMatrix::Identity(void)
150{
513abb88
RR
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;
4e32eea1 153 m_isIdentity = true;
c801d85f 154
4e32eea1 155 return true;
c801d85f
KB
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//
163bool wxTransformMatrix::Scale(double scale)
164{
513abb88
RR
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
4e32eea1 175 return true;
513abb88
RR
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//
185wxTransformMatrix& 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 {
c77a6796
VZ
191 double tx = xc*(1-xs);
192 double ty = yc*(1-ys);
513abb88
RR
193 r00 = xs;
194 r10 = 0;
195 r20 = tx;
196 r01 = 0;
197 r11 = ys;
198 r21 = ty;
199 }
c77a6796 200 else if ( !wxIsNullDouble(xc) || !wxIsNullDouble(yc) )
513abb88 201 {
c77a6796
VZ
202 double tx = xc*(1-xs);
203 double ty = yc*(1-ys);
513abb88
RR
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
c801d85f 249
513abb88
RR
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
255wxTransformMatrix& wxTransformMatrix::Mirror(bool x, bool y)
256{
257 wxTransformMatrix temp;
258 if (x)
259 {
260 temp.m_matrix[1][1] = -1;
4e32eea1 261 temp.m_isIdentity=false;
513abb88
RR
262 }
263 if (y)
264 {
265 temp.m_matrix[0][0] = -1;
4e32eea1 266 temp.m_isIdentity=false;
513abb88
RR
267 }
268
269 *this = temp * (*this);
270 m_isIdentity = IsIdentity1();
271 return *this;
c801d85f
KB
272}
273
274// Translate by dx, dy:
275// | 1 0 dx |
276// matrix' = | 0 1 dy | x matrix
277// | 0 0 1 |
278//
279bool wxTransformMatrix::Translate(double dx, double dy)
280{
513abb88
RR
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];
c801d85f 286
513abb88 287 m_isIdentity = IsIdentity1();
c801d85f 288
4e32eea1 289 return true;
c801d85f
KB
290}
291
513abb88 292// Rotate clockwise by the given number of degrees:
c801d85f
KB
293// | cos sin 0 |
294// matrix' = | -sin cos 0 | x matrix
295// | 0 0 1 |
c801d85f
KB
296bool wxTransformMatrix::Rotate(double degrees)
297{
513abb88 298 Rotate(-degrees,0,0);
4e32eea1 299 return true;
513abb88 300}
c801d85f 301
513abb88
RR
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
307wxTransformMatrix& 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 {
c77a6796
VZ
316 double tx = x*(1-c)+y*s;
317 double ty = y*(1-c)-x*s;
513abb88
RR
318 r00 = c ;
319 r10 = -s;
320 r20 = tx;
321 r01 = s;
322 r11 = c;
323 r21 = ty;
324 }
c77a6796 325 else if ( !wxIsNullDouble(x) || !wxIsNullDouble(y) )
513abb88 326 {
c77a6796
VZ
327 double tx = x*(1-c)+y*s;
328 double ty = y*(1-c)-x*s;
513abb88
RR
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;
c801d85f
KB
370}
371
372// Transform a point from logical to device coordinates
373bool wxTransformMatrix::TransformPoint(double x, double y, double& tx, double& ty) const
374{
513abb88
RR
375 if (IsIdentity())
376 {
4e32eea1 377 tx = x; ty = y; return true;
513abb88 378 }
c801d85f 379
513abb88
RR
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];
c801d85f 382
4e32eea1 383 return true;
c801d85f
KB
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.
c801d85f
KB
396bool wxTransformMatrix::InverseTransformPoint(double x, double y, double& tx, double& ty) const
397{
513abb88
RR
398 if (IsIdentity())
399 {
c77a6796
VZ
400 tx = x;
401 ty = y;
402 return true;
513abb88
RR
403 }
404
c77a6796
VZ
405 const double z = (1.0 - m_matrix[0][2] * x - m_matrix[1][2] * y) / m_matrix[2][2];
406 if ( wxIsNullDouble(z) )
4e32eea1 407 return false;
c77a6796 408
513abb88
RR
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];
4e32eea1 411 return true;
513abb88
RR
412}
413
414wxTransformMatrix& 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
423wxTransformMatrix& 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
432wxTransformMatrix& 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
441wxTransformMatrix& 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
450wxTransformMatrix& 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
482wxTransformMatrix 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
490wxTransformMatrix 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
499wxTransformMatrix 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
507wxTransformMatrix 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
516wxTransformMatrix 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
525wxTransformMatrix 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
535static 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
548double wxTransformMatrix::Get_scaleX()
549{
550 double scale_factor;
551 double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi);
c77a6796 552 if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) )
513abb88
RR
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
564double wxTransformMatrix::Get_scaleY()
565{
566 double scale_factor;
567 double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi);
c77a6796 568 if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) )
513abb88
RR
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
582double 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
594void 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);
c801d85f 600}