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