Files
wxWidgets/src/common/matrix.cpp
Vadim Zeitlin fcc0e48ade Deprecate wxTransformMatrix to prepare for its removal later
This class is redundant with wxAffineMatrix2D, which is actually used by
the library itself and documented, so it gets to stay, while this one is
scheduled for removal.

Closes https://github.com/wxWidgets/wxWidgets/pull/2083

Closes #13114.
2020-10-16 02:03:38 +02:00

602 lines
15 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: src/common/matrix.cpp
// Purpose: wxTransformMatrix class
// Author: Chris Breeze, Julian Smart
// Modified by: Klaas Holwerda
// Created: 01/02/97
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// Note: this is intended to be used in wxDC at some point to replace
// the current system of scaling/translation. It is not yet used.
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#if WXWIN_COMPATIBILITY_3_0
#include "wx/matrix.h"
#ifndef WX_PRECOMP
#include "wx/math.h"
#endif
static const double pi = M_PI;
wxTransformMatrix::wxTransformMatrix()
{
m_isIdentity = false;
Identity();
}
wxTransformMatrix::wxTransformMatrix(const wxTransformMatrix& mat)
: wxObject()
{
(*this) = mat;
}
double wxTransformMatrix::GetValue(int col, int row) const
{
if (row < 0 || row > 2 || col < 0 || col > 2)
return 0.0;
return m_matrix[col][row];
}
void wxTransformMatrix::SetValue(int col, int row, double value)
{
if (row < 0 || row > 2 || col < 0 || col > 2)
return;
m_matrix[col][row] = value;
m_isIdentity = IsIdentity1();
}
void wxTransformMatrix::operator = (const wxTransformMatrix& mat)
{
int i, j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
m_matrix[i][j] = mat.m_matrix[i][j];
}
}
m_isIdentity = mat.m_isIdentity;
}
bool wxTransformMatrix::operator == (const wxTransformMatrix& mat) const
{
if (m_isIdentity && mat.m_isIdentity)
return true;
int i, j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
if ( !wxIsSameDouble(m_matrix[i][j], mat.m_matrix[i][j]) )
return false;
}
}
return true;
}
bool wxTransformMatrix::operator != (const wxTransformMatrix& mat) const
{
return (! ((*this) == mat));
}
double& wxTransformMatrix::operator()(int col, int row)
{
if (row < 0 || row > 2 || col < 0 || col > 2)
return m_matrix[0][0];
return m_matrix[col][row];
}
double wxTransformMatrix::operator()(int col, int row) const
{
if (row < 0 || row > 2 || col < 0 || col > 2)
return 0.0;
return m_matrix[col][row];
}
// Invert matrix
bool wxTransformMatrix::Invert()
{
double inverseMatrix[3][3];
// calculate the adjoint
inverseMatrix[0][0] = wxCalculateDet(m_matrix[1][1],m_matrix[2][1],m_matrix[1][2],m_matrix[2][2]);
inverseMatrix[0][1] = -wxCalculateDet(m_matrix[0][1],m_matrix[2][1],m_matrix[0][2],m_matrix[2][2]);
inverseMatrix[0][2] = wxCalculateDet(m_matrix[0][1],m_matrix[1][1],m_matrix[0][2],m_matrix[1][2]);
inverseMatrix[1][0] = -wxCalculateDet(m_matrix[1][0],m_matrix[2][0],m_matrix[1][2],m_matrix[2][2]);
inverseMatrix[1][1] = wxCalculateDet(m_matrix[0][0],m_matrix[2][0],m_matrix[0][2],m_matrix[2][2]);
inverseMatrix[1][2] = -wxCalculateDet(m_matrix[0][0],m_matrix[1][0],m_matrix[0][2],m_matrix[1][2]);
inverseMatrix[2][0] = wxCalculateDet(m_matrix[1][0],m_matrix[2][0],m_matrix[1][1],m_matrix[2][1]);
inverseMatrix[2][1] = -wxCalculateDet(m_matrix[0][0],m_matrix[2][0],m_matrix[0][1],m_matrix[2][1]);
inverseMatrix[2][2] = wxCalculateDet(m_matrix[0][0],m_matrix[1][0],m_matrix[0][1],m_matrix[1][1]);
// now divide by the determinant
double det = m_matrix[0][0] * inverseMatrix[0][0] + m_matrix[0][1] * inverseMatrix[1][0] + m_matrix[0][2] * inverseMatrix[2][0];
if ( wxIsNullDouble(det) )
return false;
inverseMatrix[0][0] /= det; inverseMatrix[1][0] /= det; inverseMatrix[2][0] /= det;
inverseMatrix[0][1] /= det; inverseMatrix[1][1] /= det; inverseMatrix[2][1] /= det;
inverseMatrix[0][2] /= det; inverseMatrix[1][2] /= det; inverseMatrix[2][2] /= det;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
m_matrix[i][j] = inverseMatrix[i][j];
}
}
m_isIdentity = IsIdentity1();
return true;
}
// Make into identity matrix
bool wxTransformMatrix::Identity()
{
m_matrix[0][0] = m_matrix[1][1] = m_matrix[2][2] = 1.0;
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;
m_isIdentity = true;
return true;
}
// Scale by scale (isotropic scaling i.e. the same in x and y):
// | scale 0 0 |
// matrix' = | 0 scale 0 | x matrix
// | 0 0 scale |
//
bool wxTransformMatrix::Scale(double scale)
{
int i, j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
m_matrix[i][j] *= scale;
}
}
m_isIdentity = IsIdentity1();
return true;
}
// scale a matrix in 2D
//
// xs 0 xc(1-xs)
// 0 ys yc(1-ys)
// 0 0 1
//
wxTransformMatrix& wxTransformMatrix::Scale(const double &xs, const double &ys,const double &xc, const double &yc)
{
double r00,r10,r20,r01,r11,r21;
if (m_isIdentity)
{
double tx = xc*(1-xs);
double ty = yc*(1-ys);
r00 = xs;
r10 = 0;
r20 = tx;
r01 = 0;
r11 = ys;
r21 = ty;
}
else if ( !wxIsNullDouble(xc) || !wxIsNullDouble(yc) )
{
double tx = xc*(1-xs);
double ty = yc*(1-ys);
r00 = xs * m_matrix[0][0];
r10 = xs * m_matrix[1][0];
r20 = xs * m_matrix[2][0] + tx;
r01 = ys * m_matrix[0][1];
r11 = ys * m_matrix[1][1];
r21 = ys * m_matrix[2][1] + ty;
}
else
{
r00 = xs * m_matrix[0][0];
r10 = xs * m_matrix[1][0];
r20 = xs * m_matrix[2][0];
r01 = ys * m_matrix[0][1];
r11 = ys * m_matrix[1][1];
r21 = ys * m_matrix[2][1];
}
m_matrix[0][0] = r00;
m_matrix[1][0] = r10;
m_matrix[2][0] = r20;
m_matrix[0][1] = r01;
m_matrix[1][1] = r11;
m_matrix[2][1] = r21;
/* or like this
// first translate to origin O
(*this).Translate(-x_cen, -y_cen);
// now do the scaling
wxTransformMatrix scale;
scale.m_matrix[0][0] = x_fac;
scale.m_matrix[1][1] = y_fac;
scale.m_isIdentity = IsIdentity1();
*this = scale * (*this);
// translate back from origin to x_cen, y_cen
(*this).Translate(x_cen, y_cen);
*/
m_isIdentity = IsIdentity1();
return *this;
}
// mirror a matrix in x, y
//
// -1 0 0 Y-mirror
// 0 -1 0 X-mirror
// 0 0 -1 Z-mirror
wxTransformMatrix& wxTransformMatrix::Mirror(bool x, bool y)
{
wxTransformMatrix temp;
if (x)
{
temp.m_matrix[1][1] = -1;
temp.m_isIdentity=false;
}
if (y)
{
temp.m_matrix[0][0] = -1;
temp.m_isIdentity=false;
}
*this = temp * (*this);
m_isIdentity = IsIdentity1();
return *this;
}
// Translate by dx, dy:
// | 1 0 dx |
// matrix' = | 0 1 dy | x matrix
// | 0 0 1 |
//
bool wxTransformMatrix::Translate(double dx, double dy)
{
int i;
for (i = 0; i < 3; i++)
m_matrix[i][0] += dx * m_matrix[i][2];
for (i = 0; i < 3; i++)
m_matrix[i][1] += dy * m_matrix[i][2];
m_isIdentity = IsIdentity1();
return true;
}
// Rotate clockwise by the given number of degrees:
// | cos sin 0 |
// matrix' = | -sin cos 0 | x matrix
// | 0 0 1 |
bool wxTransformMatrix::Rotate(double degrees)
{
Rotate(-degrees,0,0);
return true;
}
// counter clockwise rotate around a point
//
// cos(r) -sin(r) x(1-cos(r))+y(sin(r)
// sin(r) cos(r) y(1-cos(r))-x(sin(r)
// 0 0 1
wxTransformMatrix& wxTransformMatrix::Rotate(const double &degrees, const double &x, const double &y)
{
double angle = degrees * pi / 180.0;
double c = cos(angle);
double s = sin(angle);
double r00,r10,r20,r01,r11,r21;
if (m_isIdentity)
{
double tx = x*(1-c)+y*s;
double ty = y*(1-c)-x*s;
r00 = c ;
r10 = -s;
r20 = tx;
r01 = s;
r11 = c;
r21 = ty;
}
else if ( !wxIsNullDouble(x) || !wxIsNullDouble(y) )
{
double tx = x*(1-c)+y*s;
double ty = y*(1-c)-x*s;
r00 = c * m_matrix[0][0] - s * m_matrix[0][1] + tx * m_matrix[0][2];
r10 = c * m_matrix[1][0] - s * m_matrix[1][1] + tx * m_matrix[1][2];
r20 = c * m_matrix[2][0] - s * m_matrix[2][1] + tx;// * m_matrix[2][2];
r01 = c * m_matrix[0][1] + s * m_matrix[0][0] + ty * m_matrix[0][2];
r11 = c * m_matrix[1][1] + s * m_matrix[1][0] + ty * m_matrix[1][2];
r21 = c * m_matrix[2][1] + s * m_matrix[2][0] + ty;// * m_matrix[2][2];
}
else
{
r00 = c * m_matrix[0][0] - s * m_matrix[0][1];
r10 = c * m_matrix[1][0] - s * m_matrix[1][1];
r20 = c * m_matrix[2][0] - s * m_matrix[2][1];
r01 = c * m_matrix[0][1] + s * m_matrix[0][0];
r11 = c * m_matrix[1][1] + s * m_matrix[1][0];
r21 = c * m_matrix[2][1] + s * m_matrix[2][0];
}
m_matrix[0][0] = r00;
m_matrix[1][0] = r10;
m_matrix[2][0] = r20;
m_matrix[0][1] = r01;
m_matrix[1][1] = r11;
m_matrix[2][1] = r21;
/* or like this
wxTransformMatrix rotate;
rotate.m_matrix[2][0] = tx;
rotate.m_matrix[2][1] = ty;
rotate.m_matrix[0][0] = c;
rotate.m_matrix[0][1] = s;
rotate.m_matrix[1][0] = -s;
rotate.m_matrix[1][1] = c;
rotate.m_isIdentity=false;
*this = rotate * (*this);
*/
m_isIdentity = IsIdentity1();
return *this;
}
// Transform a point from logical to device coordinates
bool wxTransformMatrix::TransformPoint(double x, double y, double& tx, double& ty) const
{
if (IsIdentity())
{
tx = x; ty = y; return true;
}
tx = x * m_matrix[0][0] + y * m_matrix[1][0] + m_matrix[2][0];
ty = x * m_matrix[0][1] + y * m_matrix[1][1] + m_matrix[2][1];
return true;
}
// Transform a point from device to logical coordinates.
// Example of use:
// wxTransformMatrix mat = dc.GetTransformation();
// mat.Invert();
// mat.InverseTransformPoint(x, y, x1, y1);
// OR (shorthand:)
// dc.LogicalToDevice(x, y, x1, y1);
// The latter is slightly less efficient if we're doing several
// conversions, since the matrix is inverted several times.
bool wxTransformMatrix::InverseTransformPoint(double x, double y, double& tx, double& ty) const
{
if (IsIdentity())
{
tx = x;
ty = y;
return true;
}
const double z = (1.0 - m_matrix[0][2] * x - m_matrix[1][2] * y) / m_matrix[2][2];
if ( wxIsNullDouble(z) )
return false;
tx = x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0];
ty = x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1];
return true;
}
wxTransformMatrix& wxTransformMatrix::operator*=(const double& t)
{
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
m_matrix[i][j]*= t;
m_isIdentity = IsIdentity1();
return *this;
}
wxTransformMatrix& wxTransformMatrix::operator/=(const double& t)
{
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
m_matrix[i][j]/= t;
m_isIdentity = IsIdentity1();
return *this;
}
wxTransformMatrix& wxTransformMatrix::operator+=(const wxTransformMatrix& mat)
{
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
m_matrix[i][j] += mat.m_matrix[i][j];
m_isIdentity = IsIdentity1();
return *this;
}
wxTransformMatrix& wxTransformMatrix::operator-=(const wxTransformMatrix& mat)
{
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
m_matrix[i][j] -= mat.m_matrix[i][j];
m_isIdentity = IsIdentity1();
return *this;
}
wxTransformMatrix& wxTransformMatrix::operator*=(const wxTransformMatrix& mat)
{
if (mat.m_isIdentity)
return *this;
if (m_isIdentity)
{
*this = mat;
return *this;
}
else
{
wxTransformMatrix result;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
double sum = 0;
for (int k = 0; k < 3; k++)
sum += m_matrix[k][i] * mat.m_matrix[j][k];
result.m_matrix[j][i] = sum;
}
}
*this = result;
}
m_isIdentity = IsIdentity1();
return *this;
}
// constant operators
wxTransformMatrix wxTransformMatrix::operator*(const double& t) const
{
wxTransformMatrix result = *this;
result *= t;
result.m_isIdentity = result.IsIdentity1();
return result;
}
wxTransformMatrix wxTransformMatrix::operator/(const double& t) const
{
wxTransformMatrix result = *this;
// wxASSERT(t!=0);
result /= t;
result.m_isIdentity = result.IsIdentity1();
return result;
}
wxTransformMatrix wxTransformMatrix::operator+(const wxTransformMatrix& m) const
{
wxTransformMatrix result = *this;
result += m;
result.m_isIdentity = result.IsIdentity1();
return result;
}
wxTransformMatrix wxTransformMatrix::operator-(const wxTransformMatrix& m) const
{
wxTransformMatrix result = *this;
result -= m;
result.m_isIdentity = result.IsIdentity1();
return result;
}
wxTransformMatrix wxTransformMatrix::operator*(const wxTransformMatrix& m) const
{
wxTransformMatrix result = *this;
result *= m;
result.m_isIdentity = result.IsIdentity1();
return result;
}
wxTransformMatrix wxTransformMatrix::operator-() const
{
wxTransformMatrix result = *this;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
result.m_matrix[i][j] = -(this->m_matrix[i][j]);
result.m_isIdentity = result.IsIdentity1();
return result;
}
static double CheckInt(double getal)
{
// check if the number is very close to an integer
if ( (ceil(getal) - getal) < 0.0001)
return ceil(getal);
else if ( (getal - floor(getal)) < 0.0001)
return floor(getal);
return getal;
}
double wxTransformMatrix::Get_scaleX()
{
double scale_factor;
double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi);
if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) )
scale_factor = m_matrix[0][0]/cos((rot_angle/180)*pi);
else
scale_factor = m_matrix[0][0]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden !
scale_factor = CheckInt(scale_factor);
if (scale_factor < 0)
scale_factor = -scale_factor;
return scale_factor;
}
double wxTransformMatrix::Get_scaleY()
{
double scale_factor;
double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi);
if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) )
scale_factor = m_matrix[1][1]/cos((rot_angle/180)*pi);
else
scale_factor = m_matrix[1][1]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden !
scale_factor = CheckInt(scale_factor);
if (scale_factor < 0)
scale_factor = -scale_factor;
return scale_factor;
}
double wxTransformMatrix::GetRotation()
{
double temp1 = GetValue(0,0); // for angle calculation
double temp2 = GetValue(0,1); //
// Rotation
double rot_angle = atan2(temp2,temp1)*180/pi;
rot_angle = CheckInt(rot_angle);
return rot_angle;
}
void wxTransformMatrix::SetRotation(double rotation)
{
double x=GetValue(2,0);
double y=GetValue(2,1);
Rotate(-GetRotation(), x, y);
Rotate(rotation, x, y);
}
#endif // WXWIN_COMPATIBILITY_3_0