affine.cpp revision 7bda77e763c0af49270427593108b66455dfd125
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * Lauris Kaplinski <lauris@kaplinski.com>
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * Michael G. Sloan <mgsloan@gmail.com>
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * This code is in public domain
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** Creates a Affine given an axis and origin point.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * The axis is represented as two vectors, which represent skew, rotation, and scaling in two dimensions.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * from_basis(Point(1, 0), Point(0, 1), Point(0, 0)) would return the identity matrix.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler \param x_basis the vector for the x-axis.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler \param y_basis the vector for the y-axis.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler \param offset the translation applied by the matrix.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler \return The new Affine.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler//NOTE: Inkscape's version is broken, so when including this version, you'll have to search for code with this func
f6df6236fcf18524e049bba12b69704af32eff90Josh AndlerAffine from_basis(Point const x_basis, Point const y_basis, Point const offset) {
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** Gets the translation imparted by the Affine.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler for(int i = 0; i < 2; i++)
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler for(int i = 0; i < 2; i++)
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** Sets the translation imparted by the Affine.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler for(int i = 0; i < 2; i++)
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** Calculates the amount of x-scaling imparted by the Affine. This is the scaling applied to
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * the original x-axis region. It is \emph{not} the overall x-scaling of the transformation.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * Equivalent to L2(m.xAxis())
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** Calculates the amount of y-scaling imparted by the Affine. This is the scaling applied before
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * the other transformations. It is \emph{not} the overall y-scaling of the transformation.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * Equivalent to L2(m.yAxis())
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler if(!are_near(exp_x, 0.0)) { //TODO: best way to deal with it is to skip op?
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler if(!are_near(exp_y, 0.0)) { //TODO: best way to deal with it is to skip op?
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** Sets this matrix to be the Identity Affine. */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether this matrix is an identity matrix.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return True iff the matrix is of the form
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * \f$\left[\begin{array}{ccc}
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 1 & 0 & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 0 & 1 & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 0 & 0 & 1 \end{array}\right]\f$ */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler return are_near(_c[0], 1.0, eps) && are_near(_c[1], 0.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[2], 0.0, eps) && are_near(_c[3], 1.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps);
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether this matrix represents a pure translation.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * Will return true for the identity matrix, which represents a zero translation.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return True iff the matrix is of the form
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * \f$\left[\begin{array}{ccc}
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 1 & 0 & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 0 & 1 & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler a & b & 1 \end{array}\right]\f$ */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler return are_near(_c[0], 1.0, eps) && are_near(_c[1], 0.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[2], 0.0, eps) && are_near(_c[3], 1.0, eps);
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether this matrix represents a pure nonzero translation.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return True iff the matrix is of the form
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * \f$\left[\begin{array}{ccc}
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 1 & 0 & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 0 & 1 & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler a & b & 1 \end{array}\right]\f$ and \f$a, b \neq 0\f$ */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andlerbool Affine::isNonzeroTranslation(Coord eps) const {
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler return are_near(_c[0], 1.0, eps) && are_near(_c[1], 0.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[2], 0.0, eps) && are_near(_c[3], 1.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler (!are_near(_c[4], 0.0, eps) || !are_near(_c[5], 0.0, eps));
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether this matrix represents pure scaling.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return True iff the matrix is of the form
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * \f$\left[\begin{array}{ccc}
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler a & 0 & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 0 & b & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 0 & 0 & 1 \end{array}\right]\f$. */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler return are_near(_c[1], 0.0, eps) && are_near(_c[2], 0.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps);
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether this matrix represents pure, nonzero scaling.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return True iff the matrix is of the form
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * \f$\left[\begin{array}{ccc}
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler a & 0 & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 0 & b & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 0 & 0 & 1 \end{array}\right]\f$ and \f$a, b \neq 1\f$. */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler return (!are_near(_c[0], 1.0, eps) || !are_near(_c[3], 1.0, eps)) && //NOTE: these are the diags, and the next line opposite diags
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[1], 0.0, eps) && are_near(_c[2], 0.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps);
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether this matrix represents pure uniform scaling.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return True iff the matrix is of the form
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * \f$\left[\begin{array}{ccc}
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski a_1 & 0 & 0 \\
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski 0 & a_2 & 0 \\
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski 0 & 0 & 1 \end{array}\right]\f$ where \f$|a_1| = |a_2|\f$. */
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski return are_near(fabs(_c[0]), fabs(_c[3]), eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[1], 0.0, eps) && are_near(_c[2], 0.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps);
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether this matrix represents pure, nonzero uniform scaling.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return True iff the matrix is of the form
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * \f$\left[\begin{array}{ccc}
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski a_1 & 0 & 0 \\
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski 0 & a_2 & 0 \\
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski 0 & 0 & 1 \end{array}\right]\f$ where \f$|a_1| = |a_2|\f$
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski * and \f$a_1, a_2 \neq 1\f$. */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andlerbool Affine::isNonzeroUniformScale(Coord eps) const {
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski // we need to test both c0 and c3 to handle the case of flips,
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski // which should be treated as nonzero uniform scales
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski return !(are_near(_c[0], 1.0, eps) && are_near(_c[3], 1.0, eps)) &&
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski are_near(fabs(_c[0]), fabs(_c[3]), eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[1], 0.0, eps) && are_near(_c[2], 0.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps);
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether this matrix represents a pure rotation.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return True iff the matrix is of the form
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * \f$\left[\begin{array}{ccc}
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler a & b & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler -b & a & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 0 & 0 & 1 \end{array}\right]\f$ and \f$a^2 + b^2 = 1\f$. */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler return are_near(_c[0], _c[3], eps) && are_near(_c[1], -_c[2], eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether this matrix represents a pure, nonzero rotation.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return True iff the matrix is of the form
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * \f$\left[\begin{array}{ccc}
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler a & b & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler -b & a & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 0 & 0 & 1 \end{array}\right]\f$, \f$a^2 + b^2 = 1\f$ and \f$a \neq 1\f$. */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andlerbool Affine::isNonzeroRotation(Coord eps) const {
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[0], _c[3], eps) && are_near(_c[1], -_c[2], eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether this matrix represents pure horizontal shearing.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return True iff the matrix is of the form
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * \f$\left[\begin{array}{ccc}
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 1 & 0 & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler k & 1 & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 0 & 0 & 1 \end{array}\right]\f$. */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler return are_near(_c[0], 1.0, eps) && are_near(_c[1], 0.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[3], 1.0, eps) && are_near(_c[4], 0.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether this matrix represents pure, nonzero horizontal shearing.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return True iff the matrix is of the form
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * \f$\left[\begin{array}{ccc}
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 1 & 0 & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler k & 1 & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 0 & 0 & 1 \end{array}\right]\f$ and \f$k \neq 0\f$. */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler return are_near(_c[0], 1.0, eps) && are_near(_c[1], 0.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler !are_near(_c[2], 0.0, eps) && are_near(_c[3], 1.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps);
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether this matrix represents pure vertical shearing.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return True iff the matrix is of the form
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * \f$\left[\begin{array}{ccc}
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 1 & k & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 0 & 1 & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 0 & 0 & 1 \end{array}\right]\f$. */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler return are_near(_c[0], 1.0, eps) && are_near(_c[2], 0.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[3], 1.0, eps) && are_near(_c[4], 0.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether this matrix represents pure, nonzero vertical shearing.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return True iff the matrix is of the form
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * \f$\left[\begin{array}{ccc}
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 1 & k & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 0 & 1 & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 0 & 0 & 1 \end{array}\right]\f$ and \f$k \neq 0\f$. */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler return are_near(_c[0], 1.0, eps) && !are_near(_c[1], 0.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[2], 0.0, eps) && are_near(_c[3], 1.0, eps) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps);
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether this matrix represents zooming.
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski * Zooming is any combination of translation and uniform non-flipping scaling.
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski * It preserves angles, ratios of distances between arbitrary points
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski * and unit vectors of line segments.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski * @return True iff the matrix is invertible and of the form
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * \f$\left[\begin{array}{ccc}
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler a & 0 & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler 0 & a & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler b & c & 1 \end{array}\right]\f$. */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler return are_near(_c[0], _c[3], eps) && are_near(_c[1], 0, eps) && are_near(_c[2], 0, eps);
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether the transformation preserves areas of polygons.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * This means that the transformation can be any combination of translation, rotation,
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * shearing and squeezing (non-uniform scaling such that the absolute value of the product
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * of Y-scale and X-scale is 1).
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return True iff \f$|\det A| = 1\f$. */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether the transformation preserves angles between lines.
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski * This means that the transformation can be any combination of translation, uniform scaling,
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski * rotation and flipping.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return True iff the matrix is of the form
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * \f$\left[\begin{array}{ccc}
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski c & d & 1 \end{array}\right]\f$ or
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski \f$\left[\begin{array}{ccc}
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski c & d & 1 \end{array}\right]\f$. */
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski return (are_near(_c[0], _c[3], eps) && are_near(_c[1], -_c[2], eps)) ||
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski (are_near(_c[0], -_c[3], eps) && are_near(_c[1], _c[2], eps));
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether the transformation preserves distances between points.
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski * This means that the transformation can be any combination of translation,
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski * rotation and flipping.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return True iff the matrix is of the form
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * \f$\left[\begin{array}{ccc}
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler a & b & 0 \\
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler -b & a & 0 \\
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski c & d & 1 \end{array}\right]\f$ or
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski \f$\left[\begin{array}{ccc}
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler c & d & 1 \end{array}\right]\f$ and \f$a^2 + b^2 = 1\f$. */
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski return ((are_near(_c[0], _c[3], eps) && are_near(_c[1], -_c[2], eps)) ||
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski (are_near(_c[0], -_c[3], eps) && are_near(_c[1], _c[2], eps))) &&
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler are_near(_c[0] * _c[0] + _c[1] * _c[1], 1.0, eps);
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether this transformation flips objects.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * A transformation flips objects if it has a negative scaling component. */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler // TODO shouldn't this be det() < 0?
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Check whether this matrix is singular.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * Singular matrices have no inverse, which means that applying them to a set of points
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * results in a loss of information.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return True iff the determinant is near zero. */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Compute the inverse matrix.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * Inverse is a matrix (denoted \f$A^{-1}) such that \f$AA^{-1} = A^{-1}A = I\f$.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * Singular matrices have no inverse (for example a matrix that has two of its columns equal).
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * For such matrices, the identity matrix will be returned instead.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @param eps Numerical tolerance
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return Inverse of the matrix, or the identity matrix if the inverse is undefined.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @post (m * m.inverse()).isIdentity() == true */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler fabs(_c[2]) + fabs(_c[3])); // a random matrix norm (either l1 or linfty
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Calculate the determinant.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return \f$\det A\f$. */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler // TODO this can overflow
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Calculate the square of the descriminant.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * This is simply the absolute value of the determinant.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return \f$|\det A|\f$. */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Calculate the descriminant.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * If the matrix doesn't contain a shearing or non-uniform scaling component, this value says
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * how will the length of any line segment change after applying this transformation
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * to arbitrary objects on a plane. The new length will be
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * @code line_seg.length() * m.descrim()) @endcode
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * @return \f$\sqrt{|\det A|}\f$. */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler/** @brief Combine this transformation with another one.
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * After this operation, the matrix will correspond to the transformation
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * obtained by first applying the original version of this matrix, and then
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler * applying @a m. */
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler for(int b = 0; b < 2; b++) {
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler nc[a + b] = _c[a] * o._c[b] + _c[a + 1] * o._c[b + 2];
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler for(int a = 0; a < 6; ++a) {
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler return *this;
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler//TODO: What's this!?!
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński/** Given a matrix m such that unit_circle = m*x, this returns the
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * quadratic form x*A*x = 1.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * @relates Affine */
f6df6236fcf18524e049bba12b69704af32eff90Josh AndlerAffine elliptic_quadratic_form(Affine const &m) {
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler double const B = -m[0] - m[3];
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler values[0] = center + delta; values[1] = center - delta;
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler for (int i = 0; i < 2; i++) {
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler vectors[i] = unit_vector(rot90(Point(m[0]-values[i], m[1])));
f6df6236fcf18524e049bba12b69704af32eff90Josh Andlerstatic void quadratic_roots(double q0, double q1, double q2, int &n, double&r0, double&r1) {
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler else if (desc == 0) {
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler double const C = m[0][0]*m[1][1] - m[1][0]*m[0][1];
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler //double const desc = B*B-4*C;
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler //double t = -0.5*(B+sgn(B)*desc);
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler quadratic_roots(C, B, 1, n, values[0], values[1]);
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler for (int i = 0; i < n; i++)
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler vectors[i] = unit_vector(rot90(Point(m[0][0]-values[i], m[0][1])));
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler for (int i = n; i < 2; i++)
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński/** @brief Nearness predicate for affine transforms
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * @returns True if all entries of matrices are within eps of each other */
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosińskibool are_near(Affine const &a, Affine const &b, Coord eps)
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński return are_near(a[0], b[0], eps) && are_near(a[1], b[1], eps) &&
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński are_near(a[2], b[2], eps) && are_near(a[3], b[3], eps) &&
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński are_near(a[4], b[4], eps) && are_near(a[5], b[5], eps);
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler} //namespace Geom
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler Local Variables:
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler c-file-style:"stroustrup"
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler indent-tabs-mode:nil
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler fill-column:99
f6df6236fcf18524e049bba12b69704af32eff90Josh Andler// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :