summaryrefslogtreecommitdiffstats
path: root/scribus/plugins/tools/2geomtools/lib2geom/matrix.cpp
diff options
context:
space:
mode:
authorcraig <craig@11d20701-8431-0410-a711-e3c959e3b870>2012-01-01 11:40:09 +0000
committercraig <craig@11d20701-8431-0410-a711-e3c959e3b870>2012-01-01 11:40:09 +0000
commit7ed83b6c6666eb8b6b104c211ae7e52907350372 (patch)
tree4430b556abac0ad660a0aacf1887d77f85d8be02 /scribus/plugins/tools/2geomtools/lib2geom/matrix.cpp
downloadscribus-7ed83b6c6666eb8b6b104c211ae7e52907350372.tar.gz
scribus-7ed83b6c6666eb8b6b104c211ae7e52907350372.tar.xz
scribus-7ed83b6c6666eb8b6b104c211ae7e52907350372.zip
Branch 1.3.5 tree to 1.4.x tree, goodbye 1.3.x
git-svn-id: svn://scribus.net/branches/Version14x/Scribus@17163 11d20701-8431-0410-a711-e3c959e3b870
Diffstat (limited to 'scribus/plugins/tools/2geomtools/lib2geom/matrix.cpp')
-rw-r--r--scribus/plugins/tools/2geomtools/lib2geom/matrix.cpp253
1 files changed, 253 insertions, 0 deletions
diff --git a/scribus/plugins/tools/2geomtools/lib2geom/matrix.cpp b/scribus/plugins/tools/2geomtools/lib2geom/matrix.cpp
new file mode 100644
index 0000000..6d7c772
--- /dev/null
+++ b/scribus/plugins/tools/2geomtools/lib2geom/matrix.cpp
@@ -0,0 +1,253 @@
+#define __Geom_MATRIX_C__
+
+/** \file
+ * Various matrix routines. Currently includes some Geom::Rotate etc. routines too.
+ */
+
+/*
+ * Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * Michael G. Sloan <mgsloan@gmail.com>
+ *
+ * This code is in public domain
+ */
+
+#include "utils.h"
+#include "matrix.h"
+#include "point.h"
+
+namespace Geom {
+
+/** Creates a Matrix given an axis and origin point.
+ * The axis is represented as two vectors, which represent skew, rotation, and scaling in two dimensions.
+ * from_basis(Point(1, 0), Point(0, 1), Point(0, 0)) would return the identity matrix.
+
+ \param x_basis the vector for the x-axis.
+ \param y_basis the vector for the y-axis.
+ \param offset the translation applied by the matrix.
+ \return The new Matrix.
+ */
+//NOTE: Inkscape's version is broken, so when including this version, you'll have to search for code with this func
+//TODO: move to Matrix::from_basis
+Matrix from_basis(Point const x_basis, Point const y_basis, Point const offset) {
+ return Matrix(x_basis[X], x_basis[Y],
+ y_basis[X], y_basis[Y],
+ offset [X], offset [Y]);
+}
+
+Point Matrix::xAxis() const {
+ return Point(_c[0], _c[1]);
+}
+
+Point Matrix::yAxis() const {
+ return Point(_c[2], _c[3]);
+}
+
+/** Gets the translation imparted by the Matrix.
+ */
+Point Matrix::translation() const {
+ return Point(_c[4], _c[5]);
+}
+
+void Matrix::setXAxis(Point const &vec) {
+ for(int i = 0; i < 2; i++)
+ _c[i] = vec[i];
+}
+
+void Matrix::setYAxis(Point const &vec) {
+ for(int i = 0; i < 2; i++)
+ _c[i + 2] = vec[i];
+}
+
+/** Sets the translation imparted by the Matrix.
+ */
+void Matrix::setTranslation(Point const &loc) {
+ for(int i = 0; i < 2; i++)
+ _c[i + 4] = loc[i];
+}
+
+/** Calculates the amount of x-scaling imparted by the Matrix. This is the scaling applied to
+ * the original x-axis region. It is \emph{not} the overall x-scaling of the transformation.
+ * Equivalent to L2(m.xAxis())
+ */
+double Matrix::expansionX() const {
+ return sqrt(_c[0] * _c[0] + _c[1] * _c[1]);
+}
+
+/** Calculates the amount of y-scaling imparted by the Matrix. This is the scaling applied before
+ * the other transformations. It is \emph{not} the overall y-scaling of the transformation.
+ * Equivalent to L2(m.yAxis())
+ */
+double Matrix::expansionY() const {
+ return sqrt(_c[2] * _c[2] + _c[3] * _c[3]);
+}
+
+void Matrix::setExpansionX(double val) {
+ double exp_x = expansionX();
+ if(!are_near(exp_x, 0.0)) { //TODO: best way to deal with it is to skip op?
+ double coef = val / expansionX();
+ for(unsigned i=0;i<2;i++) _c[i] *= coef;
+ }
+}
+
+void Matrix::setExpansionY(double val) {
+ double exp_y = expansionY();
+ if(!are_near(exp_y, 0.0)) { //TODO: best way to deal with it is to skip op?
+ double coef = val / expansionY();
+ for(unsigned i=2; i<4; i++) _c[i] *= coef;
+ }
+}
+
+/** Sets this matrix to be the Identity Matrix. */
+void Matrix::setIdentity() {
+ _c[0] = 1.0; _c[1] = 0.0;
+ _c[2] = 0.0; _c[3] = 1.0;
+ _c[4] = 0.0; _c[5] = 0.0;
+}
+
+//TODO: use eps
+
+bool Matrix::isIdentity(Coord const eps) const {
+ return are_near(_c[0], 1.0) && are_near(_c[1], 0.0) &&
+ are_near(_c[2], 0.0) && are_near(_c[3], 1.0) &&
+ are_near(_c[4], 0.0) && are_near(_c[5], 0.0);
+}
+
+/** Answers the question "Does this matrix perform a translation, and \em{only} a translation?"
+ \param eps an epsilon value defaulting to EPSILON
+ \return A bool representing yes/no.
+ */
+bool Matrix::isTranslation(Coord const eps) const {
+ return are_near(_c[0], 1.0) && are_near(_c[1], 0.0) &&
+ are_near(_c[2], 0.0) && are_near(_c[3], 1.0) &&
+ (!are_near(_c[4], 0.0) || !are_near(_c[5], 0.0));
+}
+
+/** Answers the question "Does this matrix perform a scale, and \em{only} a Scale?"
+ \param eps an epsilon value defaulting to EPSILON
+ \return A bool representing yes/no.
+ */
+bool Matrix::isScale(Coord const eps) const {
+ return !are_near(_c[0], 1.0) || !are_near(_c[3], 1.0) && //NOTE: these are the diags, and the next line opposite diags
+ are_near(_c[1], 0.0) && are_near(_c[2], 0.0) &&
+ are_near(_c[4], 0.0) && are_near(_c[5], 0.0);
+}
+
+/** Answers the question "Does this matrix perform a uniform scale, and \em{only} a uniform scale?"
+ \param eps an epsilon value defaulting to EPSILON
+ \return A bool representing yes/no.
+ */
+bool Matrix::isUniformScale(Coord const eps) const {
+ return !are_near(_c[0], 1.0) && are_near(_c[0], _c[3]) &&
+ are_near(_c[1], 0.0) && are_near(_c[2], 0.0) &&
+ are_near(_c[4], 0.0) && are_near(_c[5], 0.0);
+}
+
+/** Answers the question "Does this matrix perform a rotation, and \em{only} a rotation?"
+ \param eps an epsilon value defaulting to EPSILON
+ \return A bool representing yes/no.
+ */
+bool Matrix::isRotation(Coord const eps) const {
+ return !are_near(_c[0], _c[3]) && are_near(_c[1], -_c[2]) &&
+ are_near(_c[4], 0.0) && are_near(_c[5], 0.0) &&
+ are_near(_c[0]*_c[0] + _c[1]*_c[1], 1.0);
+}
+
+bool Matrix::onlyScaleAndTranslation(Coord const eps) const {
+ return are_near(_c[0], _c[3]) && are_near(_c[1], 0) && are_near(_c[2], 0);
+}
+
+bool Matrix::flips() const {
+ return cross(xAxis(), yAxis()) > 0;
+}
+
+/** Returns the Scale/Rotate/skew part of the matrix without the translation part. */
+Matrix Matrix::without_translation() const {
+ return Matrix(_c[0], _c[1], _c[2], _c[3], 0, 0);
+}
+
+/** Attempts to calculate the inverse of a matrix.
+ * This is a Matrix such that m * m.inverse() is very near (hopefully < epsilon difference) the identity Matrix.
+ * \textbf{The Identity Matrix is returned if the matrix has no inverse.}
+ \return The inverse of the Matrix if defined, otherwise the Identity Matrix.
+ */
+Matrix Matrix::inverse() const {
+ Matrix d;
+
+ Geom::Coord const determ = det();
+ if (!are_near(determ, 0.0)) {
+ Geom::Coord const ideterm = 1.0 / determ;
+
+ d._c[0] = _c[3] * ideterm;
+ d._c[1] = -_c[1] * ideterm;
+ d._c[2] = -_c[2] * ideterm;
+ d._c[3] = _c[0] * ideterm;
+ d._c[4] = -_c[4] * d._c[0] - _c[5] * d._c[2];
+ d._c[5] = -_c[4] * d._c[1] - _c[5] * d._c[3];
+ } else {
+ d.setIdentity();
+ }
+
+ return d;
+}
+
+/** Calculates the determinant of a Matrix. */
+Geom::Coord Matrix::det() const {
+ return _c[0] * _c[3] - _c[1] * _c[2];
+}
+
+/** Calculates the scalar of the descriminant of the Matrix.
+ * This is simply the absolute value of the determinant.
+ */
+Geom::Coord Matrix::descrim2() const {
+ return fabs(det());
+}
+
+/** Calculates the descriminant of the Matrix. */
+Geom::Coord Matrix::descrim() const {
+ return sqrt(descrim2());
+}
+
+Matrix operator*(Matrix const &m0, Matrix const &m1) {
+ Matrix ret;
+ for(int a = 0; a < 5; a += 2) {
+ for(int b = 0; b < 2; b++) {
+ ret[a + b] = m0[a] * m1[b] + m0[a + 1] * m1[b + 2];
+ }
+ }
+ ret[4] += m1[4];
+ ret[5] += m1[5];
+ return ret;
+}
+
+//TODO: What's this!?!
+Matrix elliptic_quadratic_form(Matrix const &m) {
+ double const od = m[0] * m[1] + m[2] * m[3];
+ return Matrix(m[0]*m[0] + m[1]*m[1], od,
+ od, m[2]*m[2] + m[3]*m[3],
+ 0, 0);
+}
+
+Eigen::Eigen(Matrix const &m) {
+ double const B = -m[0] - m[3];
+ double const C = m[0]*m[3] - m[1]*m[2];
+ double const center = -B/2.0;
+ double const delta = sqrt(B*B-4*C)/2.0;
+ values[0] = center + delta; values[1] = center - delta;
+ for (int i = 0; i < 2; i++) {
+ vectors[i] = unit_vector(rot90(Point(m[0]-values[i], m[1])));
+ }
+}
+
+} //namespace Geom
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :