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