326 lines
9.0 KiB
C++
326 lines
9.0 KiB
C++
/*
|
|
* (c) Copyright Ascensio System SIA 2010-2023
|
|
*
|
|
* This program is a free software product. You can redistribute it and/or
|
|
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
|
* version 3 as published by the Free Software Foundation. In accordance with
|
|
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
|
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
|
* of any third-party rights.
|
|
*
|
|
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
|
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
|
*
|
|
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
|
|
* street, Riga, Latvia, EU, LV-1050.
|
|
*
|
|
* The interactive user interfaces in modified source and object code versions
|
|
* of the Program must display Appropriate Legal Notices, as required under
|
|
* Section 5 of the GNU AGPL version 3.
|
|
*
|
|
* Pursuant to Section 7(b) of the License you must retain the original Product
|
|
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
|
* grant you any rights under trademark law for use of our trademarks.
|
|
*
|
|
* All the Product's GUI elements, including illustrations and icon sets, as
|
|
* well as technical writing content are licensed under the terms of the
|
|
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
|
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
|
*
|
|
*/
|
|
#include "Matrix_private.h"
|
|
|
|
namespace Aggplus
|
|
{
|
|
CMatrix::CMatrix(double m11, double m12, double m21, double m22, double dx, double dy)
|
|
{
|
|
m_internal = new CMatrix_private();
|
|
m_internal->m_agg_mtx.sx = m11;
|
|
m_internal->m_agg_mtx.shy = m12;
|
|
m_internal->m_agg_mtx.shx = m21;
|
|
m_internal->m_agg_mtx.sy = m22;
|
|
m_internal->m_agg_mtx.tx = dx;
|
|
m_internal->m_agg_mtx.ty = dy;
|
|
}
|
|
|
|
CMatrix::CMatrix(const CMatrix& oSrc)
|
|
{
|
|
m_internal = new CMatrix_private();
|
|
m_internal->m_agg_mtx = oSrc.m_internal->m_agg_mtx;
|
|
}
|
|
|
|
CMatrix::CMatrix()
|
|
{
|
|
m_internal = new CMatrix_private();
|
|
}
|
|
|
|
CMatrix::~CMatrix()
|
|
{
|
|
RELEASEOBJECT(m_internal);
|
|
}
|
|
|
|
void CMatrix::Translate(double offsetX, double offsetY, MatrixOrder order)
|
|
{
|
|
if (order == MatrixOrderPrepend)
|
|
{
|
|
m_internal->m_agg_mtx.premultiply(agg::trans_affine_translation(offsetX, offsetY));
|
|
}
|
|
else
|
|
{
|
|
m_internal->m_agg_mtx.multiply(agg::trans_affine_translation(offsetX, offsetY));
|
|
}
|
|
}
|
|
|
|
void CMatrix::Scale(double scaleX, double scaleY, MatrixOrder order)
|
|
{
|
|
if (order == MatrixOrderPrepend)
|
|
{
|
|
m_internal->m_agg_mtx.premultiply(agg::trans_affine_scaling(scaleX, scaleY));
|
|
}
|
|
else
|
|
{
|
|
m_internal->m_agg_mtx.multiply(agg::trans_affine_scaling(scaleX, scaleY));
|
|
}
|
|
}
|
|
|
|
void CMatrix::Shear(double shearX, double shearY, MatrixOrder order)
|
|
{
|
|
if (order == MatrixOrderPrepend)
|
|
{
|
|
m_internal->m_agg_mtx.premultiply(agg::trans_affine_skewing(shearX, shearY));
|
|
}
|
|
else
|
|
{
|
|
m_internal->m_agg_mtx.multiply(agg::trans_affine_skewing(shearX, shearY));
|
|
}
|
|
}
|
|
|
|
void CMatrix::TransformVectors(PointF* pts, int count) const
|
|
{
|
|
// Store matrix to an array [6] of double
|
|
double M[6]; m_internal->m_agg_mtx.store_to(M);
|
|
|
|
for (int i = 0; i < count; ++i)
|
|
{
|
|
double x = pts[i].X;
|
|
double y = pts[i].Y;
|
|
m_internal->m_agg_mtx.transform(&x, &y);
|
|
pts[i].X = (float)(x-M[4]);
|
|
pts[i].Y = (float)(y-M[5]);
|
|
}
|
|
}
|
|
|
|
void CMatrix::TransformPoints(PointF* pts, int count) const
|
|
{
|
|
for (int i = 0; i < count; ++i)
|
|
{
|
|
double x = pts[i].X;
|
|
double y = pts[i].Y;
|
|
m_internal->m_agg_mtx.transform(&x, &y);
|
|
pts[i].X = (float)x;
|
|
pts[i].Y = (float)y;
|
|
}
|
|
}
|
|
|
|
void CMatrix::TransformPoint(double& x, double& y) const
|
|
{
|
|
m_internal->m_agg_mtx.transform(&x, &y);
|
|
}
|
|
|
|
void CMatrix::Rotate(double angle, MatrixOrder order)
|
|
{
|
|
if (order == MatrixOrderPrepend)
|
|
{
|
|
m_internal->m_agg_mtx.premultiply(agg::trans_affine_rotation(agg::deg2rad(angle)));
|
|
}
|
|
else
|
|
{
|
|
m_internal->m_agg_mtx.multiply(agg::trans_affine_rotation(agg::deg2rad(angle)));
|
|
}
|
|
}
|
|
|
|
void CMatrix::RotateAt(double angle, const PointF ¢er, MatrixOrder order)
|
|
{
|
|
Translate(-center.X, -center.Y, order);
|
|
if(order == MatrixOrderPrepend)
|
|
{
|
|
m_internal->m_agg_mtx.premultiply(agg::trans_affine_rotation(agg::deg2rad(angle)));
|
|
}
|
|
else
|
|
{
|
|
m_internal->m_agg_mtx.multiply(agg::trans_affine_rotation(agg::deg2rad(angle)));
|
|
}
|
|
Translate(center.X, center.Y, order);
|
|
return;
|
|
}
|
|
|
|
void CMatrix::RotateAt(double angle, double x, double y, MatrixOrder order)
|
|
{
|
|
Translate(-x, -y, order);
|
|
if (order == MatrixOrderPrepend)
|
|
{
|
|
m_internal->m_agg_mtx.premultiply(agg::trans_affine_rotation(agg::deg2rad(angle)));
|
|
}
|
|
else
|
|
{
|
|
m_internal->m_agg_mtx.multiply(agg::trans_affine_rotation(agg::deg2rad(angle)));
|
|
}
|
|
Translate(x, y, order);
|
|
}
|
|
|
|
void CMatrix::Multiply(const CMatrix* matrix, MatrixOrder order)
|
|
{
|
|
if (order == MatrixOrderPrepend)
|
|
{
|
|
m_internal->m_agg_mtx.premultiply(matrix->m_internal->m_agg_mtx);
|
|
}
|
|
else
|
|
{
|
|
m_internal->m_agg_mtx.multiply(matrix->m_internal->m_agg_mtx);
|
|
}
|
|
}
|
|
|
|
double CMatrix::OffsetX() const
|
|
{
|
|
return m_internal->m_agg_mtx.tx;
|
|
}
|
|
double CMatrix::OffsetY() const
|
|
{
|
|
return m_internal->m_agg_mtx.ty;
|
|
}
|
|
|
|
double CMatrix::sx() const
|
|
{
|
|
return m_internal->m_agg_mtx.sx;
|
|
}
|
|
double CMatrix::sy() const
|
|
{
|
|
return m_internal->m_agg_mtx.sy;
|
|
}
|
|
double CMatrix::shx() const
|
|
{
|
|
return m_internal->m_agg_mtx.shx;
|
|
}
|
|
double CMatrix::shy() const
|
|
{
|
|
return m_internal->m_agg_mtx.shy;
|
|
}
|
|
double CMatrix::tx() const
|
|
{
|
|
return m_internal->m_agg_mtx.tx;
|
|
}
|
|
double CMatrix::ty() const
|
|
{
|
|
return m_internal->m_agg_mtx.ty;
|
|
}
|
|
double CMatrix::rotation()
|
|
{
|
|
return m_internal->m_agg_mtx.rotation();
|
|
}
|
|
|
|
|
|
void CMatrix::SetElements(const double& sx, const double& shy, const double& shx, const double& sy, const double& tx, const double& ty)
|
|
{
|
|
m_internal->m_agg_mtx.sx = sx;
|
|
m_internal->m_agg_mtx.shy = shy;
|
|
m_internal->m_agg_mtx.shx = shx;
|
|
m_internal->m_agg_mtx.sy = sy;
|
|
m_internal->m_agg_mtx.tx = tx;
|
|
m_internal->m_agg_mtx.ty = ty;
|
|
}
|
|
|
|
Status CMatrix::GetElements(REAL* m) const
|
|
{
|
|
double M[6]; m_internal->m_agg_mtx.store_to(M);
|
|
m[0]=(REAL)M[0];
|
|
m[1]=(REAL)M[1];
|
|
m[2]=(REAL)M[2];
|
|
m[3]=(REAL)M[3];
|
|
m[4]=(REAL)M[4];
|
|
m[5]=(REAL)M[5];
|
|
return Ok;
|
|
}
|
|
|
|
Status CMatrix::GetElements(double* m) const
|
|
{
|
|
m_internal->m_agg_mtx.store_to(m);
|
|
return Ok;
|
|
}
|
|
|
|
void CMatrix::Reset()
|
|
{
|
|
m_internal->m_agg_mtx.reset();
|
|
}
|
|
|
|
double CMatrix::Determinant() const
|
|
{
|
|
return m_internal->m_agg_mtx.determinant();
|
|
}
|
|
|
|
const CMatrix& CMatrix::operator=(const CMatrix& Src)
|
|
{
|
|
m_internal->m_agg_mtx = Src.m_internal->m_agg_mtx;
|
|
return *this;
|
|
}
|
|
|
|
Status CMatrix::Invert()
|
|
{
|
|
double d = m_internal->m_agg_mtx.determinant();
|
|
if (0.0001 >= fabs(d))
|
|
return InvalidParameter;
|
|
|
|
m_internal->m_agg_mtx.invert();
|
|
return Ok;
|
|
}
|
|
|
|
//Temp
|
|
//Used in X_BrushLinearGradient constructor
|
|
double CMatrix::z_Rotation() const
|
|
{
|
|
return agg::rad2deg(m_internal->m_agg_mtx.rotation());
|
|
}
|
|
|
|
void CMatrix::TransformPoints( PointF* dst, const PointF* src, int count ) const
|
|
{
|
|
agg::trans_affine& m = m_internal->m_agg_mtx;
|
|
for(int i = 0; i < count; ++i)
|
|
{
|
|
double x = src[i].X * m.sx + src[i].Y * m.shx + m.tx;
|
|
double y = src[i].Y * m.sy + src[i].X * m.shy + m.ty;
|
|
|
|
dst[i].X = (float)x;
|
|
dst[i].Y = (float)y;
|
|
}
|
|
}
|
|
|
|
bool CMatrix::IsIdentity(const double& eps) const
|
|
{
|
|
return m_internal->m_agg_mtx.is_identity(eps);
|
|
}
|
|
bool CMatrix::IsIdentity2(const double& eps) const
|
|
{
|
|
agg::trans_affine& m = m_internal->m_agg_mtx;
|
|
return agg::is_equal_eps(m.sx, 1.0, eps) &&
|
|
agg::is_equal_eps(m.shy, 0.0, eps) &&
|
|
agg::is_equal_eps(m.shx, 0.0, eps) &&
|
|
agg::is_equal_eps(m.sy, 1.0, eps);
|
|
}
|
|
|
|
bool CMatrix::IsEqual(const CMatrix* mm1, const CMatrix* mm2, const double& eps, bool bIsOnlyMain)
|
|
{
|
|
agg::trans_affine& m1 = mm1->m_internal->m_agg_mtx;
|
|
agg::trans_affine& m2 = mm2->m_internal->m_agg_mtx;
|
|
|
|
bool bMain = fabs(m1.sx - m2.sx) < eps &&
|
|
fabs(m1.sy - m2.sy) < eps &&
|
|
fabs(m1.shx - m2.shx) < eps &&
|
|
fabs(m1.shy - m2.shy) < eps;
|
|
|
|
if (!bMain || bIsOnlyMain)
|
|
return bMain;
|
|
|
|
return fabs(m1.tx - m2.tx) < eps && fabs(m1.ty - m2.ty) < eps;
|
|
}
|
|
}
|