]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/matrix.cpp
Fix ribbon documentation warnings.
[wxWidgets.git] / src / common / matrix.cpp
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/common/matrix.cpp
3// Purpose: wxTransformMatrix class
4// Author: Chris Breeze, Julian Smart
5// Modified by: Klaas Holwerda
6// Created: 01/02/97
7// Copyright: (c) Julian Smart
8// Licence: wxWindows licence
9///////////////////////////////////////////////////////////////////////////////
10
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__
18 #pragma hdrstop
19#endif
20
21#include "wx/matrix.h"
22
23#ifndef WX_PRECOMP
24 #include "wx/math.h"
25#endif
26
27static const double pi = M_PI;
28
29wxTransformMatrix::wxTransformMatrix(void)
30{
31 m_isIdentity = false;
32
33 Identity();
34}
35
36wxTransformMatrix::wxTransformMatrix(const wxTransformMatrix& mat)
37 : wxObject()
38{
39 (*this) = mat;
40}
41
42double wxTransformMatrix::GetValue(int col, int row) const
43{
44 if (row < 0 || row > 2 || col < 0 || col > 2)
45 return 0.0;
46
47 return m_matrix[col][row];
48}
49
50void wxTransformMatrix::SetValue(int col, int row, double value)
51{
52 if (row < 0 || row > 2 || col < 0 || col > 2)
53 return;
54
55 m_matrix[col][row] = value;
56 m_isIdentity = IsIdentity1();
57}
58
59void wxTransformMatrix::operator = (const wxTransformMatrix& mat)
60{
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;
70}
71
72bool wxTransformMatrix::operator == (const wxTransformMatrix& mat) const
73{
74 if (m_isIdentity && mat.m_isIdentity)
75 return true;
76
77 int i, j;
78 for (i = 0; i < 3; i++)
79 {
80 for (j = 0; j < 3; j++)
81 {
82 if ( !wxIsSameDouble(m_matrix[i][j], mat.m_matrix[i][j]) )
83 return false;
84 }
85 }
86 return true;
87}
88
89bool wxTransformMatrix::operator != (const wxTransformMatrix& mat) const
90{
91 return (! ((*this) == mat));
92}
93
94double& wxTransformMatrix::operator()(int col, int row)
95{
96 if (row < 0 || row > 2 || col < 0 || col > 2)
97 return m_matrix[0][0];
98
99 return m_matrix[col][row];
100}
101
102double wxTransformMatrix::operator()(int col, int row) const
103{
104 if (row < 0 || row > 2 || col < 0 || col > 2)
105 return 0.0;
106
107 return m_matrix[col][row];
108}
109
110// Invert matrix
111bool wxTransformMatrix::Invert(void)
112{
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];
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;
136
137 for (int i = 0; i < 3; i++)
138 {
139 for (int j = 0; j < 3; j++)
140 {
141 m_matrix[i][j] = inverseMatrix[i][j];
142 }
143 }
144 m_isIdentity = IsIdentity1();
145 return true;
146}
147
148// Make into identity matrix
149bool wxTransformMatrix::Identity(void)
150{
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;
153 m_isIdentity = true;
154
155 return true;
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{
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
175 return true;
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 {
191 double tx = xc*(1-xs);
192 double ty = yc*(1-ys);
193 r00 = xs;
194 r10 = 0;
195 r20 = tx;
196 r01 = 0;
197 r11 = ys;
198 r21 = ty;
199 }
200 else if ( !wxIsNullDouble(xc) || !wxIsNullDouble(yc) )
201 {
202 double tx = xc*(1-xs);
203 double ty = yc*(1-ys);
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
249
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;
261 temp.m_isIdentity=false;
262 }
263 if (y)
264 {
265 temp.m_matrix[0][0] = -1;
266 temp.m_isIdentity=false;
267 }
268
269 *this = temp * (*this);
270 m_isIdentity = IsIdentity1();
271 return *this;
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{
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];
286
287 m_isIdentity = IsIdentity1();
288
289 return true;
290}
291
292// Rotate clockwise by the given number of degrees:
293// | cos sin 0 |
294// matrix' = | -sin cos 0 | x matrix
295// | 0 0 1 |
296bool wxTransformMatrix::Rotate(double degrees)
297{
298 Rotate(-degrees,0,0);
299 return true;
300}
301
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 {
316 double tx = x*(1-c)+y*s;
317 double ty = y*(1-c)-x*s;
318 r00 = c ;
319 r10 = -s;
320 r20 = tx;
321 r01 = s;
322 r11 = c;
323 r21 = ty;
324 }
325 else if ( !wxIsNullDouble(x) || !wxIsNullDouble(y) )
326 {
327 double tx = x*(1-c)+y*s;
328 double ty = y*(1-c)-x*s;
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;
370}
371
372// Transform a point from logical to device coordinates
373bool wxTransformMatrix::TransformPoint(double x, double y, double& tx, double& ty) const
374{
375 if (IsIdentity())
376 {
377 tx = x; ty = y; return true;
378 }
379
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];
382
383 return true;
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.
396bool wxTransformMatrix::InverseTransformPoint(double x, double y, double& tx, double& ty) const
397{
398 if (IsIdentity())
399 {
400 tx = x;
401 ty = y;
402 return true;
403 }
404
405 const double z = (1.0 - m_matrix[0][2] * x - m_matrix[1][2] * y) / m_matrix[2][2];
406 if ( wxIsNullDouble(z) )
407 return false;
408
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];
411 return true;
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);
552 if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) )
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);
568 if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) )
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);
600}