/*
* gdiplusmatrix.h
*
* GDI+ Matrix class
*
* This file is part of the w32api package.
*
* Contributors:
* Created by Markus Koenig <markus@stber-koenig.de>
*
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* This source code is offered for use in the public domain. You may
* use, modify or distribute it freely.
*
* This code is distributed in the hope that it will be useful but
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
* DISCLAIMED. This includes but is not limited to warranties of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#ifndef __GDIPLUS_MATRIX_H
#define __GDIPLUS_MATRIX_H
#if __GNUC__ >=3
#pragma GCC system_header
#endif
#ifndef __cplusplus
#error "A C++ compiler is required to include gdiplusmatrix.h."
#endif
#define GDIP_MATRIX_PI \
3.1415926535897932384626433832795028841971693993751058209749445923078164
class Matrix: public GdiplusBase
{
friend class Graphics;
friend class GraphicsPath;
friend class LinearGradientBrush;
friend class PathGradientBrush;
friend class Pen;
friend class Region;
friend class TextureBrush;
public:
Matrix(): nativeMatrix(NULL), lastStatus(Ok)
{
lastStatus = DllExports::GdipCreateMatrix(&nativeMatrix);
}
Matrix(REAL m11, REAL m12, REAL m21, REAL m22, REAL dx, REAL dy):
nativeMatrix(NULL), lastStatus(Ok)
{
lastStatus = DllExports::GdipCreateMatrix2(
m11, m12, m21, m22, dx, dy,
&nativeMatrix);
}
Matrix(const RectF& rect, const PointF *dstplg):
nativeMatrix(NULL), lastStatus(Ok)
{
lastStatus = DllExports::GdipCreateMatrix3(
&rect, dstplg, &nativeMatrix);
}
Matrix(const Rect& rect, const Point *dstplg):
nativeMatrix(NULL), lastStatus(Ok)
{
lastStatus = DllExports::GdipCreateMatrix3I(
&rect, dstplg, &nativeMatrix);
}
~Matrix()
{
DllExports::GdipDeleteMatrix(nativeMatrix);
}
Matrix* Clone() const
{
GpMatrix *cloneMatrix = NULL;
Status status = updateStatus(DllExports::GdipCloneMatrix(
nativeMatrix, &cloneMatrix));
if (status == Ok) {
Matrix *result = new Matrix(cloneMatrix, lastStatus);
if (!result) {
DllExports::GdipDeleteMatrix(cloneMatrix);
lastStatus = OutOfMemory;
}
return result;
} else {
return NULL;
}
}
BOOL Equals(const Matrix *matrix) const
{
BOOL result;
updateStatus(DllExports::GdipIsMatrixEqual(
nativeMatrix,
matrix ? matrix->nativeMatrix : NULL, &result));
return result;
}
Status GetElements(REAL *m) const
{
return updateStatus(DllExports::GdipGetMatrixElements(
nativeMatrix, m));
}
Status GetLastStatus() const
{
Status result = lastStatus;
lastStatus = Ok;
return result;
}
Status Invert()
{
return updateStatus(DllExports::GdipInvertMatrix(nativeMatrix));
}
BOOL IsIdentity() const
{
BOOL result;
updateStatus(DllExports::GdipIsMatrixIdentity(
nativeMatrix, &result));
return result;
}
BOOL IsInvertible() const
{
BOOL result;
updateStatus(DllExports::GdipIsMatrixInvertible(
nativeMatrix, &result));
return result;
}
Status Multiply(const Matrix *matrix,
MatrixOrder order = MatrixOrderPrepend)
{
return updateStatus(DllExports::GdipMultiplyMatrix(
nativeMatrix,
matrix ? matrix->nativeMatrix : NULL, order));
}
REAL OffsetX() const
{
REAL m[6];
updateStatus(DllExports::GdipGetMatrixElements(nativeMatrix, m));
return m[4];
}
REAL OffsetY() const
{
REAL m[6];
updateStatus(DllExports::GdipGetMatrixElements(nativeMatrix, m));
return m[5];
}
Status Reset()
{
return updateStatus(DllExports::GdipSetMatrixElements(
nativeMatrix,
1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f));
}
Status Rotate(REAL angle, MatrixOrder order = MatrixOrderPrepend)
{
return updateStatus(DllExports::GdipRotateMatrix(
nativeMatrix, angle, order));
}
Status RotateAt(REAL angle, const PointF& center,
MatrixOrder order = MatrixOrderPrepend)
{
REAL angleRadian = angle * GDIP_MATRIX_PI / 180.0f;
REAL cosAngle = ::cos(angleRadian);
REAL sinAngle = ::sin(angleRadian);
REAL x = center.X;
REAL y = center.Y;
Matrix matrix2(cosAngle, sinAngle, -sinAngle, cosAngle,
x * (1.0f-cosAngle) + y * sinAngle,
-x * sinAngle + y * (1.0f-cosAngle));
Status status = matrix2.GetLastStatus();
if (status == Ok) {
return Multiply(&matrix2, order);
} else {
return lastStatus = status;
}
}
Status Scale(REAL scaleX, REAL scaleY,
MatrixOrder order = MatrixOrderPrepend)
{
return updateStatus(DllExports::GdipScaleMatrix(
nativeMatrix, scaleX, scaleY, order));
}
Status SetElements(REAL m11, REAL m12, REAL m21, REAL m22,
REAL dx, REAL dy)
{
return updateStatus(DllExports::GdipSetMatrixElements(
nativeMatrix, m11, m12, m21, m22, dx, dy));
}
Status Shear(REAL shearX, REAL shearY,
MatrixOrder order = MatrixOrderPrepend)
{
return updateStatus(DllExports::GdipShearMatrix(
nativeMatrix, shearX, shearY, order));
}
Status TransformPoints(PointF *pts, INT count = 1) const
{
return updateStatus(DllExports::GdipTransformMatrixPoints(
nativeMatrix, pts, count));
}
Status TransformPoints(Point *pts, INT count = 1) const
{
return updateStatus(DllExports::GdipTransformMatrixPointsI(
nativeMatrix, pts, count));
}
Status TransformVectors(PointF *pts, INT count = 1) const
{
return updateStatus(DllExports::GdipVectorTransformMatrixPoints(
nativeMatrix, pts, count));
}
Status TransformVectors(Point *pts, INT count = 1) const
{
return updateStatus(DllExports::GdipVectorTransformMatrixPointsI(
nativeMatrix, pts, count));
}
Status Translate(REAL offsetX, REAL offsetY,
MatrixOrder order = MatrixOrderPrepend)
{
return updateStatus(DllExports::GdipTranslateMatrix(
nativeMatrix, offsetX, offsetY, order));
}
private:
Matrix(GpMatrix *matrix, Status status):
nativeMatrix(matrix), lastStatus(status) {}
Matrix(const Matrix&);
Matrix& operator=(const Matrix&);
Status updateStatus(Status newStatus) const
{
if (newStatus != Ok) lastStatus = newStatus;
return newStatus;
}
GpMatrix *nativeMatrix;
mutable Status lastStatus;
};
#undef GDIP_MATRIX_PI
#endif /* __GDIPLUS_MATRIX_H */