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