summaryrefslogtreecommitdiffstats
path: root/include/basegfx/matrix
diff options
context:
space:
mode:
Diffstat (limited to 'include/basegfx/matrix')
-rw-r--r--include/basegfx/matrix/b2dhommatrix.hxx158
-rw-r--r--include/basegfx/matrix/b2dhommatrixtools.hxx218
-rw-r--r--include/basegfx/matrix/b3dhommatrix.hxx127
-rw-r--r--include/basegfx/matrix/b3dhommatrixtools.hxx44
-rw-r--r--include/basegfx/matrix/hommatrixtemplate.hxx427
5 files changed, 974 insertions, 0 deletions
diff --git a/include/basegfx/matrix/b2dhommatrix.hxx b/include/basegfx/matrix/b2dhommatrix.hxx
new file mode 100644
index 0000000000..8067b8e1c6
--- /dev/null
+++ b/include/basegfx/matrix/b2dhommatrix.hxx
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <ostream>
+
+#include <sal/types.h>
+#include <basegfx/basegfxdllapi.h>
+#include <array>
+
+namespace basegfx
+{
+ class B2DTuple;
+
+ class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC B2DHomMatrix
+ {
+ private:
+ // Since this is a graphics matrix, the last row is always 0 0 1, so we don't bother to store it.
+ std::array<std::array<double, 3>, 2> mfValues {
+ std::array<double, 3>{ 1.0, 0.0, 0.0 },
+ std::array<double, 3>{ 0.0, 1.0, 0.0 } };
+
+ public:
+ constexpr B2DHomMatrix() = default;
+
+ /** constructor to allow setting all needed values for a 3x2 matrix at once. The
+ parameter f_0x1 e.g. is the same as using set(0, 1, f)
+ */
+ constexpr B2DHomMatrix(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2)
+ {
+ mfValues[0][0] = f_0x0;
+ mfValues[0][1] = f_0x1;
+ mfValues[0][2] = f_0x2;
+ mfValues[1][0] = f_1x0;
+ mfValues[1][1] = f_1x1;
+ mfValues[1][2] = f_1x2;
+ }
+
+ /** Convenience creator for declaration of the matrix that is commonly
+ used by web standards (SVG, CSS, HTML).
+
+ Values a,b,c,d,e,f represent the following values in the matrix:
+ [a,c,e] [a,c,e]
+ [b,d,f] or [b,d,f]
+ [0,0,1]
+
+ */
+ static B2DHomMatrix abcdef(double da, double db, double dc, double dd, double de, double df)
+ {
+ return B2DHomMatrix(da, dc, de, db, dd, df);
+ }
+
+ // Convenience accessor for value at 0,0 position in the matrix
+ double a() const { return get(0,0); }
+ // Convenience accessor for value at 1,0 position in the matrix
+ double b() const { return get(1,0); }
+ // Convenience accessor for value at 0,1 position in the matrix
+ double c() const { return get(0,1); }
+ // Convenience accessor for value at 1,1 position in the matrix
+ double d() const { return get(1,1); }
+ // Convenience accessor for value at 0,2 position in the matrix
+ double e() const { return get(0,2); }
+ // Convenience accessor for value at 1,2 position in the matrix
+ double f() const { return get(1,2); }
+
+ double get(sal_uInt16 nRow, sal_uInt16 nColumn) const
+ {
+ return mfValues[nRow][nColumn];
+ }
+
+ void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
+ {
+ mfValues[nRow][nColumn] = fValue;
+ }
+
+ /** allow setting all needed values for a 3x2 matrix in one call. The
+ parameter f_0x1 e.g. is the same as using set(0, 1, f)
+ */
+ void set3x2(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2);
+
+ // reset to a standard matrix
+ bool isIdentity() const;
+ void identity();
+
+ bool isInvertible() const;
+ bool invert();
+
+ void rotate(double fRadiant);
+
+ void translate(double fX, double fY);
+ void translate(const B2DTuple& rTuple);
+
+ void scale(double fX, double fY);
+ void scale(const B2DTuple& rTuple);
+
+ // Shearing-Matrices
+ void shearX(double fSx);
+ void shearY(double fSy);
+
+ bool operator==(const B2DHomMatrix& rMat) const;
+ bool operator!=(const B2DHomMatrix& rMat) const;
+
+ // matrix multiplication from the left to the local
+ B2DHomMatrix& operator*=(const B2DHomMatrix& rMat);
+
+ /**
+ * Help routine to decompose given homogen 3x3 matrix to components. A correction of the
+ * components is done to avoid inaccuracies.
+ *
+ * See basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix() for the opposite, to
+ * compose a homogen 3x3 matrix from components.
+ */
+ bool decompose(B2DTuple& rScale, B2DTuple& rTranslate, double& rRotate, double& rShearX) const;
+
+ private:
+ void computeAdjoint(double (&dst)[6]) const;
+ double computeDeterminant(double (&dst)[6]) const;
+ void doMulMatrix(const B2DHomMatrix& rMat);
+ };
+
+ inline B2DHomMatrix operator*(const B2DHomMatrix& rMatA, const B2DHomMatrix& rMatB)
+ {
+ B2DHomMatrix aMul(rMatB);
+ aMul *= rMatA;
+ return aMul;
+ }
+
+ template<typename charT, typename traits>
+ std::basic_ostream<charT, traits> & operator <<(
+ std::basic_ostream<charT, traits> & stream, B2DHomMatrix const & matrix)
+ {
+ return stream
+ << '[' << matrix.get(0, 0) << ' ' << matrix.get(0, 1) << ' '
+ << matrix.get(0, 2) << "; " << matrix.get(1, 0) << ' '
+ << matrix.get(1, 1) << ' ' << matrix.get(1, 2) << ']';
+ }
+} // end of namespace basegfx
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/basegfx/matrix/b2dhommatrixtools.hxx b/include/basegfx/matrix/b2dhommatrixtools.hxx
new file mode 100644
index 0000000000..9b81f33d2a
--- /dev/null
+++ b/include/basegfx/matrix/b2dhommatrixtools.hxx
@@ -0,0 +1,218 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/tuple/b2dtuple.hxx>
+#include <utility>
+#include <basegfx/basegfxdllapi.h>
+
+namespace basegfx { class B2DRange; }
+
+namespace basegfx::utils
+{
+ /** If the rotation angle is an approximate multiple of pi/2,
+ force fSin/fCos to -1/0/1, to maintain orthogonality (which
+ might also be advantageous for the other cases, but: for
+ multiples of pi/2, the exact values _can_ be attained. It
+ would be largely unintuitive, if a 180 degrees rotation
+ would introduce slight roundoff errors, instead of exactly
+ mirroring the coordinate system)
+ */
+ void createSinCosOrthogonal(double& o_rSin, double& rCos, double fRadiant);
+
+ /** Tooling methods for on-the-fly matrix generation e.g. for inline
+ multiplications
+ */
+ BASEGFX_DLLPUBLIC B2DHomMatrix createScaleB2DHomMatrix(double fScaleX, double fScaleY);
+ BASEGFX_DLLPUBLIC B2DHomMatrix createShearXB2DHomMatrix(double fShearX);
+ BASEGFX_DLLPUBLIC B2DHomMatrix createShearYB2DHomMatrix(double fShearY);
+ BASEGFX_DLLPUBLIC B2DHomMatrix createRotateB2DHomMatrix(double fRadiant);
+ BASEGFX_DLLPUBLIC B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY);
+
+ /// inline versions for parameters as tuples
+ inline B2DHomMatrix createScaleB2DHomMatrix(const B2DTuple& rScale)
+ {
+ return createScaleB2DHomMatrix(rScale.getX(), rScale.getY());
+ }
+
+ inline B2DHomMatrix createTranslateB2DHomMatrix(const B2DTuple& rTranslate)
+ {
+ return createTranslateB2DHomMatrix(rTranslate.getX(), rTranslate.getY());
+ }
+
+ /** Tooling methods for faster completely combined matrix creation
+ when scale, shearX, rotation and translation needs to be done in
+ exactly that order. It's faster since it directly calculates
+ each matrix value based on a symbolic calculation of the three
+ matrix multiplications.
+ Inline versions for parameters as tuples added, too.
+ */
+ BASEGFX_DLLPUBLIC B2DHomMatrix createScaleShearXRotateTranslateB2DHomMatrix(
+ double fScaleX, double fScaleY,
+ double fShearX,
+ double fRadiant,
+ double fTranslateX, double fTranslateY);
+ inline B2DHomMatrix createScaleShearXRotateTranslateB2DHomMatrix(
+ const B2DTuple& rScale,
+ double fShearX,
+ double fRadiant,
+ const B2DTuple& rTranslate)
+ {
+ return createScaleShearXRotateTranslateB2DHomMatrix(
+ rScale.getX(), rScale.getY(),
+ fShearX,
+ fRadiant,
+ rTranslate.getX(), rTranslate.getY());
+ }
+
+ BASEGFX_DLLPUBLIC B2DHomMatrix createShearXRotateTranslateB2DHomMatrix(
+ double fShearX,
+ double fRadiant,
+ double fTranslateX, double fTranslateY);
+ inline B2DHomMatrix createShearXRotateTranslateB2DHomMatrix(
+ double fShearX,
+ double fRadiant,
+ const B2DTuple& rTranslate)
+ {
+ return createShearXRotateTranslateB2DHomMatrix(
+ fShearX,
+ fRadiant,
+ rTranslate.getX(), rTranslate.getY());
+ }
+
+ BASEGFX_DLLPUBLIC B2DHomMatrix createScaleTranslateB2DHomMatrix(
+ double fScaleX, double fScaleY,
+ double fTranslateX, double fTranslateY);
+ inline B2DHomMatrix createScaleTranslateB2DHomMatrix(
+ const B2DTuple& rScale,
+ const B2DTuple& rTranslate)
+ {
+ return createScaleTranslateB2DHomMatrix(
+ rScale.getX(), rScale.getY(),
+ rTranslate.getX(), rTranslate.getY());
+ }
+
+ /// special for the often used case of rotation around a point
+ BASEGFX_DLLPUBLIC B2DHomMatrix createRotateAroundPoint(
+ double fPointX, double fPointY,
+ double fRadiant);
+ inline B2DHomMatrix createRotateAroundPoint(
+ const B2DTuple& rPoint,
+ double fRadiant)
+ {
+ return createRotateAroundPoint(
+ rPoint.getX(), rPoint.getY(),
+ fRadiant);
+ }
+
+ /// special for creating a mapping for a Range rotated around it's center
+ /// while keeping AspectRatio unchanged and staying inside the given Range
+ /// by optimally using the available space (no overlap or outside allowed)
+ B2DHomMatrix createRotateAroundCenterKeepAspectRatioStayInsideRange(
+ const basegfx::B2DRange& rTargetRange,
+ double fRotate);
+
+ /// special for the case to map from source range to target range
+ BASEGFX_DLLPUBLIC B2DHomMatrix createSourceRangeTargetRangeTransform(
+ const B2DRange& rSourceRange,
+ const B2DRange& rTargetRange);
+
+ /// create based on given CoordinateSystem which is defined by origin and x/yaxis
+ BASEGFX_DLLPUBLIC B2DHomMatrix createCoordinateSystemTransform(
+ const B2DPoint& rOrigin,
+ const B2DVector& rX,
+ const B2DVector& rY);
+
+ /// get column vector from B2dHomMatrix, e.g. to extract coordinate system origin and x/yaxis
+ BASEGFX_DLLPUBLIC B2DTuple getColumn(const B2DHomMatrix& rMatrix, sal_uInt16 nCol);
+
+
+ class BASEGFX_DLLPUBLIC B2DHomMatrixBufferedDecompose
+ {
+ private:
+ B2DVector maScale;
+ B2DVector maTranslate;
+ double mfRotate;
+ double mfShearX;
+
+ public:
+ B2DHomMatrixBufferedDecompose(const B2DHomMatrix& rB2DHomMatrix = B2DHomMatrix())
+ : mfRotate(0.0),
+ mfShearX(0.0)
+ {
+ rB2DHomMatrix.decompose(maScale, maTranslate, mfRotate, mfShearX);
+ }
+
+ // data access
+ B2DHomMatrix getB2DHomMatrix() const
+ {
+ return createScaleShearXRotateTranslateB2DHomMatrix(
+ maScale, mfShearX, mfRotate, maTranslate);
+ }
+
+ const B2DVector& getScale() const { return maScale; }
+ const B2DVector& getTranslate() const { return maTranslate; }
+ double getRotate() const { return mfRotate; }
+ double getShearX() const { return mfShearX; }
+ };
+
+ class BASEGFX_DLLPUBLIC B2DHomMatrixBufferedOnDemandDecompose
+ {
+ private:
+ B2DHomMatrix maB2DHomMatrix;
+ B2DVector maScale;
+ B2DVector maTranslate;
+ double mfRotate;
+ double mfShearX;
+
+ bool mbDecomposed : 1;
+
+ void impCheckDecompose()
+ {
+ if(!mbDecomposed)
+ {
+ maB2DHomMatrix.decompose(maScale, maTranslate, mfRotate, mfShearX);
+ mbDecomposed = true;
+ }
+ }
+
+ public:
+ B2DHomMatrixBufferedOnDemandDecompose(B2DHomMatrix aB2DHomMatrix = B2DHomMatrix())
+ : maB2DHomMatrix(std::move(aB2DHomMatrix)),
+ mfRotate(0.0),
+ mfShearX(0.0),
+ mbDecomposed(false)
+ {
+ }
+
+ // data access
+ const B2DHomMatrix& getB2DHomMatrix() const { return maB2DHomMatrix; }
+ const B2DVector& getScale() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return maScale; }
+ const B2DVector& getTranslate() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return maTranslate; }
+ double getRotate() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return mfRotate; }
+ double getShearX() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return mfShearX; }
+ };
+} // end of namespace basegfx::utils
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/basegfx/matrix/b3dhommatrix.hxx b/include/basegfx/matrix/b3dhommatrix.hxx
new file mode 100644
index 0000000000..29603f88eb
--- /dev/null
+++ b/include/basegfx/matrix/b3dhommatrix.hxx
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <basegfx/point/b3dpoint.hxx>
+#include <basegfx/vector/b3dvector.hxx>
+#include <o3tl/cow_wrapper.hxx>
+#include <basegfx/basegfxdllapi.h>
+
+namespace basegfx
+{
+ class B3DTuple;
+ class Impl3DHomMatrix;
+
+ class BASEGFX_DLLPUBLIC B3DHomMatrix
+ {
+ public:
+ typedef o3tl::cow_wrapper< Impl3DHomMatrix, o3tl::ThreadSafeRefCountingPolicy > ImplType;
+
+ private:
+ ImplType mpImpl;
+
+ public:
+ B3DHomMatrix();
+ B3DHomMatrix(const B3DHomMatrix& rMat);
+ B3DHomMatrix(B3DHomMatrix&& rMat);
+ ~B3DHomMatrix();
+
+ double get(sal_uInt16 nRow, sal_uInt16 nColumn) const;
+ void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue);
+
+ // test if last line is default to see if last line needs to be
+ // involved in calculations
+ bool isLastLineDefault() const;
+
+ bool isIdentity() const;
+ /// Reset to the identity matrix
+ void identity();
+
+ /// Invert the matrix (if possible)
+ void invert();
+
+ /// Calc the matrix determinant
+ double determinant() const;
+
+ /// Rotation
+ void rotate(double fAngleX,double fAngleY,double fAngleZ);
+ void rotate(const B3DTuple& rRotation);
+
+ /// Translation
+ void translate(double fX, double fY, double fZ);
+ void translate(const B3DTuple& rTranslation);
+
+ /// Scaling
+ void scale(double fX, double fY, double fZ);
+ void scale(const B3DTuple& rScale);
+
+ // Shearing-Matrices
+ void shearXY(double fSx, double fSy);
+ void shearXZ(double fSx, double fSz);
+
+ // Projection matrices, used for converting between eye and
+ // clip coordinates
+ void frustum(double fLeft = -1.0, double fRight = 1.0,
+ double fBottom = -1.0, double fTop = 1.0,
+ double fNear = 0.001, double fFar = 1.0);
+
+ void ortho(double fLeft = -1.0, double fRight = 1.0,
+ double fBottom = -1.0, double fTop = 1.0,
+ double fNear = 0.0, double fFar = 1.0);
+
+ // build orientation matrix
+ void orientation(
+ const B3DPoint& rVRP = B3DPoint(0.0,0.0,1.0),
+ B3DVector aVPN = B3DVector(0.0,0.0,1.0),
+ B3DVector aVUV = B3DVector(0.0,1.0,0.0));
+
+ // addition, subtraction
+ B3DHomMatrix& operator+=(const B3DHomMatrix& rMat);
+ B3DHomMatrix& operator-=(const B3DHomMatrix& rMat);
+
+ // comparison
+ bool operator==(const B3DHomMatrix& rMat) const;
+ bool operator!=(const B3DHomMatrix& rMat) const;
+
+ // multiplication, division by constant value
+ B3DHomMatrix& operator*=(double fValue);
+ B3DHomMatrix& operator/=(double fValue);
+
+ // matrix multiplication (from the left)
+ B3DHomMatrix& operator*=(const B3DHomMatrix& rMat);
+
+ // assignment operator
+ B3DHomMatrix& operator=(const B3DHomMatrix& rMat);
+ B3DHomMatrix& operator=(B3DHomMatrix&& rMat);
+
+ // decomposition
+ void decompose(B3DTuple& rScale, B3DTuple& rTranslate, B3DTuple& rRotate, B3DTuple& rShear) const;
+ };
+
+ inline B3DHomMatrix operator*(const B3DHomMatrix& rMatA, const B3DHomMatrix& rMatB)
+ {
+ B3DHomMatrix aMul(rMatB);
+ aMul *= rMatA;
+ return aMul;
+ }
+} // end of namespace basegfx
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/basegfx/matrix/b3dhommatrixtools.hxx b/include/basegfx/matrix/b3dhommatrixtools.hxx
new file mode 100644
index 0000000000..6b65d24603
--- /dev/null
+++ b/include/basegfx/matrix/b3dhommatrixtools.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <basegfx/basegfxdllapi.h>
+#include <basegfx/matrix/b3dhommatrix.hxx>
+
+namespace com::sun::star::drawing
+{
+struct HomogenMatrix;
+}
+
+namespace basegfx::utils
+{
+/* tooling methods for converting API matrices (drawing::HomogenMatrix) to
+ B3DHomMatrix. drawing::HomogenMatrix4 is not used by OOo
+ */
+BASEGFX_DLLPUBLIC B3DHomMatrix
+UnoHomogenMatrixToB3DHomMatrix(const com::sun::star::drawing::HomogenMatrix& rMatrixIn);
+
+BASEGFX_DLLPUBLIC void
+B3DHomMatrixToUnoHomogenMatrix(const B3DHomMatrix& rMatrixIn,
+ com::sun::star::drawing::HomogenMatrix& rMatrixOut);
+
+} // end of namespace basegfx::tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/basegfx/matrix/hommatrixtemplate.hxx b/include/basegfx/matrix/hommatrixtemplate.hxx
new file mode 100644
index 0000000000..4f1300f533
--- /dev/null
+++ b/include/basegfx/matrix/hommatrixtemplate.hxx
@@ -0,0 +1,427 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <basegfx/numeric/ftools.hxx>
+#include <cmath>
+
+namespace basegfx::internal
+ {
+
+ inline constexpr double implGetDefaultValue(sal_uInt16 nRow, sal_uInt16 nColumn)
+ {
+ if(nRow == nColumn)
+ return 1.0;
+ return 0.0;
+ }
+
+ template < sal_uInt16 RowSize > class ImplMatLine
+ {
+ double mfValue[RowSize];
+
+ public:
+ ImplMatLine() = default;
+
+ explicit ImplMatLine(sal_uInt16 nRow)
+ {
+ for(sal_uInt16 a(0); a < RowSize; a++)
+ {
+ mfValue[a] = implGetDefaultValue(nRow, a);
+ }
+ }
+
+ double get(sal_uInt16 nColumn) const
+ {
+ return mfValue[nColumn];
+ }
+
+ void set(sal_uInt16 nColumn, const double& rValue)
+ {
+ mfValue[nColumn] = rValue;
+ }
+ };
+
+ template < sal_uInt16 RowSize > class ImplHomMatrixTemplate
+ {
+ ImplMatLine< RowSize > maLine[RowSize];
+
+ public:
+ // Is last line used?
+ bool isLastLineDefault() const
+ {
+ for(sal_uInt16 a(0); a < RowSize; a++)
+ {
+ const double fDefault(implGetDefaultValue((RowSize - 1), a));
+ const double fLineValue(maLine[RowSize-1].get(a));
+
+ if(fDefault != fLineValue)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ ImplHomMatrixTemplate()
+ {
+ // complete initialization with identity matrix, all lines
+ // were initialized with a trailing 1 followed by 0's.
+ for(sal_uInt16 a(0); a < RowSize; a++)
+ {
+ for(sal_uInt16 b(0); b < RowSize; b++)
+ maLine[a].set(b, implGetDefaultValue(a, b) );
+ }
+ }
+
+ ImplHomMatrixTemplate(const ImplHomMatrixTemplate& rToBeCopied)
+ {
+ operator=(rToBeCopied);
+ }
+
+ ImplHomMatrixTemplate& operator=(const ImplHomMatrixTemplate& rToBeCopied)
+ {
+ if (this != &rToBeCopied)
+ {
+ // complete initialization using copy
+ for(sal_uInt16 a(0); a < RowSize; a++)
+ {
+ maLine[a] = rToBeCopied.maLine[a];
+ }
+ }
+ return *this;
+ }
+
+ static sal_uInt16 getEdgeLength() { return RowSize; }
+
+ double get(sal_uInt16 nRow, sal_uInt16 nColumn) const
+ {
+ return maLine[nRow].get(nColumn);
+ }
+
+ void set(sal_uInt16 nRow, sal_uInt16 nColumn, const double& rValue)
+ {
+ maLine[nRow].set(nColumn, rValue);
+ }
+
+ // Left-upper decomposition
+ bool ludcmp(sal_uInt16 nIndex[], sal_Int16& nParity)
+ {
+ double fBig, fSum, fDum;
+ double fStorage[RowSize];
+ sal_uInt16 a, b, c;
+
+ // #i30874# Initialize nAMax (compiler warns)
+ sal_uInt16 nAMax = 0;
+
+ nParity = 1;
+
+ // Calc the max of each line. If a line is empty,
+ // stop immediately since matrix is not invertible then.
+ for(a = 0; a < RowSize; a++)
+ {
+ fBig = 0.0;
+
+ for(b = 0; b < RowSize; b++)
+ {
+ double fTemp(fabs(get(a, b)));
+
+ if(::basegfx::fTools::more(fTemp, fBig))
+ {
+ fBig = fTemp;
+ }
+ }
+
+ if(::basegfx::fTools::equalZero(fBig))
+ {
+ return false;
+ }
+
+ fStorage[a] = 1.0 / fBig;
+ }
+
+ // start normalizing
+ for(b = 0; b < RowSize; b++)
+ {
+ for(a = 0; a < b; a++)
+ {
+ fSum = get(a, b);
+
+ for(c = 0; c < a; c++)
+ {
+ fSum -= get(a, c) * get(c, b);
+ }
+
+ set(a, b, fSum);
+ }
+
+ fBig = 0.0;
+
+ for(a = b; a < RowSize; a++)
+ {
+ fSum = get(a, b);
+
+ for(c = 0; c < b; c++)
+ {
+ fSum -= get(a, c) * get(c, b);
+ }
+
+ set(a, b, fSum);
+ fDum = fStorage[a] * fabs(fSum);
+
+ if(::basegfx::fTools::moreOrEqual(fDum, fBig))
+ {
+ fBig = fDum;
+ nAMax = a;
+ }
+ }
+
+ if(b != nAMax)
+ {
+ for(c = 0; c < RowSize; c++)
+ {
+ fDum = get(nAMax, c);
+ set(nAMax, c, get(b, c));
+ set(b, c, fDum);
+ }
+
+ nParity = -nParity;
+ fStorage[nAMax] = fStorage[b];
+ }
+
+ nIndex[b] = nAMax;
+
+ // here the failure of precision occurs
+ const double fValBB(fabs(get(b, b)));
+
+ if(::basegfx::fTools::equalZero(fValBB))
+ {
+ return false;
+ }
+
+ if(b != (RowSize - 1))
+ {
+ fDum = 1.0 / get(b, b);
+
+ for(a = b + 1; a < RowSize; a++)
+ {
+ set(a, b, get(a, b) * fDum);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ void lubksb(const sal_uInt16 nIndex[], double fRow[]) const
+ {
+ sal_uInt16 b, ip;
+ sal_Int16 a, a2 = -1;
+ double fSum;
+
+ for(a = 0; a < RowSize; a++)
+ {
+ ip = nIndex[a];
+ fSum = fRow[ip];
+ fRow[ip] = fRow[a];
+
+ if(a2 >= 0)
+ {
+ for(b = a2; b < a; b++)
+ {
+ fSum -= get(a, b) * fRow[b];
+ }
+ }
+ else if(!::basegfx::fTools::equalZero(fSum))
+ {
+ a2 = a;
+ }
+
+ fRow[a] = fSum;
+ }
+
+ for(a = (RowSize - 1); a >= 0; a--)
+ {
+ fSum = fRow[a];
+
+ for(b = a + 1; b < RowSize; b++)
+ {
+ fSum -= get(a, b) * fRow[b];
+ }
+
+ const double fValueAA(get(a, a));
+
+ if(!::basegfx::fTools::equalZero(fValueAA))
+ {
+ fRow[a] = fSum / get(a, a);
+ }
+ }
+ }
+
+ bool isIdentity() const
+ {
+ for(sal_uInt16 a(0); a < RowSize; a++)
+ {
+ for(sal_uInt16 b(0); b < RowSize; b++)
+ {
+ const double fDefault(implGetDefaultValue(a, b));
+ const double fValueAB(get(a, b));
+
+ if(!::basegfx::fTools::equal(fDefault, fValueAB))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ bool isInvertible() const
+ {
+ ImplHomMatrixTemplate aWork(*this);
+ sal_uInt16 nIndex[RowSize];
+ sal_Int16 nParity;
+
+ return aWork.ludcmp(nIndex, nParity);
+ }
+
+ void doInvert(const ImplHomMatrixTemplate& rWork, const sal_uInt16 nIndex[])
+ {
+ double fArray[RowSize];
+
+ for(sal_uInt16 a(0); a < RowSize; a++)
+ {
+ // prepare line
+ sal_uInt16 b;
+ for( b = 0; b < RowSize; b++)
+ {
+ fArray[b] = implGetDefaultValue(a, b);
+ }
+
+ // expand line
+ rWork.lubksb(nIndex, fArray);
+
+ // copy line transposed to this matrix
+ for( b = 0; b < RowSize; b++)
+ {
+ set(b, a, fArray[b]);
+ }
+ }
+ }
+
+ double doDeterminant() const
+ {
+ ImplHomMatrixTemplate aWork(*this);
+ sal_uInt16 nIndex[RowSize];
+ sal_Int16 nParity;
+ double fRetval(0.0);
+
+ if(aWork.ludcmp(nIndex, nParity))
+ {
+ fRetval = static_cast<double>(nParity);
+ for(sal_uInt16 a(0); a < RowSize; a++)
+ {
+ fRetval *= aWork.get(a, a);
+ }
+ }
+
+ return fRetval;
+ }
+
+ void doAddMatrix(const ImplHomMatrixTemplate& rMat)
+ {
+ for(sal_uInt16 a(0); a < RowSize; a++)
+ {
+ for(sal_uInt16 b(0); b < RowSize; b++)
+ {
+ set(a, b, get(a, b) + rMat.get(a, b));
+ }
+ }
+ }
+
+ void doSubMatrix(const ImplHomMatrixTemplate& rMat)
+ {
+ for(sal_uInt16 a(0); a < RowSize; a++)
+ {
+ for(sal_uInt16 b(0); b < RowSize; b++)
+ {
+ set(a, b, get(a, b) - rMat.get(a, b));
+ }
+ }
+ }
+
+ void doMulMatrix(const double& rfValue)
+ {
+ for(sal_uInt16 a(0); a < RowSize; a++)
+ {
+ for(sal_uInt16 b(0); b < RowSize; b++)
+ {
+ set(a, b, get(a, b) * rfValue);
+ }
+ }
+ }
+
+ void doMulMatrix(const ImplHomMatrixTemplate& rMat)
+ {
+ // create a copy as source for the original values
+ const ImplHomMatrixTemplate aCopy(*this);
+
+ // TODO: maybe optimize cases where last line is [0 0 1].
+
+ double fValue(0.0);
+
+ for(sal_uInt16 a(0); a < RowSize; ++a)
+ {
+ for(sal_uInt16 b(0); b < RowSize; ++b)
+ {
+ fValue = 0.0;
+
+ for(sal_uInt16 c(0); c < RowSize; ++c)
+ fValue += aCopy.get(c, b) * rMat.get(a, c);
+
+ set(a, b, fValue);
+ }
+ }
+ }
+
+ bool isEqual(const ImplHomMatrixTemplate& rMat) const
+ {
+ for(sal_uInt16 a(0); a < RowSize; a++)
+ {
+ for(sal_uInt16 b(0); b < RowSize; b++)
+ {
+ const double fValueA(get(a, b));
+ const double fValueB(rMat.get(a, b));
+
+ if(!::basegfx::fTools::equal(fValueA, fValueB))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+ };
+
+} // namespace basegfx::internal
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */