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